mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-11 15:08:09 -05:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e843419397 | ||
|
|
badde3cba5 | ||
|
|
caa16e1676 | ||
|
|
7c742da488 | ||
|
|
0cdb0dc7a9 | ||
|
|
3143373f5f | ||
|
|
18ee6a67c5 | ||
|
|
05da46a719 | ||
|
|
55e0b11d17 | ||
|
|
6f72d0447e | ||
|
|
76d66eba58 | ||
|
|
c551609e17 | ||
|
|
47e5a43646 | ||
|
|
7604612581 | ||
|
|
35d4ec5ad0 | ||
|
|
8f745e9836 | ||
|
|
4ec1045916 | ||
|
|
f94e21dd45 | ||
|
|
205641a65c | ||
|
|
d02f41b2c9 | ||
|
|
72204358f0 | ||
|
|
072bc21d20 | ||
|
|
f7a2465db8 | ||
|
|
154ff0c8a0 | ||
|
|
2b266aaa68 | ||
|
|
410f14bc7d | ||
|
|
4d903bc9b2 | ||
|
|
59a2f1e998 | ||
|
|
20c5e9855b | ||
|
|
1f2fe74cbe | ||
|
|
0e12661fd5 | ||
|
|
04e66231e5 | ||
|
|
417a228523 |
@@ -7,11 +7,13 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"bridge-history-api/config"
|
||||
"bridge-history-api/internal/controller"
|
||||
"bridge-history-api/internal/route"
|
||||
"bridge-history-api/observability"
|
||||
"bridge-history-api/utils"
|
||||
)
|
||||
|
||||
@@ -54,13 +56,18 @@ func action(ctx *cli.Context) error {
|
||||
|
||||
router := gin.Default()
|
||||
controller.InitController(db)
|
||||
route.Route(router, cfg)
|
||||
|
||||
registry := prometheus.DefaultRegisterer
|
||||
route.Route(router, cfg, registry)
|
||||
|
||||
go func() {
|
||||
if runServerErr := router.Run(fmt.Sprintf(":%s", port)); runServerErr != nil {
|
||||
log.Crit("run http server failure", "error", runServerErr)
|
||||
}
|
||||
}()
|
||||
|
||||
observability.Server(ctx, db)
|
||||
|
||||
// Catch CTRL-C to ensure a graceful shutdown.
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
|
||||
@@ -3,15 +3,20 @@ module bridge-history-api
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/bits-and-blooms/bitset v1.7.0
|
||||
github.com/ethereum/go-ethereum v1.12.2
|
||||
github.com/gin-contrib/cors v1.4.0
|
||||
github.com/gin-contrib/pprof v1.4.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-isatty v0.0.19
|
||||
github.com/modern-go/reflect2 v1.0.2
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pressly/goose/v3 v3.7.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
golang.org/x/sync v0.3.0
|
||||
gorm.io/driver/postgres v1.5.0
|
||||
gorm.io/gorm v1.25.2
|
||||
)
|
||||
@@ -20,7 +25,6 @@ require (
|
||||
github.com/DataDog/zstd v1.5.2 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.7.0 // indirect
|
||||
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
|
||||
github.com/bytedance/sonic v1.9.2 // indirect
|
||||
@@ -94,7 +98,6 @@ require (
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
@@ -117,7 +120,6 @@ require (
|
||||
golang.org/x/crypto v0.12.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad // indirect
|
||||
golang.org/x/net v0.14.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
|
||||
@@ -119,6 +119,8 @@ github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnR
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
||||
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
|
||||
github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg=
|
||||
github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
@@ -362,6 +364,8 @@ github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
|
||||
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
|
||||
@@ -11,10 +11,6 @@ var (
|
||||
HistoryCtrler *HistoryController
|
||||
// BatchCtrler is controller instance
|
||||
BatchCtrler *BatchController
|
||||
// HealthCheck the health check controller
|
||||
HealthCheck *HealthCheckController
|
||||
// Ready the ready controller
|
||||
Ready *ReadyController
|
||||
|
||||
initControllerOnce sync.Once
|
||||
)
|
||||
@@ -24,7 +20,5 @@ func InitController(db *gorm.DB) {
|
||||
initControllerOnce.Do(func() {
|
||||
HistoryCtrler = NewHistoryController(db)
|
||||
BatchCtrler = NewBatchController(db)
|
||||
HealthCheck = NewHealthCheckController(db)
|
||||
Ready = NewReadyController()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"bridge-history-api/internal/types"
|
||||
"bridge-history-api/utils"
|
||||
)
|
||||
|
||||
// HealthCheckController is health check API
|
||||
type HealthCheckController struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewHealthCheckController returns an HealthCheckController instance
|
||||
func NewHealthCheckController(db *gorm.DB) *HealthCheckController {
|
||||
return &HealthCheckController{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// HealthCheck the api controller for coordinator health check
|
||||
func (a *HealthCheckController) HealthCheck(c *gin.Context) {
|
||||
if _, err := utils.Ping(a.db); err != nil {
|
||||
types.RenderFatal(c, err)
|
||||
return
|
||||
}
|
||||
types.RenderSuccess(c, nil)
|
||||
}
|
||||
@@ -1,23 +1,40 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"golang.org/x/sync/singleflight"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"bridge-history-api/internal/logic"
|
||||
"bridge-history-api/internal/types"
|
||||
)
|
||||
|
||||
const (
|
||||
cacheKeyPrefixClaimableTxsByAddr = "claimableTxsByAddr:"
|
||||
cacheKeyPrefixQueryTxsByHash = "queryTxsByHash:"
|
||||
)
|
||||
|
||||
// HistoryController contains the query claimable txs service
|
||||
type HistoryController struct {
|
||||
historyLogic *logic.HistoryLogic
|
||||
cache *cache.Cache
|
||||
singleFlight singleflight.Group
|
||||
cacheMetrics *cacheMetrics
|
||||
}
|
||||
|
||||
// NewHistoryController return HistoryController instance
|
||||
func NewHistoryController(db *gorm.DB) *HistoryController {
|
||||
return &HistoryController{
|
||||
historyLogic: logic.NewHistoryLogic(db),
|
||||
cache: cache.New(30*time.Second, 10*time.Minute),
|
||||
cacheMetrics: initCacheMetrics(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,32 +45,48 @@ func (c *HistoryController) GetAllClaimableTxsByAddr(ctx *gin.Context) {
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
|
||||
return
|
||||
}
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
limit := req.PageSize
|
||||
txs, total, err := c.historyLogic.GetClaimableTxsByAddress(ctx, common.HexToAddress(req.Address), offset, limit)
|
||||
|
||||
cacheKey := cacheKeyPrefixClaimableTxsByAddr + req.Address
|
||||
if cachedData, found := c.cache.Get(cacheKey); found {
|
||||
c.cacheMetrics.cacheHits.WithLabelValues("GetAllClaimableTxsByAddr").Inc()
|
||||
// Log cache hit along with request param.
|
||||
log.Info("cache hit", "request", req)
|
||||
if cachedData == nil {
|
||||
types.RenderSuccess(ctx, &types.ResultData{})
|
||||
return
|
||||
} else if resultData, ok := cachedData.(*types.ResultData); ok {
|
||||
types.RenderSuccess(ctx, resultData)
|
||||
return
|
||||
}
|
||||
// Log error for unexpected type, then fetch data from the database.
|
||||
log.Error("unexpected type in cache", "expected", "*types.ResultData", "got", reflect.TypeOf(cachedData))
|
||||
} else {
|
||||
c.cacheMetrics.cacheMisses.WithLabelValues("GetAllClaimableTxsByAddr").Inc()
|
||||
// Log cache miss along with request param.
|
||||
log.Info("cache miss", "request", req)
|
||||
}
|
||||
|
||||
result, err, _ := c.singleFlight.Do(cacheKey, func() (interface{}, error) {
|
||||
txs, total, err := c.historyLogic.GetClaimableTxsByAddress(ctx, common.HexToAddress(req.Address))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultData := &types.ResultData{Result: txs, Total: total}
|
||||
c.cache.Set(cacheKey, resultData, cache.DefaultExpiration)
|
||||
return resultData, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
types.RenderFailure(ctx, types.ErrGetClaimablesFailure, err)
|
||||
return
|
||||
}
|
||||
|
||||
types.RenderSuccess(ctx, &types.ResultData{Result: txs, Total: total})
|
||||
}
|
||||
|
||||
// GetAllTxsByAddr defines the http get method behavior
|
||||
func (c *HistoryController) GetAllTxsByAddr(ctx *gin.Context) {
|
||||
var req types.QueryByAddressRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
|
||||
return
|
||||
if resultData, ok := result.(*types.ResultData); ok {
|
||||
types.RenderSuccess(ctx, resultData)
|
||||
} else {
|
||||
log.Error("unexpected type from singleflight", "expected", "*types.ResultData", "got", reflect.TypeOf(result))
|
||||
types.RenderFailure(ctx, types.ErrGetClaimablesFailure, errors.New("unexpected error"))
|
||||
}
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
limit := req.PageSize
|
||||
message, total, err := c.historyLogic.GetTxsByAddress(ctx, common.HexToAddress(req.Address), offset, limit)
|
||||
if err != nil {
|
||||
types.RenderFailure(ctx, types.ErrGetTxsByAddrFailure, err)
|
||||
return
|
||||
}
|
||||
types.RenderSuccess(ctx, &types.ResultData{Result: message, Total: total})
|
||||
}
|
||||
|
||||
// PostQueryTxsByHash defines the http post method behavior
|
||||
@@ -63,10 +96,66 @@ func (c *HistoryController) PostQueryTxsByHash(ctx *gin.Context) {
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
|
||||
return
|
||||
}
|
||||
result, err := c.historyLogic.GetTxsByHashes(ctx, req.Txs)
|
||||
if err != nil {
|
||||
types.RenderFailure(ctx, types.ErrGetTxsByHashFailure, err)
|
||||
|
||||
if len(req.Txs) > 10 {
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, errors.New("the number of hashes in the request exceeds the allowed maximum of 10"))
|
||||
return
|
||||
}
|
||||
types.RenderSuccess(ctx, &types.ResultData{Result: result, Total: 0})
|
||||
hashesMap := make(map[string]struct{}, len(req.Txs))
|
||||
results := make([]*types.TxHistoryInfo, 0, len(req.Txs))
|
||||
uncachedHashes := make([]string, 0, len(req.Txs))
|
||||
for _, hash := range req.Txs {
|
||||
if _, exists := hashesMap[hash]; exists {
|
||||
// Skip duplicate tx hash values.
|
||||
continue
|
||||
}
|
||||
hashesMap[hash] = struct{}{}
|
||||
|
||||
cacheKey := cacheKeyPrefixQueryTxsByHash + hash
|
||||
if cachedData, found := c.cache.Get(cacheKey); found {
|
||||
c.cacheMetrics.cacheHits.WithLabelValues("PostQueryTxsByHash").Inc()
|
||||
// Log cache hit along with tx hash.
|
||||
log.Info("cache hit", "tx hash", hash)
|
||||
if cachedData == nil {
|
||||
continue
|
||||
} else if txInfo, ok := cachedData.(*types.TxHistoryInfo); ok {
|
||||
results = append(results, txInfo)
|
||||
} else {
|
||||
log.Error("unexpected type in cache", "expected", "*types.TxHistoryInfo", "got", reflect.TypeOf(cachedData))
|
||||
uncachedHashes = append(uncachedHashes, hash)
|
||||
}
|
||||
} else {
|
||||
c.cacheMetrics.cacheMisses.WithLabelValues("PostQueryTxsByHash").Inc()
|
||||
// Log cache miss along with tx hash.
|
||||
log.Info("cache miss", "tx hash", hash)
|
||||
uncachedHashes = append(uncachedHashes, hash)
|
||||
}
|
||||
}
|
||||
|
||||
if len(uncachedHashes) > 0 {
|
||||
dbResults, err := c.historyLogic.GetTxsByHashes(ctx, uncachedHashes)
|
||||
if err != nil {
|
||||
types.RenderFailure(ctx, types.ErrGetTxsByHashFailure, err)
|
||||
return
|
||||
}
|
||||
|
||||
resultMap := make(map[string]*types.TxHistoryInfo)
|
||||
for _, result := range dbResults {
|
||||
results = append(results, result)
|
||||
resultMap[result.Hash] = result
|
||||
}
|
||||
|
||||
for _, hash := range uncachedHashes {
|
||||
cacheKey := cacheKeyPrefixQueryTxsByHash + hash
|
||||
result, found := resultMap[hash]
|
||||
if found {
|
||||
c.cache.Set(cacheKey, result, cache.DefaultExpiration)
|
||||
} else {
|
||||
c.cache.Set(cacheKey, nil, cache.DefaultExpiration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resultData := &types.ResultData{Result: results, Total: uint64(len(results))}
|
||||
types.RenderSuccess(ctx, resultData)
|
||||
}
|
||||
|
||||
40
bridge-history-api/internal/controller/metrics.go
Normal file
40
bridge-history-api/internal/controller/metrics.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
type cacheMetrics struct {
|
||||
cacheHits *prometheus.CounterVec
|
||||
cacheMisses *prometheus.CounterVec
|
||||
}
|
||||
|
||||
var (
|
||||
initMetricsOnce sync.Once
|
||||
cm *cacheMetrics
|
||||
)
|
||||
|
||||
func initCacheMetrics() *cacheMetrics {
|
||||
initMetricsOnce.Do(func() {
|
||||
cm = &cacheMetrics{
|
||||
cacheHits: promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "bridge_history_api_cache_hits_total",
|
||||
Help: "The total number of cache hits",
|
||||
},
|
||||
[]string{"api"},
|
||||
),
|
||||
cacheMisses: promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "bridge_history_api_cache_misses_total",
|
||||
Help: "The total number of cache misses",
|
||||
},
|
||||
[]string{"api"},
|
||||
),
|
||||
}
|
||||
})
|
||||
return cm
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"bridge-history-api/internal/types"
|
||||
)
|
||||
|
||||
// ReadyController ready API
|
||||
type ReadyController struct {
|
||||
}
|
||||
|
||||
// NewReadyController returns an ReadyController instance
|
||||
func NewReadyController() *ReadyController {
|
||||
return &ReadyController{}
|
||||
}
|
||||
|
||||
// Ready the api controller for coordinator ready
|
||||
func (r *ReadyController) Ready(c *gin.Context) {
|
||||
types.RenderSuccess(c, nil)
|
||||
}
|
||||
@@ -23,66 +23,101 @@ func NewHistoryLogic(db *gorm.DB) *HistoryLogic {
|
||||
return logic
|
||||
}
|
||||
|
||||
// getCrossTxClaimInfo get UserClaimInfos by address
|
||||
func getCrossTxClaimInfo(ctx context.Context, msgHash string, db *gorm.DB) *types.UserClaimInfo {
|
||||
// updateL2TxClaimInfo updates UserClaimInfos for each transaction history.
|
||||
func updateL2TxClaimInfo(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) {
|
||||
l2SentMsgOrm := orm.NewL2SentMsg(db)
|
||||
rollupOrm := orm.NewRollupBatch(db)
|
||||
l2sentMsg, err := l2SentMsgOrm.GetL2SentMsgByHash(ctx, msgHash)
|
||||
if err != nil || l2sentMsg == nil {
|
||||
log.Debug("getCrossTxClaimInfo failed", "error", err)
|
||||
return &types.UserClaimInfo{}
|
||||
}
|
||||
batch, err := rollupOrm.GetRollupBatchByIndex(ctx, l2sentMsg.BatchIndex)
|
||||
if err != nil {
|
||||
log.Debug("getCrossTxClaimInfo failed", "error", err)
|
||||
return &types.UserClaimInfo{}
|
||||
}
|
||||
return &types.UserClaimInfo{
|
||||
From: l2sentMsg.Sender,
|
||||
To: l2sentMsg.Target,
|
||||
Value: l2sentMsg.Value,
|
||||
Nonce: strconv.FormatUint(l2sentMsg.Nonce, 10),
|
||||
Message: l2sentMsg.MsgData,
|
||||
Proof: "0x" + l2sentMsg.MsgProof,
|
||||
BatchHash: batch.BatchHash,
|
||||
BatchIndex: strconv.FormatUint(l2sentMsg.BatchIndex, 10),
|
||||
|
||||
var l2MsgHashes []string
|
||||
for _, txHistory := range txHistories {
|
||||
if !txHistory.IsL1 {
|
||||
l2MsgHashes = append(l2MsgHashes, txHistory.MsgHash)
|
||||
}
|
||||
}
|
||||
|
||||
l2sentMsgs, err := l2SentMsgOrm.GetL2SentMsgsByHashes(ctx, l2MsgHashes)
|
||||
if err != nil || len(l2sentMsgs) == 0 {
|
||||
log.Debug("GetL2SentMsgsByHashes failed", "l2 sent msgs", l2sentMsgs, "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
l2MsgMap := make(map[string]*orm.L2SentMsg, len(l2sentMsgs))
|
||||
var batchIndexes []uint64
|
||||
for _, l2sentMsg := range l2sentMsgs {
|
||||
l2MsgMap[l2sentMsg.MsgHash] = l2sentMsg
|
||||
batchIndexes = append(batchIndexes, l2sentMsg.BatchIndex)
|
||||
}
|
||||
|
||||
batches, err := rollupOrm.GetRollupBatchesByIndexes(ctx, batchIndexes)
|
||||
if err != nil {
|
||||
log.Debug("GetRollupBatchesByIndexes failed", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
batchMap := make(map[uint64]*orm.RollupBatch, len(batches))
|
||||
for _, batch := range batches {
|
||||
batchMap[batch.BatchIndex] = batch
|
||||
}
|
||||
|
||||
for _, txHistory := range txHistories {
|
||||
if txHistory.IsL1 {
|
||||
continue
|
||||
}
|
||||
|
||||
l2sentMsg, foundL2SentMsg := l2MsgMap[txHistory.MsgHash]
|
||||
batch, foundBatch := batchMap[l2sentMsg.BatchIndex]
|
||||
if foundL2SentMsg && foundBatch {
|
||||
txHistory.ClaimInfo = &types.UserClaimInfo{
|
||||
From: l2sentMsg.Sender,
|
||||
To: l2sentMsg.Target,
|
||||
Value: l2sentMsg.Value,
|
||||
Nonce: strconv.FormatUint(l2sentMsg.Nonce, 10),
|
||||
Message: l2sentMsg.MsgData,
|
||||
Proof: "0x" + l2sentMsg.MsgProof,
|
||||
BatchHash: batch.BatchHash,
|
||||
BatchIndex: strconv.FormatUint(l2sentMsg.BatchIndex, 10),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateCrossTxHash(ctx context.Context, msgHash string, txInfo *types.TxHistoryInfo, db *gorm.DB) {
|
||||
func updateCrossTxHashes(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) {
|
||||
msgHashes := make([]string, len(txHistories))
|
||||
for i, txHistory := range txHistories {
|
||||
msgHashes[i] = txHistory.MsgHash
|
||||
}
|
||||
|
||||
relayed := orm.NewRelayedMsg(db)
|
||||
relayed, err := relayed.GetRelayedMsgByHash(ctx, msgHash)
|
||||
if err != nil {
|
||||
log.Debug("updateCrossTxHash failed", "error", err)
|
||||
return
|
||||
}
|
||||
if relayed == nil {
|
||||
return
|
||||
}
|
||||
if relayed.Layer1Hash != "" {
|
||||
txInfo.FinalizeTx.Hash = relayed.Layer1Hash
|
||||
txInfo.FinalizeTx.BlockNumber = relayed.Height
|
||||
return
|
||||
}
|
||||
if relayed.Layer2Hash != "" {
|
||||
txInfo.FinalizeTx.Hash = relayed.Layer2Hash
|
||||
txInfo.FinalizeTx.BlockNumber = relayed.Height
|
||||
relayedMsgs, err := relayed.GetRelayedMsgsByHashes(ctx, msgHashes)
|
||||
if err != nil || len(relayedMsgs) == 0 {
|
||||
log.Debug("GetRelayedMsgsByHashes failed", "msg hashes", msgHashes, "relayed msgs", relayedMsgs, "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
relayedMsgMap := make(map[string]*orm.RelayedMsg, len(relayedMsgs))
|
||||
for _, relayedMsg := range relayedMsgs {
|
||||
relayedMsgMap[relayedMsg.MsgHash] = relayedMsg
|
||||
}
|
||||
|
||||
for _, txHistory := range txHistories {
|
||||
if relayedMsg, found := relayedMsgMap[txHistory.MsgHash]; found {
|
||||
txHistory.FinalizeTx.Hash = relayedMsg.Layer1Hash + relayedMsg.Layer2Hash
|
||||
txHistory.FinalizeTx.BlockNumber = relayedMsg.Height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateCrossTxHashesAndL2TxClaimInfo(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) {
|
||||
updateCrossTxHashes(ctx, txHistories, db)
|
||||
updateL2TxClaimInfo(ctx, txHistories, db)
|
||||
}
|
||||
|
||||
// GetClaimableTxsByAddress get all claimable txs under given address
|
||||
func (h *HistoryLogic) GetClaimableTxsByAddress(ctx context.Context, address common.Address, offset int, limit int) ([]*types.TxHistoryInfo, uint64, error) {
|
||||
func (h *HistoryLogic) GetClaimableTxsByAddress(ctx context.Context, address common.Address) ([]*types.TxHistoryInfo, uint64, error) {
|
||||
var txHistories []*types.TxHistoryInfo
|
||||
l2SentMsgOrm := orm.NewL2SentMsg(h.db)
|
||||
l2CrossMsgOrm := orm.NewCrossMsg(h.db)
|
||||
total, err := l2SentMsgOrm.GetClaimableL2SentMsgByAddressTotalNum(ctx, address.Hex())
|
||||
if err != nil || total == 0 {
|
||||
return txHistories, 0, err
|
||||
}
|
||||
results, err := l2SentMsgOrm.GetClaimableL2SentMsgByAddressWithOffset(ctx, address.Hex(), offset, limit)
|
||||
results, err := l2SentMsgOrm.GetClaimableL2SentMsgByAddress(ctx, address.Hex())
|
||||
if err != nil || len(results) == 0 {
|
||||
return txHistories, 0, err
|
||||
}
|
||||
@@ -102,10 +137,10 @@ func (h *HistoryLogic) GetClaimableTxsByAddress(ctx context.Context, address com
|
||||
for _, result := range results {
|
||||
txInfo := &types.TxHistoryInfo{
|
||||
Hash: result.TxHash,
|
||||
MsgHash: result.MsgHash,
|
||||
IsL1: false,
|
||||
BlockNumber: result.Height,
|
||||
FinalizeTx: &types.Finalized{},
|
||||
ClaimInfo: getCrossTxClaimInfo(ctx, result.MsgHash, h.db),
|
||||
}
|
||||
if crossMsg, exist := crossMsgMap[result.MsgHash]; exist {
|
||||
txInfo.Amount = crossMsg.Amount
|
||||
@@ -117,96 +152,36 @@ func (h *HistoryLogic) GetClaimableTxsByAddress(ctx context.Context, address com
|
||||
}
|
||||
txHistories = append(txHistories, txInfo)
|
||||
}
|
||||
return txHistories, total, err
|
||||
}
|
||||
|
||||
// GetTxsByAddress get all txs under given address
|
||||
func (h *HistoryLogic) GetTxsByAddress(ctx context.Context, address common.Address, offset int, limit int) ([]*types.TxHistoryInfo, uint64, error) {
|
||||
var txHistories []*types.TxHistoryInfo
|
||||
utilOrm := orm.NewCrossMsg(h.db)
|
||||
total, err := utilOrm.GetTotalCrossMsgCountByAddress(ctx, address.String())
|
||||
if err != nil || total == 0 {
|
||||
return txHistories, 0, err
|
||||
}
|
||||
result, err := utilOrm.GetCrossMsgsByAddressWithOffset(ctx, address.String(), offset, limit)
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
for _, msg := range result {
|
||||
txHistory := &types.TxHistoryInfo{
|
||||
Hash: msg.Layer1Hash + msg.Layer2Hash,
|
||||
Amount: msg.Amount,
|
||||
To: msg.Target,
|
||||
L1Token: msg.Layer1Token,
|
||||
L2Token: msg.Layer2Token,
|
||||
IsL1: msg.MsgType == int(orm.Layer1Msg),
|
||||
BlockNumber: msg.Height,
|
||||
BlockTimestamp: msg.Timestamp,
|
||||
CreatedAt: msg.CreatedAt,
|
||||
FinalizeTx: &types.Finalized{
|
||||
Hash: "",
|
||||
},
|
||||
ClaimInfo: getCrossTxClaimInfo(ctx, msg.MsgHash, h.db),
|
||||
}
|
||||
updateCrossTxHash(ctx, msg.MsgHash, txHistory, h.db)
|
||||
txHistories = append(txHistories, txHistory)
|
||||
}
|
||||
return txHistories, total, nil
|
||||
updateL2TxClaimInfo(ctx, txHistories, h.db)
|
||||
return txHistories, uint64(len(results)), err
|
||||
}
|
||||
|
||||
// GetTxsByHashes get tx infos under given tx hashes
|
||||
func (h *HistoryLogic) GetTxsByHashes(ctx context.Context, hashes []string) ([]*types.TxHistoryInfo, error) {
|
||||
txHistories := make([]*types.TxHistoryInfo, 0)
|
||||
CrossMsgOrm := orm.NewCrossMsg(h.db)
|
||||
for _, hash := range hashes {
|
||||
l1result, err := CrossMsgOrm.GetL1CrossMsgByHash(ctx, common.HexToHash(hash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if l1result != nil {
|
||||
txHistory := &types.TxHistoryInfo{
|
||||
Hash: l1result.Layer1Hash,
|
||||
Amount: l1result.Amount,
|
||||
To: l1result.Target,
|
||||
IsL1: true,
|
||||
L1Token: l1result.Layer1Token,
|
||||
L2Token: l1result.Layer2Token,
|
||||
BlockNumber: l1result.Height,
|
||||
BlockTimestamp: l1result.Timestamp,
|
||||
CreatedAt: l1result.CreatedAt,
|
||||
FinalizeTx: &types.Finalized{
|
||||
Hash: "",
|
||||
},
|
||||
}
|
||||
updateCrossTxHash(ctx, l1result.MsgHash, txHistory, h.db)
|
||||
txHistories = append(txHistories, txHistory)
|
||||
continue
|
||||
}
|
||||
l2result, err := CrossMsgOrm.GetL2CrossMsgByHash(ctx, common.HexToHash(hash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if l2result != nil {
|
||||
txHistory := &types.TxHistoryInfo{
|
||||
Hash: l2result.Layer2Hash,
|
||||
Amount: l2result.Amount,
|
||||
To: l2result.Target,
|
||||
IsL1: false,
|
||||
L1Token: l2result.Layer1Token,
|
||||
L2Token: l2result.Layer2Token,
|
||||
BlockNumber: l2result.Height,
|
||||
BlockTimestamp: l2result.Timestamp,
|
||||
CreatedAt: l2result.CreatedAt,
|
||||
FinalizeTx: &types.Finalized{
|
||||
Hash: "",
|
||||
},
|
||||
ClaimInfo: getCrossTxClaimInfo(ctx, l2result.MsgHash, h.db),
|
||||
}
|
||||
updateCrossTxHash(ctx, l2result.MsgHash, txHistory, h.db)
|
||||
txHistories = append(txHistories, txHistory)
|
||||
continue
|
||||
}
|
||||
results, err := CrossMsgOrm.GetCrossMsgsByHashes(ctx, hashes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var txHistories []*types.TxHistoryInfo
|
||||
for _, result := range results {
|
||||
txHistory := &types.TxHistoryInfo{
|
||||
Hash: result.Layer1Hash + result.Layer2Hash,
|
||||
MsgHash: result.MsgHash,
|
||||
Amount: result.Amount,
|
||||
To: result.Target,
|
||||
L1Token: result.Layer1Token,
|
||||
L2Token: result.Layer2Token,
|
||||
IsL1: orm.MsgType(result.MsgType) == orm.Layer1Msg,
|
||||
BlockNumber: result.Height,
|
||||
BlockTimestamp: result.Timestamp,
|
||||
CreatedAt: result.CreatedAt,
|
||||
FinalizeTx: &types.Finalized{Hash: ""},
|
||||
}
|
||||
txHistories = append(txHistories, txHistory)
|
||||
}
|
||||
|
||||
updateCrossTxHashesAndL2TxClaimInfo(ctx, txHistories, h.db)
|
||||
return txHistories, nil
|
||||
}
|
||||
|
||||
@@ -5,13 +5,15 @@ import (
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"bridge-history-api/config"
|
||||
"bridge-history-api/internal/controller"
|
||||
"bridge-history-api/observability"
|
||||
)
|
||||
|
||||
// Route routes the APIs
|
||||
func Route(router *gin.Engine, conf *config.Config) {
|
||||
func Route(router *gin.Engine, conf *config.Config, reg prometheus.Registerer) {
|
||||
router.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
|
||||
@@ -20,11 +22,9 @@ func Route(router *gin.Engine, conf *config.Config) {
|
||||
MaxAge: 12 * time.Hour,
|
||||
}))
|
||||
|
||||
observability.Use(router, "bridge_history_api", reg)
|
||||
|
||||
r := router.Group("api/")
|
||||
r.GET("/txs", controller.HistoryCtrler.GetAllTxsByAddr)
|
||||
r.POST("/txsbyhashes", controller.HistoryCtrler.PostQueryTxsByHash)
|
||||
r.GET("/claimable", controller.HistoryCtrler.GetAllClaimableTxsByAddr)
|
||||
r.GET("/withdraw_root", controller.BatchCtrler.GetWithdrawRootByBatchIndex)
|
||||
r.GET("/health", controller.HealthCheck.HealthCheck)
|
||||
r.GET("/ready", controller.Ready.Ready)
|
||||
}
|
||||
|
||||
@@ -26,9 +26,7 @@ const (
|
||||
|
||||
// QueryByAddressRequest the request parameter of address api
|
||||
type QueryByAddressRequest struct {
|
||||
Address string `form:"address" binding:"required"`
|
||||
Page int `form:"page" binding:"required"`
|
||||
PageSize int `form:"page_size" binding:"required"`
|
||||
Address string `form:"address" binding:"required"`
|
||||
}
|
||||
|
||||
// QueryByHashRequest the request parameter of hash api
|
||||
@@ -80,6 +78,7 @@ type UserClaimInfo struct {
|
||||
// TxHistoryInfo the schema of tx history infos
|
||||
type TxHistoryInfo struct {
|
||||
Hash string `json:"hash"`
|
||||
MsgHash string `json:"msgHash"`
|
||||
Amount string `json:"amount"`
|
||||
To string `json:"to"` // useless
|
||||
IsL1 bool `json:"isL1"`
|
||||
|
||||
57
bridge-history-api/observability/ginmetrics/bloom.go
Normal file
57
bridge-history-api/observability/ginmetrics/bloom.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package ginmetrics
|
||||
|
||||
import (
|
||||
"github.com/bits-and-blooms/bitset"
|
||||
)
|
||||
|
||||
const defaultSize = 2 << 24
|
||||
|
||||
var seeds = []uint{7, 11, 13, 31, 37, 61}
|
||||
|
||||
// BloomFilter a simple bloom filter
|
||||
type BloomFilter struct {
|
||||
Set *bitset.BitSet
|
||||
Funcs [6]simpleHash
|
||||
}
|
||||
|
||||
// NewBloomFilter new a BloomFilter
|
||||
func NewBloomFilter() *BloomFilter {
|
||||
bf := new(BloomFilter)
|
||||
for i := 0; i < len(bf.Funcs); i++ {
|
||||
bf.Funcs[i] = simpleHash{defaultSize, seeds[i]}
|
||||
}
|
||||
bf.Set = bitset.New(defaultSize)
|
||||
return bf
|
||||
}
|
||||
|
||||
// Add a value to BloomFilter
|
||||
func (bf *BloomFilter) Add(value string) {
|
||||
for _, f := range bf.Funcs {
|
||||
bf.Set.Set(f.hash(value))
|
||||
}
|
||||
}
|
||||
|
||||
// Contains check the value is in bloom filter
|
||||
func (bf *BloomFilter) Contains(value string) bool {
|
||||
if value == "" {
|
||||
return false
|
||||
}
|
||||
ret := true
|
||||
for _, f := range bf.Funcs {
|
||||
ret = ret && bf.Set.Test(f.hash(value))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type simpleHash struct {
|
||||
Cap uint
|
||||
Seed uint
|
||||
}
|
||||
|
||||
func (s *simpleHash) hash(value string) uint {
|
||||
var result uint = 0
|
||||
for i := 0; i < len(value); i++ {
|
||||
result = result*s.Seed + uint(value[i])
|
||||
}
|
||||
return (s.Cap - 1) & result
|
||||
}
|
||||
89
bridge-history-api/observability/ginmetrics/metric.go
Normal file
89
bridge-history-api/observability/ginmetrics/metric.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package ginmetrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// Metric defines a metric object. Users can use it to save
|
||||
// metric data. Every metric should be globally unique by name.
|
||||
type Metric struct {
|
||||
Type MetricType
|
||||
Name string
|
||||
Description string
|
||||
Labels []string
|
||||
Buckets []float64
|
||||
Objectives map[float64]float64
|
||||
|
||||
vec prometheus.Collector
|
||||
}
|
||||
|
||||
// SetGaugeValue set data for Gauge type Metric.
|
||||
func (m *Metric) SetGaugeValue(labelValues []string, value float64) error {
|
||||
if m.Type == None {
|
||||
return fmt.Errorf("metric %s not existed", m.Name)
|
||||
}
|
||||
|
||||
if m.Type != Gauge {
|
||||
return fmt.Errorf("metric %s not Gauge type", m.Name)
|
||||
}
|
||||
m.vec.(*prometheus.GaugeVec).WithLabelValues(labelValues...).Set(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Inc increases value for Counter/Gauge type metric, increments
|
||||
// the counter by 1
|
||||
func (m *Metric) Inc(labelValues []string) error {
|
||||
if m.Type == None {
|
||||
return fmt.Errorf("metric %s not existed", m.Name)
|
||||
}
|
||||
|
||||
if m.Type != Gauge && m.Type != Counter {
|
||||
return fmt.Errorf("metric %s not Gauge or Counter type", m.Name)
|
||||
}
|
||||
switch m.Type {
|
||||
case Counter:
|
||||
m.vec.(*prometheus.CounterVec).WithLabelValues(labelValues...).Inc()
|
||||
case Gauge:
|
||||
m.vec.(*prometheus.GaugeVec).WithLabelValues(labelValues...).Inc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add adds the given value to the Metric object. Only
|
||||
// for Counter/Gauge type metric.
|
||||
func (m *Metric) Add(labelValues []string, value float64) error {
|
||||
if m.Type == None {
|
||||
return fmt.Errorf("metric %s not existed", m.Name)
|
||||
}
|
||||
|
||||
if m.Type != Gauge && m.Type != Counter {
|
||||
return fmt.Errorf("metric %s not Gauge or Counter type", m.Name)
|
||||
}
|
||||
switch m.Type {
|
||||
case Counter:
|
||||
m.vec.(*prometheus.CounterVec).WithLabelValues(labelValues...).Add(value)
|
||||
case Gauge:
|
||||
m.vec.(*prometheus.GaugeVec).WithLabelValues(labelValues...).Add(value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Observe is used by Histogram and Summary type metric to
|
||||
// add observations.
|
||||
func (m *Metric) Observe(labelValues []string, value float64) error {
|
||||
if m.Type == 0 {
|
||||
return fmt.Errorf("metric %s not existed", m.Name)
|
||||
}
|
||||
if m.Type != Histogram && m.Type != Summary {
|
||||
return fmt.Errorf("metric %s not Histogram or Summary type", m.Name)
|
||||
}
|
||||
switch m.Type {
|
||||
case Histogram:
|
||||
m.vec.(*prometheus.HistogramVec).WithLabelValues(labelValues...).Observe(value)
|
||||
case Summary:
|
||||
m.vec.(*prometheus.SummaryVec).WithLabelValues(labelValues...).Observe(value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
155
bridge-history-api/observability/ginmetrics/middleware.go
Normal file
155
bridge-history-api/observability/ginmetrics/middleware.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package ginmetrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
var (
|
||||
metricRequestTotal = "request_total"
|
||||
metricRequestUVTotal = "request_uv_total"
|
||||
metricURIRequestTotal = "uri_request_total"
|
||||
metricRequestBody = "request_body_total"
|
||||
metricResponseBody = "response_body_total"
|
||||
metricRequestDuration = "request_duration"
|
||||
metricSlowRequest = "slow_request_total"
|
||||
|
||||
bloomFilter *BloomFilter
|
||||
)
|
||||
|
||||
// Use set gin metrics middleware
|
||||
func (m *Monitor) Use(r gin.IRoutes) {
|
||||
m.initGinMetrics()
|
||||
|
||||
r.Use(m.monitorInterceptor)
|
||||
r.GET(m.metricPath, func(ctx *gin.Context) {
|
||||
promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request)
|
||||
})
|
||||
}
|
||||
|
||||
// UseWithoutExposingEndpoint is used to add monitor interceptor to gin router
|
||||
// It can be called multiple times to intercept from multiple gin.IRoutes
|
||||
// http path is not set, to do that use Expose function
|
||||
func (m *Monitor) UseWithoutExposingEndpoint(r gin.IRoutes) {
|
||||
m.initGinMetrics()
|
||||
r.Use(m.monitorInterceptor)
|
||||
}
|
||||
|
||||
// Expose adds metric path to a given router.
|
||||
// The router can be different with the one passed to UseWithoutExposingEndpoint.
|
||||
// This allows to expose metrics on different port.
|
||||
func (m *Monitor) Expose(r gin.IRoutes) {
|
||||
r.GET(m.metricPath, func(ctx *gin.Context) {
|
||||
promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request)
|
||||
})
|
||||
}
|
||||
|
||||
// initGinMetrics used to init gin metrics
|
||||
func (m *Monitor) initGinMetrics() {
|
||||
bloomFilter = NewBloomFilter()
|
||||
|
||||
_ = monitor.AddMetric(&Metric{
|
||||
Type: Counter,
|
||||
Name: metricRequestTotal,
|
||||
Description: "all the server received request num.",
|
||||
Labels: nil,
|
||||
})
|
||||
_ = monitor.AddMetric(&Metric{
|
||||
Type: Counter,
|
||||
Name: metricRequestUVTotal,
|
||||
Description: "all the server received ip num.",
|
||||
Labels: nil,
|
||||
})
|
||||
_ = monitor.AddMetric(&Metric{
|
||||
Type: Counter,
|
||||
Name: metricURIRequestTotal,
|
||||
Description: "all the server received request num with every uri.",
|
||||
Labels: []string{"uri", "method", "code"},
|
||||
})
|
||||
_ = monitor.AddMetric(&Metric{
|
||||
Type: Counter,
|
||||
Name: metricRequestBody,
|
||||
Description: "the server received request body size, unit byte",
|
||||
Labels: nil,
|
||||
})
|
||||
_ = monitor.AddMetric(&Metric{
|
||||
Type: Counter,
|
||||
Name: metricResponseBody,
|
||||
Description: "the server send response body size, unit byte",
|
||||
Labels: nil,
|
||||
})
|
||||
_ = monitor.AddMetric(&Metric{
|
||||
Type: Histogram,
|
||||
Name: metricRequestDuration,
|
||||
Description: "the time server took to handle the request.",
|
||||
Labels: []string{"uri"},
|
||||
Buckets: m.reqDuration,
|
||||
})
|
||||
_ = monitor.AddMetric(&Metric{
|
||||
Type: Counter,
|
||||
Name: metricSlowRequest,
|
||||
Description: fmt.Sprintf("the server handled slow requests counter, t=%d.", m.slowTime),
|
||||
Labels: []string{"uri", "method", "code"},
|
||||
})
|
||||
}
|
||||
|
||||
// monitorInterceptor as gin monitor middleware.
|
||||
func (m *Monitor) monitorInterceptor(ctx *gin.Context) {
|
||||
if ctx.Request.URL.Path == m.metricPath {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
startTime := time.Now()
|
||||
|
||||
// execute normal process.
|
||||
ctx.Next()
|
||||
|
||||
// after request
|
||||
m.ginMetricHandle(ctx, startTime)
|
||||
}
|
||||
|
||||
func (m *Monitor) ginMetricHandle(ctx *gin.Context, start time.Time) {
|
||||
r := ctx.Request
|
||||
w := ctx.Writer
|
||||
|
||||
//set request total
|
||||
_ = m.GetMetric(metricRequestTotal).Inc(nil)
|
||||
|
||||
// set uv
|
||||
if clientIP := ctx.ClientIP(); !bloomFilter.Contains(clientIP) {
|
||||
bloomFilter.Add(clientIP)
|
||||
_ = m.GetMetric(metricRequestUVTotal).Inc(nil)
|
||||
}
|
||||
|
||||
errCode := strconv.Itoa(ctx.GetInt("errcode"))
|
||||
if len(errCode) == 0 {
|
||||
errCode = strconv.Itoa(w.Status())
|
||||
}
|
||||
|
||||
// set uri request total
|
||||
_ = m.GetMetric(metricURIRequestTotal).Inc([]string{ctx.FullPath(), r.Method, errCode})
|
||||
|
||||
// set request body size
|
||||
// since r.ContentLength can be negative (in some occasions) guard the operation
|
||||
if r.ContentLength >= 0 {
|
||||
_ = m.GetMetric(metricRequestBody).Add(nil, float64(r.ContentLength))
|
||||
}
|
||||
|
||||
// set slow request
|
||||
latency := time.Since(start)
|
||||
if int32(latency.Seconds()) > m.slowTime {
|
||||
_ = m.GetMetric(metricSlowRequest).Inc([]string{ctx.FullPath(), r.Method, strconv.Itoa(w.Status())})
|
||||
}
|
||||
|
||||
// set request duration
|
||||
_ = m.GetMetric(metricRequestDuration).Observe([]string{ctx.FullPath()}, latency.Seconds())
|
||||
|
||||
// set response size
|
||||
if w.Size() > 0 {
|
||||
_ = m.GetMetric(metricResponseBody).Add(nil, float64(w.Size()))
|
||||
}
|
||||
}
|
||||
158
bridge-history-api/observability/ginmetrics/types.go
Normal file
158
bridge-history-api/observability/ginmetrics/types.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package ginmetrics
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
// MetricType define metric type
|
||||
type MetricType int
|
||||
|
||||
const (
|
||||
// None unknown metric type
|
||||
None MetricType = iota
|
||||
// Counter MetricType
|
||||
Counter
|
||||
// Gauge MetricType
|
||||
Gauge
|
||||
// Histogram MetricType
|
||||
Histogram
|
||||
// Summary MetricType
|
||||
Summary
|
||||
|
||||
defaultMetricPath = "/debug/metrics"
|
||||
defaultSlowTime = int32(5)
|
||||
)
|
||||
|
||||
var (
|
||||
defaultDuration = []float64{0.1, 0.3, 1.2, 5, 10}
|
||||
monitor *Monitor
|
||||
|
||||
promTypeHandler = map[MetricType]func(metric *Metric, reg prometheus.Registerer){
|
||||
Counter: counterHandler,
|
||||
Gauge: gaugeHandler,
|
||||
Histogram: histogramHandler,
|
||||
Summary: summaryHandler,
|
||||
}
|
||||
)
|
||||
|
||||
// Monitor is an object that uses to set gin server monitor.
|
||||
type Monitor struct {
|
||||
slowTime int32
|
||||
metricPath string
|
||||
reqDuration []float64
|
||||
metrics map[string]*Metric
|
||||
register prometheus.Registerer
|
||||
}
|
||||
|
||||
// GetMonitor used to get global Monitor object,
|
||||
// this function returns a singleton object.
|
||||
func GetMonitor(reg prometheus.Registerer) *Monitor {
|
||||
if monitor == nil {
|
||||
monitor = &Monitor{
|
||||
metricPath: defaultMetricPath,
|
||||
slowTime: defaultSlowTime,
|
||||
reqDuration: defaultDuration,
|
||||
metrics: make(map[string]*Metric),
|
||||
register: reg,
|
||||
}
|
||||
}
|
||||
return monitor
|
||||
}
|
||||
|
||||
// GetMetric used to get metric object by metric_name.
|
||||
func (m *Monitor) GetMetric(name string) *Metric {
|
||||
if metric, ok := m.metrics[name]; ok {
|
||||
return metric
|
||||
}
|
||||
return &Metric{}
|
||||
}
|
||||
|
||||
// SetMetricPath set metricPath property. metricPath is used for Prometheus
|
||||
// to get gin server monitoring data.
|
||||
func (m *Monitor) SetMetricPath(path string) {
|
||||
m.metricPath = path
|
||||
}
|
||||
|
||||
// SetSlowTime set slowTime property. slowTime is used to determine whether
|
||||
// the request is slow. For "gin_slow_request_total" metric.
|
||||
func (m *Monitor) SetSlowTime(slowTime int32) {
|
||||
m.slowTime = slowTime
|
||||
}
|
||||
|
||||
// SetDuration set reqDuration property. reqDuration is used to ginRequestDuration
|
||||
// metric buckets.
|
||||
func (m *Monitor) SetDuration(duration []float64) {
|
||||
m.reqDuration = duration
|
||||
}
|
||||
|
||||
// SetMetricPrefix set the metric prefix
|
||||
func (m *Monitor) SetMetricPrefix(prefix string) {
|
||||
metricRequestTotal = prefix + metricRequestTotal
|
||||
metricRequestUVTotal = prefix + metricRequestUVTotal
|
||||
metricURIRequestTotal = prefix + metricURIRequestTotal
|
||||
metricRequestBody = prefix + metricRequestBody
|
||||
metricResponseBody = prefix + metricResponseBody
|
||||
metricRequestDuration = prefix + metricRequestDuration
|
||||
metricSlowRequest = prefix + metricSlowRequest
|
||||
}
|
||||
|
||||
// SetMetricSuffix set the metric suffix
|
||||
func (m *Monitor) SetMetricSuffix(suffix string) {
|
||||
metricRequestTotal += suffix
|
||||
metricRequestUVTotal += suffix
|
||||
metricURIRequestTotal += suffix
|
||||
metricRequestBody += suffix
|
||||
metricResponseBody += suffix
|
||||
metricRequestDuration += suffix
|
||||
metricSlowRequest += suffix
|
||||
}
|
||||
|
||||
// AddMetric add custom monitor metric.
|
||||
func (m *Monitor) AddMetric(metric *Metric) error {
|
||||
if _, ok := m.metrics[metric.Name]; ok {
|
||||
return fmt.Errorf("metric %s is existed", metric.Name)
|
||||
}
|
||||
|
||||
if metric.Name == "" {
|
||||
return errors.New("metric name cannot be empty")
|
||||
}
|
||||
|
||||
if f, ok := promTypeHandler[metric.Type]; ok {
|
||||
f(metric, m.register)
|
||||
m.metrics[metric.Name] = metric
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func counterHandler(metric *Metric, register prometheus.Registerer) {
|
||||
metric.vec = promauto.With(register).NewCounterVec(
|
||||
prometheus.CounterOpts{Name: metric.Name, Help: metric.Description},
|
||||
metric.Labels,
|
||||
)
|
||||
}
|
||||
|
||||
func gaugeHandler(metric *Metric, register prometheus.Registerer) {
|
||||
metric.vec = promauto.With(register).NewGaugeVec(
|
||||
prometheus.GaugeOpts{Name: metric.Name, Help: metric.Description},
|
||||
metric.Labels,
|
||||
)
|
||||
}
|
||||
|
||||
func histogramHandler(metric *Metric, register prometheus.Registerer) {
|
||||
metric.vec = promauto.With(register).NewHistogramVec(
|
||||
prometheus.HistogramOpts{Name: metric.Name, Help: metric.Description, Buckets: metric.Buckets},
|
||||
metric.Labels,
|
||||
)
|
||||
}
|
||||
|
||||
func summaryHandler(metric *Metric, register prometheus.Registerer) {
|
||||
promauto.With(register).NewSummaryVec(
|
||||
prometheus.SummaryOpts{Name: metric.Name, Help: metric.Description, Objectives: metric.Objectives},
|
||||
metric.Labels,
|
||||
)
|
||||
}
|
||||
18
bridge-history-api/observability/middleware.go
Normal file
18
bridge-history-api/observability/middleware.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package observability
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"bridge-history-api/observability/ginmetrics"
|
||||
)
|
||||
|
||||
// Use register the gin metric
|
||||
func Use(router *gin.Engine, metricsPrefix string, reg prometheus.Registerer) {
|
||||
m := ginmetrics.GetMonitor(reg)
|
||||
m.SetMetricPath("/metrics")
|
||||
m.SetMetricPrefix(metricsPrefix + "_")
|
||||
m.SetSlowTime(1)
|
||||
m.SetDuration([]float64{0.025, .05, .1, .5, 1, 5, 10})
|
||||
m.UseWithoutExposingEndpoint(router)
|
||||
}
|
||||
35
bridge-history-api/observability/probes.go
Normal file
35
bridge-history-api/observability/probes.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package observability
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"bridge-history-api/internal/types"
|
||||
"bridge-history-api/utils"
|
||||
)
|
||||
|
||||
// ProbesController probe check controller
|
||||
type ProbesController struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewProbesController returns an ProbesController instance
|
||||
func NewProbesController(db *gorm.DB) *ProbesController {
|
||||
return &ProbesController{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// HealthCheck the api controller for health check
|
||||
func (a *ProbesController) HealthCheck(c *gin.Context) {
|
||||
if _, err := utils.Ping(a.db); err != nil {
|
||||
types.RenderFatal(c, err)
|
||||
return
|
||||
}
|
||||
types.RenderSuccess(c, nil)
|
||||
}
|
||||
|
||||
// Ready the api controller for ready check
|
||||
func (a *ProbesController) Ready(c *gin.Context) {
|
||||
types.RenderSuccess(c, nil)
|
||||
}
|
||||
53
bridge-history-api/observability/server.go
Normal file
53
bridge-history-api/observability/server.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package observability
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
// enable the pprof
|
||||
_ "net/http/pprof"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"bridge-history-api/utils"
|
||||
)
|
||||
|
||||
// Server starts the metrics server on the given address, will be closed when the given
|
||||
// context is canceled.
|
||||
func Server(c *cli.Context, db *gorm.DB) {
|
||||
if !c.Bool(utils.MetricsEnabled.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery())
|
||||
pprof.Register(r)
|
||||
r.GET("/metrics", func(context *gin.Context) {
|
||||
promhttp.Handler().ServeHTTP(context.Writer, context.Request)
|
||||
})
|
||||
|
||||
probeController := NewProbesController(db)
|
||||
r.GET("/health", probeController.HealthCheck)
|
||||
r.GET("/ready", probeController.Ready)
|
||||
|
||||
address := fmt.Sprintf(":%s", c.String(utils.MetricsPort.Name))
|
||||
server := &http.Server{
|
||||
Addr: address,
|
||||
Handler: r,
|
||||
ReadHeaderTimeout: time.Minute,
|
||||
}
|
||||
log.Info("Starting metrics server", "address", address)
|
||||
|
||||
go func() {
|
||||
if runServerErr := server.ListenAndServe(); runServerErr != nil && !errors.Is(runServerErr, http.ErrServerClosed) {
|
||||
log.Crit("run metrics http server failure", "error", runServerErr)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -71,6 +71,16 @@ func (r *RollupBatch) GetRollupBatchByIndex(ctx context.Context, index uint64) (
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// GetRollupBatchesByIndexes return the rollup batches by indexes
|
||||
func (r *RollupBatch) GetRollupBatchesByIndexes(ctx context.Context, indexes []uint64) ([]*RollupBatch, error) {
|
||||
var results []*RollupBatch
|
||||
err := r.db.WithContext(ctx).Model(&RollupBatch{}).Where("batch_index IN (?)", indexes).Find(&results).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("RollupBatch.GetRollupBatchesByIndexes error: %w", err)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// InsertRollupBatch batch insert rollup batch into db and return the transaction
|
||||
func (r *RollupBatch) InsertRollupBatch(ctx context.Context, batches []*RollupBatch, dbTx ...*gorm.DB) error {
|
||||
if len(batches) == 0 {
|
||||
|
||||
@@ -368,3 +368,14 @@ func (c *CrossMsg) GetCrossMsgsByAddressWithOffset(ctx context.Context, sender s
|
||||
}
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
// GetCrossMsgsByHashes retrieves a list of cross messages identified by their Layer 1 or Layer 2 hashes.
|
||||
func (c *CrossMsg) GetCrossMsgsByHashes(ctx context.Context, hashes []string) ([]*CrossMsg, error) {
|
||||
var results []*CrossMsg
|
||||
err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer1_hash IN (?) OR layer2_hash IN (?)", hashes, hashes).Find(&results).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CrossMsg.GetCrossMsgsByHashes error: %w", err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -54,6 +55,19 @@ func (l *L2SentMsg) GetL2SentMsgByHash(ctx context.Context, msgHash string) (*L2
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// GetL2SentMsgsByHashes get l2 sent msgs by hashes
|
||||
func (l *L2SentMsg) GetL2SentMsgsByHashes(ctx context.Context, msgHashes []string) ([]*L2SentMsg, error) {
|
||||
var results []*L2SentMsg
|
||||
err := l.db.WithContext(ctx).Model(&L2SentMsg{}).
|
||||
Where("msg_hash IN (?)", msgHashes).
|
||||
Find(&results).
|
||||
Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("L2SentMsg.GetL2SentMsgsByHashes error: %w", err)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetLatestSentMsgHeightOnL2 get latest sent msg height on l2
|
||||
func (l *L2SentMsg) GetLatestSentMsgHeightOnL2(ctx context.Context) (uint64, error) {
|
||||
var result L2SentMsg
|
||||
@@ -72,26 +86,61 @@ func (l *L2SentMsg) GetLatestSentMsgHeightOnL2(ctx context.Context) (uint64, err
|
||||
return result.Height, nil
|
||||
}
|
||||
|
||||
// GetClaimableL2SentMsgByAddressWithOffset get claimable l2 sent msg by address with offset
|
||||
func (l *L2SentMsg) GetClaimableL2SentMsgByAddressWithOffset(ctx context.Context, address string, offset int, limit int) ([]*L2SentMsg, error) {
|
||||
var results []*L2SentMsg
|
||||
err := l.db.WithContext(ctx).Raw(`SELECT * FROM l2_sent_msg WHERE id NOT IN (SELECT l2_sent_msg.id FROM l2_sent_msg INNER JOIN relayed_msg ON l2_sent_msg.msg_hash = relayed_msg.msg_hash WHERE l2_sent_msg.deleted_at IS NULL AND relayed_msg.deleted_at IS NULL) AND (original_sender=$1 OR sender = $1) AND msg_proof !='' ORDER BY id DESC LIMIT $2 OFFSET $3;`, address, limit, offset).
|
||||
Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("L2SentMsg.GetClaimableL2SentMsgByAddressWithOffset error: %w", err)
|
||||
// GetClaimableL2SentMsgByAddress returns both the total number of unclaimed messages and a paginated list of those messages.
|
||||
// TODO: Add metrics about the result set sizes (total/claimed/unclaimed messages).
|
||||
func (l *L2SentMsg) GetClaimableL2SentMsgByAddress(ctx context.Context, address string) ([]*L2SentMsg, error) {
|
||||
var totalMsgs []*L2SentMsg
|
||||
db := l.db.WithContext(ctx)
|
||||
db = db.Table("l2_sent_msg")
|
||||
db = db.Where("original_sender = ? OR sender = ?", address, address)
|
||||
db = db.Where("msg_proof != ''")
|
||||
db = db.Where("deleted_at IS NULL")
|
||||
db = db.Order("id DESC")
|
||||
tx := db.Find(&totalMsgs)
|
||||
if tx.Error != nil || tx.RowsAffected == 0 {
|
||||
return nil, tx.Error
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetClaimableL2SentMsgByAddressTotalNum get claimable l2 sent msg by address total num
|
||||
func (l *L2SentMsg) GetClaimableL2SentMsgByAddressTotalNum(ctx context.Context, address string) (uint64, error) {
|
||||
var count uint64
|
||||
err := l.db.WithContext(ctx).Raw(`SELECT COUNT(*) FROM l2_sent_msg WHERE id NOT IN (SELECT l2_sent_msg.id FROM l2_sent_msg INNER JOIN relayed_msg ON l2_sent_msg.msg_hash = relayed_msg.msg_hash WHERE l2_sent_msg.deleted_at IS NULL AND relayed_msg.deleted_at IS NULL) AND (original_sender=$1 OR sender = $1) AND msg_proof !='';`, address).
|
||||
Scan(&count).Error
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("L2SentMsg.GetClaimableL2SentMsgByAddressTotalNum error: %w", err)
|
||||
// Note on the use of IN vs VALUES in SQL Queries:
|
||||
// ------------------------------------------------
|
||||
// When using the IN predicate with a large list (>100) of values, performance may suffer.
|
||||
// An alternative approach is to use constant subqueries with the VALUES construct.
|
||||
// For more details and optimization tips, visit:
|
||||
// https://postgres.cz/wiki/PostgreSQL_SQL_Tricks_I#Predicate_IN_optimalization
|
||||
//
|
||||
// Example using IN:
|
||||
// SELECT * FROM tab WHERE x IN (1,2,3,...,n); -- where n > 70
|
||||
//
|
||||
// Optimized example using VALUES:
|
||||
// SELECT * FROM tab WHERE x IN (VALUES(10), (20));
|
||||
//
|
||||
var valuesStr string
|
||||
for _, msg := range totalMsgs {
|
||||
valuesStr += fmt.Sprintf("('%s'),", msg.MsgHash)
|
||||
}
|
||||
return count, nil
|
||||
valuesStr = strings.TrimSuffix(valuesStr, ",")
|
||||
|
||||
var claimedMsgHashes []string
|
||||
db = l.db.WithContext(ctx)
|
||||
db = db.Table("relayed_msg")
|
||||
db = db.Where(fmt.Sprintf("msg_hash IN (VALUES %s)", valuesStr))
|
||||
db = db.Where("deleted_at IS NULL")
|
||||
if err := db.Pluck("msg_hash", &claimedMsgHashes).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claimedMsgHashSet := make(map[string]struct{})
|
||||
for _, hash := range claimedMsgHashes {
|
||||
claimedMsgHashSet[hash] = struct{}{}
|
||||
}
|
||||
var unclaimedL2Msgs []*L2SentMsg
|
||||
for _, msg := range totalMsgs {
|
||||
if _, found := claimedMsgHashSet[msg.MsgHash]; !found {
|
||||
unclaimedL2Msgs = append(unclaimedL2Msgs, msg)
|
||||
}
|
||||
}
|
||||
|
||||
return unclaimedL2Msgs, nil
|
||||
}
|
||||
|
||||
// GetLatestL2SentMsgBatchIndex get latest l2 sent msg batch index
|
||||
|
||||
77
bridge-history-api/orm/l2_sent_msg_test.go
Normal file
77
bridge-history-api/orm/l2_sent_msg_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package orm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"bridge-history-api/orm/migrate"
|
||||
|
||||
"scroll-tech/common/database"
|
||||
"scroll-tech/common/docker"
|
||||
)
|
||||
|
||||
func TestGetClaimableL2SentMsgByAddress(t *testing.T) {
|
||||
base := docker.NewDockerApp()
|
||||
base.RunDBImage(t)
|
||||
|
||||
db, err := database.InitDB(
|
||||
&database.Config{
|
||||
DSN: base.DBConfig.DSN,
|
||||
DriverName: base.DBConfig.DriverName,
|
||||
MaxOpenNum: base.DBConfig.MaxOpenNum,
|
||||
MaxIdleNum: base.DBConfig.MaxIdleNum,
|
||||
},
|
||||
)
|
||||
assert.NoError(t, err)
|
||||
|
||||
sqlDB, err := db.DB()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, migrate.ResetDB(sqlDB))
|
||||
|
||||
l2SentMsgOrm := NewL2SentMsg(db)
|
||||
relayedMsgOrm := NewRelayedMsg(db)
|
||||
|
||||
msgs, err := l2SentMsgOrm.GetClaimableL2SentMsgByAddress(context.Background(), "sender1")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, msgs, 0)
|
||||
|
||||
l2SentMsgs := []*L2SentMsg{
|
||||
{
|
||||
Sender: "sender1",
|
||||
MsgHash: "hash1",
|
||||
MsgProof: "proof1",
|
||||
Nonce: 0,
|
||||
},
|
||||
{
|
||||
OriginalSender: "sender1",
|
||||
MsgHash: "hash2",
|
||||
MsgProof: "proof2",
|
||||
Nonce: 1,
|
||||
},
|
||||
{
|
||||
OriginalSender: "sender1",
|
||||
MsgHash: "hash3",
|
||||
MsgProof: "",
|
||||
Nonce: 2,
|
||||
},
|
||||
}
|
||||
relayedMsgs := []*RelayedMsg{
|
||||
{
|
||||
MsgHash: "hash2",
|
||||
},
|
||||
{
|
||||
MsgHash: "hash3",
|
||||
},
|
||||
}
|
||||
err = l2SentMsgOrm.InsertL2SentMsg(context.Background(), l2SentMsgs)
|
||||
assert.NoError(t, err)
|
||||
err = relayedMsgOrm.InsertRelayedMsg(context.Background(), relayedMsgs)
|
||||
assert.NoError(t, err)
|
||||
|
||||
msgs, err = l2SentMsgOrm.GetClaimableL2SentMsgByAddress(context.Background(), "sender1")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, msgs, 1)
|
||||
assert.Equal(t, "hash1", msgs[0].MsgHash)
|
||||
}
|
||||
@@ -49,6 +49,19 @@ func (r *RelayedMsg) GetRelayedMsgByHash(ctx context.Context, msgHash string) (*
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// GetRelayedMsgsByHashes get relayed msg by hash array
|
||||
func (r *RelayedMsg) GetRelayedMsgsByHashes(ctx context.Context, msgHashes []string) ([]*RelayedMsg, error) {
|
||||
var results []*RelayedMsg
|
||||
err := r.db.WithContext(ctx).Model(&RelayedMsg{}).
|
||||
Where("msg_hash IN (?)", msgHashes).
|
||||
Find(&results).
|
||||
Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("RelayedMsg.GetRelayedMsgsByHashes error: %w", err)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetLatestRelayedHeightOnL1 get latest relayed height on l1
|
||||
func (r *RelayedMsg) GetLatestRelayedHeightOnL1(ctx context.Context) (uint64, error) {
|
||||
var result RelayedMsg
|
||||
|
||||
@@ -14,14 +14,6 @@ import (
|
||||
"bridge-history-api/orm"
|
||||
)
|
||||
|
||||
// CachedParsedTxCalldata store parsed batch infos
|
||||
type CachedParsedTxCalldata struct {
|
||||
CallDataIndex uint64
|
||||
BatchIndices []uint64
|
||||
StartBlocks []uint64
|
||||
EndBlocks []uint64
|
||||
}
|
||||
|
||||
// ParseBackendL1EventLogs parses L1 watched events
|
||||
func ParseBackendL1EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedMsg, error) {
|
||||
// Need use contract abi to parse event Log
|
||||
|
||||
26
common/libzkp/impl/Cargo.lock
generated
26
common/libzkp/impl/Cargo.lock
generated
@@ -31,7 +31,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "aggregator"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"ark-std",
|
||||
"env_logger 0.10.0",
|
||||
@@ -333,7 +333,7 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
[[package]]
|
||||
name = "bus-mapping"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"ethers-core",
|
||||
@@ -959,7 +959,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "eth-types"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"ethers-core",
|
||||
"ethers-signers",
|
||||
@@ -1116,7 +1116,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "external-tracer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"geth-utils",
|
||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gadgets"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"digest 0.7.6",
|
||||
"eth-types",
|
||||
@@ -1328,7 +1328,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "geth-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"env_logger 0.9.3",
|
||||
"gobuild 0.1.0-alpha.2 (git+https://github.com/scroll-tech/gobuild.git)",
|
||||
@@ -1497,7 +1497,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "halo2-mpt-circuits"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/mpt-circuit.git?tag=v0.6.5#0bae9eeb813583c11f6db1f961a7e92f8c9bda82"
|
||||
source = "git+https://github.com/scroll-tech/mpt-circuit.git?tag=v0.7.0#578c210ceb88d3c143ee2a013ad836d19285d9c1"
|
||||
dependencies = [
|
||||
"ethers-core",
|
||||
"halo2_proofs",
|
||||
@@ -1519,7 +1519,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "halo2_proofs"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/scroll-tech/halo2.git?branch=develop#aa86c107aeb62282d81ebce5c4930ec0c0aa540b"
|
||||
source = "git+https://github.com/scroll-tech/halo2.git?branch=develop#e3fe25eadd714fd991f35190d17ff0b8fb031188"
|
||||
dependencies = [
|
||||
"ark-std",
|
||||
"blake2b_simd",
|
||||
@@ -1937,7 +1937,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "keccak256"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"env_logger 0.9.3",
|
||||
"eth-types",
|
||||
@@ -2135,7 +2135,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mock"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"ethers-core",
|
||||
@@ -2151,7 +2151,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpt-zktrie"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"halo2-mpt-circuits",
|
||||
@@ -2582,7 +2582,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "prover"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"aggregator",
|
||||
"anyhow",
|
||||
@@ -4125,7 +4125,7 @@ checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||
[[package]]
|
||||
name = "zkevm-circuits"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.1#88414cc46913978325efd744536c4d5a4a02a766"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.9.5#9b7e16b9412ff6b7a55fac6b9c6a943b55ef3718"
|
||||
dependencies = [
|
||||
"array-init",
|
||||
"bus-mapping",
|
||||
|
||||
@@ -21,7 +21,7 @@ halo2curves = { git = "https://github.com/scroll-tech/halo2curves.git", branch =
|
||||
|
||||
[dependencies]
|
||||
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
|
||||
prover = { git = "https://github.com/scroll-tech/zkevm-circuits.git", tag = "v0.9.1", default-features = false, features = ["parallel_syn", "scroll", "shanghai"] }
|
||||
prover = { git = "https://github.com/scroll-tech/zkevm-circuits.git", tag = "v0.9.5", default-features = false, features = ["parallel_syn", "scroll", "shanghai"] }
|
||||
|
||||
base64 = "0.13.0"
|
||||
env_logger = "0.9.0"
|
||||
|
||||
@@ -15,9 +15,16 @@ import (
|
||||
// CalldataNonZeroByteGas is the gas consumption per non zero byte in calldata.
|
||||
const CalldataNonZeroByteGas = 16
|
||||
|
||||
// GetKeccak256Gas calculates keccak256 hash gas.
|
||||
// GetKeccak256Gas calculates the gas cost for computing the keccak256 hash of a given size.
|
||||
func GetKeccak256Gas(size uint64) uint64 {
|
||||
return 30 + 6*((size+31)/32) // 30 + 6 * ceil(size / 32)
|
||||
return GetMemoryExpansionCost(size) + 30 + 6*((size+31)/32)
|
||||
}
|
||||
|
||||
// GetMemoryExpansionCost calculates the cost of memory expansion for a given memoryByteSize.
|
||||
func GetMemoryExpansionCost(memoryByteSize uint64) uint64 {
|
||||
memorySizeWord := (memoryByteSize + 31) / 32
|
||||
memoryCost := (memorySizeWord*memorySizeWord)/512 + (3 * memorySizeWord)
|
||||
return memoryCost
|
||||
}
|
||||
|
||||
// WrappedBlock contains the block's Header, Transactions and WithdrawTrieRoot hash.
|
||||
@@ -131,6 +138,12 @@ func (w *WrappedBlock) EstimateL1CommitGas() uint64 {
|
||||
total += 100 * numL1Messages // numL1Messages times call to L1MessageQueue
|
||||
total += 100 * numL1Messages // numL1Messages times warm address access to L1MessageQueue
|
||||
|
||||
total += GetMemoryExpansionCost(36) * numL1Messages // staticcall to proxy
|
||||
total += 100 * numL1Messages // read admin in proxy
|
||||
total += 100 * numL1Messages // read impl in proxy
|
||||
total += 100 * numL1Messages // access impl
|
||||
total += GetMemoryExpansionCost(36) * numL1Messages // delegatecall to impl
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestChunkEncode(t *testing.T) {
|
||||
},
|
||||
}
|
||||
assert.Equal(t, uint64(0), chunk.NumL1Messages(0))
|
||||
assert.Equal(t, uint64(6006), chunk.EstimateL1CommitGas())
|
||||
assert.Equal(t, uint64(6042), chunk.EstimateL1CommitGas())
|
||||
bytes, err = chunk.Encode(0)
|
||||
hexString := hex.EncodeToString(bytes)
|
||||
assert.NoError(t, err)
|
||||
@@ -68,7 +68,7 @@ func TestChunkEncode(t *testing.T) {
|
||||
},
|
||||
}
|
||||
assert.Equal(t, uint64(11), chunk.NumL1Messages(0))
|
||||
assert.Equal(t, uint64(5002), chunk.EstimateL1CommitGas())
|
||||
assert.Equal(t, uint64(5329), chunk.EstimateL1CommitGas())
|
||||
bytes, err = chunk.Encode(0)
|
||||
hexString = hex.EncodeToString(bytes)
|
||||
assert.NoError(t, err)
|
||||
@@ -84,7 +84,7 @@ func TestChunkEncode(t *testing.T) {
|
||||
},
|
||||
}
|
||||
assert.Equal(t, uint64(11), chunk.NumL1Messages(0))
|
||||
assert.Equal(t, uint64(9958), chunk.EstimateL1CommitGas())
|
||||
assert.Equal(t, uint64(10612), chunk.EstimateL1CommitGas())
|
||||
bytes, err = chunk.Encode(0)
|
||||
hexString = hex.EncodeToString(bytes)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -263,7 +263,7 @@ type ChunkInfo struct {
|
||||
|
||||
// ChunkProof includes the proof info that are required for chunk verification and rollup.
|
||||
type ChunkProof struct {
|
||||
StorageTrace []byte `json:"storage_trace"`
|
||||
StorageTrace []byte `json:"storage_trace,omitempty"`
|
||||
Protocol []byte `json:"protocol"`
|
||||
Proof []byte `json:"proof"`
|
||||
Instances []byte `json:"instances"`
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var tag = "v4.3.11"
|
||||
var tag = "v4.3.32"
|
||||
|
||||
var commit = func() string {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
|
||||
@@ -260,23 +260,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -371,22 +354,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
@@ -563,23 +530,6 @@ Emitted when some ERC1155 token is refunded.
|
||||
| tokenId | uint256 | undefined |
|
||||
| amount | uint256 | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -227,23 +227,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -316,22 +299,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
@@ -502,23 +469,6 @@ Emitted when some ERC721 token is refunded.
|
||||
| recipient `indexed` | address | undefined |
|
||||
| tokenId | uint256 | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -239,23 +239,6 @@ Mapping from queue index to previous replay queue index.
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of ETH rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### relayMessageWithProof
|
||||
|
||||
```solidity
|
||||
@@ -453,22 +436,6 @@ Update max replay times.
|
||||
|---|---|---|
|
||||
| _newMaxReplayTimes | uint256 | The new max replay times. |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### xDomainMessageSender
|
||||
|
||||
```solidity
|
||||
@@ -642,22 +609,5 @@ Emitted when the maximum number of times each message can be replayed is updated
|
||||
| oldMaxReplayTimes | uint256 | undefined |
|
||||
| newMaxReplayTimes | uint256 | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -225,23 +225,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -292,22 +275,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
@@ -405,22 +372,5 @@ Emitted when some ERC20 token is refunded.
|
||||
| recipient `indexed` | address | undefined |
|
||||
| amount | uint256 | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -223,23 +223,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -290,22 +273,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
@@ -403,22 +370,5 @@ Emitted when some ERC20 token is refunded.
|
||||
| recipient `indexed` | address | undefined |
|
||||
| amount | uint256 | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -205,23 +205,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -316,22 +299,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
@@ -488,23 +455,6 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -174,23 +174,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -263,22 +246,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
@@ -430,23 +397,6 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -155,23 +155,6 @@ function paused() external view returns (bool)
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of ETH rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### relayMessage
|
||||
|
||||
```solidity
|
||||
@@ -290,22 +273,6 @@ Update fee vault contract.
|
||||
|---|---|---|
|
||||
| _newFeeVault | address | The address of new fee vault contract. |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### xDomainMessageSender
|
||||
|
||||
```solidity
|
||||
@@ -479,22 +446,5 @@ Emitted when the maximum number of times each message can fail in L2 is updated.
|
||||
| oldMaxFailedExecutionTimes | uint256 | undefined |
|
||||
| newMaxFailedExecutionTimes | uint256 | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -139,23 +139,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -223,22 +206,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
@@ -354,23 +321,6 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
### WithdrawERC20
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -172,23 +172,6 @@ function owner() external view returns (address)
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### rateLimiter
|
||||
|
||||
```solidity
|
||||
function rateLimiter() external view returns (address)
|
||||
```
|
||||
|
||||
The address of token rate limiter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -239,22 +222,6 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateRateLimiter
|
||||
|
||||
```solidity
|
||||
function updateRateLimiter(address _newRateLimiter) external nonpayable
|
||||
```
|
||||
|
||||
Update rate limiter contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newRateLimiter | address | The address of new rate limiter contract. |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
@@ -370,23 +337,6 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### UpdateRateLimiter
|
||||
|
||||
```solidity
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter)
|
||||
```
|
||||
|
||||
Emitted when owner updates rate limiter contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldRateLimiter `indexed` | address | undefined |
|
||||
| _newRateLimiter `indexed` | address | undefined |
|
||||
|
||||
### WithdrawERC20
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -318,6 +318,53 @@ describe("L1MessageQueue", async () => {
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
});
|
||||
|
||||
// @note skip this random benchmark tests
|
||||
for (const count1 of [1, 2, 128, 129, 256]) {
|
||||
for (const count2 of [1, 2, 128, 129, 256]) {
|
||||
for (const count3 of [1, 2, 128, 129, 256]) {
|
||||
it.skip(`should succeed on random tests, pop three times each with ${count1} ${count2} ${count3} msgs`, async () => {
|
||||
// append count1 + count2 + count3 messages
|
||||
for (let i = 0; i < count1 + count2 + count3; i++) {
|
||||
await queue.connect(messenger).appendCrossDomainMessage(constants.AddressZero, 1000000, "0x");
|
||||
}
|
||||
|
||||
// first pop `count1` messages
|
||||
const bitmap1 = BigNumber.from(randomBytes(32));
|
||||
let tx = await queue.connect(scrollChain).popCrossDomainMessage(0, count1, bitmap1);
|
||||
await expect(tx)
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(0, count1, bitmap1.and(constants.One.shl(count1).sub(1)));
|
||||
for (let i = 0; i < count1; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(bitmap1.shr(i).and(1).eq(1));
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
|
||||
// then pop `count2` messages
|
||||
const bitmap2 = BigNumber.from(randomBytes(32));
|
||||
tx = await queue.connect(scrollChain).popCrossDomainMessage(count1, count2, bitmap2);
|
||||
await expect(tx)
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(count1, count2, bitmap2.and(constants.One.shl(count2).sub(1)));
|
||||
for (let i = 0; i < count2; i++) {
|
||||
expect(await queue.isMessageSkipped(i + count1)).to.eq(bitmap2.shr(i).and(1).eq(1));
|
||||
expect(await queue.isMessageDropped(i + count1)).to.eq(false);
|
||||
}
|
||||
|
||||
// last pop `count3` messages
|
||||
const bitmap3 = BigNumber.from(randomBytes(32));
|
||||
tx = await queue.connect(scrollChain).popCrossDomainMessage(count1 + count2, count3, bitmap3);
|
||||
await expect(tx)
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(count1 + count2, count3, bitmap3.and(constants.One.shl(count3).sub(1)));
|
||||
for (let i = 0; i < count3; i++) {
|
||||
expect(await queue.isMessageSkipped(i + count1 + count2)).to.eq(bitmap3.shr(i).and(1).eq(1));
|
||||
expect(await queue.isMessageDropped(i + count1 + count2)).to.eq(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
context("#dropCrossDomainMessage", async () => {
|
||||
|
||||
@@ -17,7 +17,6 @@ import {L1MessageQueue} from "../../src/L1/rollup/L1MessageQueue.sol";
|
||||
import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol";
|
||||
import {L1StandardERC20Gateway} from "../../src/L1/gateways/L1StandardERC20Gateway.sol";
|
||||
import {L1WETHGateway} from "../../src/L1/gateways/L1WETHGateway.sol";
|
||||
import {L1DAIGateway} from "../../src/L1/gateways/L1DAIGateway.sol";
|
||||
import {L2GasPriceOracle} from "../../src/L1/rollup/L2GasPriceOracle.sol";
|
||||
import {MultipleVersionRollupVerifier} from "../../src/L1/rollup/MultipleVersionRollupVerifier.sol";
|
||||
import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol";
|
||||
@@ -27,7 +26,7 @@ import {ZkEvmVerifierV1} from "../../src/libraries/verifier/ZkEvmVerifierV1.sol"
|
||||
contract DeployL1BridgeContracts is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
uint32 CHAIN_ID_L2 = uint32(vm.envUint("CHAIN_ID_L2"));
|
||||
uint64 CHAIN_ID_L2 = uint64(vm.envUint("CHAIN_ID_L2"));
|
||||
|
||||
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
|
||||
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
|
||||
@@ -56,7 +55,6 @@ contract DeployL1BridgeContracts is Script {
|
||||
deployL1CustomERC20Gateway();
|
||||
deployL1ERC721Gateway();
|
||||
deployL1ERC1155Gateway();
|
||||
deployL1DAIGateway();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
@@ -204,18 +202,6 @@ contract DeployL1BridgeContracts is Script {
|
||||
logAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1DAIGateway() internal {
|
||||
L1DAIGateway impl = new L1DAIGateway();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(impl),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_DAI_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
logAddress("L1_DAI_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1ERC721Gateway() internal {
|
||||
L1ERC721Gateway impl = new L1ERC721Gateway();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
|
||||
66
contracts/scripts/foundry/DeployL1ScrollOwner.s.sol
Normal file
66
contracts/scripts/foundry/DeployL1ScrollOwner.s.sol
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
|
||||
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL1ScrollOwner is Script {
|
||||
string NETWORK = vm.envString("NETWORK");
|
||||
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L1_SCROLL_MULTISIG_ADDR");
|
||||
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L1_SECURITY_COUNCIL_ADDR");
|
||||
|
||||
address L1_PROPOSAL_EXECUTOR_ADDR = vm.envAddress("L1_PROPOSAL_EXECUTOR_ADDR");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployScrollOwner();
|
||||
|
||||
if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("sepolia"))) {
|
||||
// for sepolia
|
||||
deployTimelockController("1D", 1 minutes);
|
||||
deployTimelockController("7D", 7 minutes);
|
||||
deployTimelockController("14D", 14 minutes);
|
||||
} else if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("mainnet"))) {
|
||||
// for mainnet
|
||||
deployTimelockController("1D", 1 days);
|
||||
deployTimelockController("7D", 7 days);
|
||||
deployTimelockController("14D", 14 days);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployScrollOwner() internal {
|
||||
ScrollOwner owner = new ScrollOwner();
|
||||
|
||||
logAddress("L1_SCROLL_OWNER_ADDR", address(owner));
|
||||
}
|
||||
|
||||
function deployTimelockController(string memory label, uint256 delay) internal {
|
||||
address[] memory proposers = new address[](1);
|
||||
address[] memory executors = new address[](1);
|
||||
|
||||
proposers[0] = SCROLL_MULTISIG_ADDR;
|
||||
executors[0] = L1_PROPOSAL_EXECUTOR_ADDR;
|
||||
|
||||
TimelockController timelock = new TimelockController(delay, proposers, executors, SECURITY_COUNCIL_ADDR);
|
||||
|
||||
logAddress(string(abi.encodePacked("L1_", label, "_TIMELOCK_ADDR")), address(timelock));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import {L2GatewayRouter} from "../../src/L2/gateways/L2GatewayRouter.sol";
|
||||
import {L2ScrollMessenger} from "../../src/L2/L2ScrollMessenger.sol";
|
||||
import {L2StandardERC20Gateway} from "../../src/L2/gateways/L2StandardERC20Gateway.sol";
|
||||
import {L2WETHGateway} from "../../src/L2/gateways/L2WETHGateway.sol";
|
||||
import {L2DAIGateway} from "../../src/L2/gateways/L2DAIGateway.sol";
|
||||
import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol";
|
||||
import {L2MessageQueue} from "../../src/L2/predeploys/L2MessageQueue.sol";
|
||||
import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol";
|
||||
@@ -60,7 +59,6 @@ contract DeployL2BridgeContracts is Script {
|
||||
deployL2CustomERC20Gateway();
|
||||
deployL2ERC721Gateway();
|
||||
deployL2ERC1155Gateway();
|
||||
deployL2DAIGateway();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
@@ -201,18 +199,6 @@ contract DeployL2BridgeContracts is Script {
|
||||
logAddress("L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2DAIGateway() internal {
|
||||
L2DAIGateway impl = new L2DAIGateway();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(impl),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_DAI_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
logAddress("L2_DAI_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2ERC721Gateway() internal {
|
||||
L2ERC721Gateway impl = new L2ERC721Gateway();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
|
||||
66
contracts/scripts/foundry/DeployL2ScrollOwner.s.sol
Normal file
66
contracts/scripts/foundry/DeployL2ScrollOwner.s.sol
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
|
||||
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL2ScrollOwner is Script {
|
||||
string NETWORK = vm.envString("NETWORK");
|
||||
|
||||
uint256 L2_DEPLOYER_PRIVATE_KEY = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L2_SCROLL_MULTISIG_ADDR");
|
||||
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L2_SECURITY_COUNCIL_ADDR");
|
||||
|
||||
address L2_PROPOSAL_EXECUTOR_ADDR = vm.envAddress("L2_PROPOSAL_EXECUTOR_ADDR");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L2_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployScrollOwner();
|
||||
|
||||
if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("sepolia"))) {
|
||||
// for sepolia
|
||||
deployTimelockController("1D", 1 minutes);
|
||||
deployTimelockController("7D", 7 minutes);
|
||||
deployTimelockController("14D", 14 minutes);
|
||||
} else if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("mainnet"))) {
|
||||
// for mainnet
|
||||
deployTimelockController("1D", 1 days);
|
||||
deployTimelockController("7D", 7 days);
|
||||
deployTimelockController("14D", 14 days);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployScrollOwner() internal {
|
||||
ScrollOwner owner = new ScrollOwner();
|
||||
|
||||
logAddress("L2_SCROLL_OWNER_ADDR", address(owner));
|
||||
}
|
||||
|
||||
function deployTimelockController(string memory label, uint256 delay) internal {
|
||||
address[] memory proposers = new address[](1);
|
||||
address[] memory executors = new address[](1);
|
||||
|
||||
proposers[0] = SCROLL_MULTISIG_ADDR;
|
||||
executors[0] = L2_PROPOSAL_EXECUTOR_ADDR;
|
||||
|
||||
TimelockController timelock = new TimelockController(delay, proposers, executors, SECURITY_COUNCIL_ADDR);
|
||||
|
||||
logAddress(string(abi.encodePacked("L2_", label, "_TIMELOCK_ADDR")), address(timelock));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import {L1GatewayRouter} from "../../src/L1/gateways/L1GatewayRouter.sol";
|
||||
import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol";
|
||||
import {L1StandardERC20Gateway} from "../../src/L1/gateways/L1StandardERC20Gateway.sol";
|
||||
import {L1WETHGateway} from "../../src/L1/gateways/L1WETHGateway.sol";
|
||||
import {L1DAIGateway} from "../../src/L1/gateways/L1DAIGateway.sol";
|
||||
import {MultipleVersionRollupVerifier} from "../../src/L1/rollup/MultipleVersionRollupVerifier.sol";
|
||||
import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol";
|
||||
import {L1MessageQueue} from "../../src/L1/rollup/L1MessageQueue.sol";
|
||||
@@ -29,9 +28,6 @@ contract InitializeL1BridgeContracts is Script {
|
||||
address L1_FEE_VAULT_ADDR = vm.envAddress("L1_FEE_VAULT_ADDR");
|
||||
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
|
||||
|
||||
address L1_DAI_ADDR = vm.envAddress("L1_DAI_ADDR");
|
||||
address L2_DAI_ADDR = vm.envAddress("L2_DAI_ADDR");
|
||||
|
||||
address L1_WHITELIST_ADDR = vm.envAddress("L1_WHITELIST_ADDR");
|
||||
address L1_SCROLL_CHAIN_PROXY_ADDR = vm.envAddress("L1_SCROLL_CHAIN_PROXY_ADDR");
|
||||
address L1_MESSAGE_QUEUE_PROXY_ADDR = vm.envAddress("L1_MESSAGE_QUEUE_PROXY_ADDR");
|
||||
@@ -44,7 +40,6 @@ contract InitializeL1BridgeContracts is Script {
|
||||
address L1_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L1_DAI_GATEWAY_PROXY_ADDR");
|
||||
address L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR = vm.envAddress("L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR");
|
||||
address L1_ENFORCED_TX_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ENFORCED_TX_GATEWAY_PROXY_ADDR");
|
||||
|
||||
@@ -56,7 +51,6 @@ contract InitializeL1BridgeContracts is Script {
|
||||
address L2_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L2_DAI_GATEWAY_PROXY_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR");
|
||||
|
||||
@@ -155,22 +149,12 @@ contract InitializeL1BridgeContracts is Script {
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L1DAIGateway
|
||||
L1DAIGateway(L1_DAI_GATEWAY_PROXY_ADDR).initialize(
|
||||
L2_DAI_GATEWAY_PROXY_ADDR,
|
||||
L1_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
L1DAIGateway(L1_DAI_GATEWAY_PROXY_ADDR).updateTokenMapping(L1_DAI_ADDR, L2_DAI_ADDR);
|
||||
|
||||
// set WETH and DAI gateways in router
|
||||
// set WETH gateway in router
|
||||
{
|
||||
address[] memory _tokens = new address[](2);
|
||||
address[] memory _tokens = new address[](1);
|
||||
_tokens[0] = L1_WETH_ADDR;
|
||||
_tokens[1] = L1_DAI_ADDR;
|
||||
address[] memory _gateways = new address[](2);
|
||||
address[] memory _gateways = new address[](1);
|
||||
_gateways[0] = L1_WETH_GATEWAY_PROXY_ADDR;
|
||||
_gateways[1] = L1_DAI_GATEWAY_PROXY_ADDR;
|
||||
L1GatewayRouter(L1_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways);
|
||||
}
|
||||
|
||||
|
||||
274
contracts/scripts/foundry/InitializeL1ScrollOwner.s.sol
Normal file
274
contracts/scripts/foundry/InitializeL1ScrollOwner.s.sol
Normal file
@@ -0,0 +1,274 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
|
||||
import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol";
|
||||
import {L1USDCGateway} from "../../src/L1/gateways/usdc/L1USDCGateway.sol";
|
||||
import {EnforcedTxGateway} from "../../src/L1/gateways/EnforcedTxGateway.sol";
|
||||
import {L1CustomERC20Gateway} from "../../src/L1/gateways/L1CustomERC20Gateway.sol";
|
||||
import {L1ERC1155Gateway} from "../../src/L1/gateways/L1ERC1155Gateway.sol";
|
||||
import {L1ERC721Gateway} from "../../src/L1/gateways/L1ERC721Gateway.sol";
|
||||
import {L1GatewayRouter} from "../../src/L1/gateways/L1GatewayRouter.sol";
|
||||
import {L1MessageQueue} from "../../src/L1/rollup/L1MessageQueue.sol";
|
||||
import {ScrollMessengerBase} from "../../src/libraries/ScrollMessengerBase.sol";
|
||||
import {L2GasPriceOracle} from "../../src/L1/rollup/L2GasPriceOracle.sol";
|
||||
import {MultipleVersionRollupVerifier} from "../../src/L1/rollup/MultipleVersionRollupVerifier.sol";
|
||||
import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol";
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract InitializeL1ScrollOwner is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
bytes32 constant SECURITY_COUNCIL_NO_DELAY_ROLE = keccak256("SECURITY_COUNCIL_NO_DELAY_ROLE");
|
||||
bytes32 constant SCROLL_MULTISIG_NO_DELAY_ROLE = keccak256("SCROLL_MULTISIG_NO_DELAY_ROLE");
|
||||
bytes32 constant EMERGENCY_MULTISIG_NO_DELAY_ROLE = keccak256("EMERGENCY_MULTISIG_NO_DELAY_ROLE");
|
||||
|
||||
bytes32 constant TIMELOCK_1DAY_DELAY_ROLE = keccak256("TIMELOCK_1DAY_DELAY_ROLE");
|
||||
bytes32 constant TIMELOCK_7DAY_DELAY_ROLE = keccak256("TIMELOCK_7DAY_DELAY_ROLE");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L1_SCROLL_MULTISIG_ADDR");
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L1_SECURITY_COUNCIL_ADDR");
|
||||
address EMERGENCY_MULTISIG_ADDR = vm.envAddress("L1_EMERGENCY_MULTISIG_ADDR");
|
||||
|
||||
address L1_SCROLL_OWNER_ADDR = vm.envAddress("L1_SCROLL_OWNER_ADDR");
|
||||
address L1_1D_TIMELOCK_ADDR = vm.envAddress("L1_1D_TIMELOCK_ADDR");
|
||||
address L1_7D_TIMELOCK_ADDR = vm.envAddress("L1_7D_TIMELOCK_ADDR");
|
||||
address L1_14D_TIMELOCK_ADDR = vm.envAddress("L1_14D_TIMELOCK_ADDR");
|
||||
|
||||
address L1_PROXY_ADMIN_ADDR = vm.envAddress("L1_PROXY_ADMIN_ADDR");
|
||||
address L1_SCROLL_CHAIN_PROXY_ADDR = vm.envAddress("L1_SCROLL_CHAIN_PROXY_ADDR");
|
||||
address L1_MESSAGE_QUEUE_PROXY_ADDR = vm.envAddress("L1_MESSAGE_QUEUE_PROXY_ADDR");
|
||||
address L2_GAS_PRICE_ORACLE_PROXY_ADDR = vm.envAddress("L2_GAS_PRICE_ORACLE_PROXY_ADDR");
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L1_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L1_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
// address L1_USDC_GATEWAY_PROXY_ADDR = vm.envAddress("L1_USDC_GATEWAY_PROXY_ADDR");
|
||||
address L1_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR = vm.envAddress("L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR");
|
||||
// address L1_ENFORCED_TX_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ENFORCED_TX_GATEWAY_PROXY_ADDR");
|
||||
address L1_WHITELIST_ADDR = vm.envAddress("L1_WHITELIST_ADDR");
|
||||
|
||||
ScrollOwner owner;
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
owner = ScrollOwner(payable(L1_SCROLL_OWNER_ADDR));
|
||||
|
||||
// @note we don't config 14D access, since the default admin is a 14D timelock which can access all methods.
|
||||
configProxyAdmin();
|
||||
configScrollChain();
|
||||
configL1MessageQueue();
|
||||
configL1ScrollMessenger();
|
||||
configL2GasPriceOracle();
|
||||
configL1Whitelist();
|
||||
configMultipleVersionRollupVerifier();
|
||||
configL1GatewayRouter();
|
||||
configL1CustomERC20Gateway();
|
||||
configL1ERC721Gateway();
|
||||
configL1ERC1155Gateway();
|
||||
|
||||
// @note comments out for testnet
|
||||
// configEnforcedTxGateway();
|
||||
// configL1USDCGateway();
|
||||
|
||||
grantRoles();
|
||||
transferOwnership();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function transferOwnership() internal {
|
||||
Ownable(L1_PROXY_ADMIN_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_SCROLL_CHAIN_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_MESSAGE_QUEUE_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_SCROLL_MESSENGER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
// Ownable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_GAS_PRICE_ORACLE_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_WHITELIST_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_GATEWAY_ROUTER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_ETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
// Ownable(L1_USDC_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_WETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_ERC721_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_ERC1155_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
}
|
||||
|
||||
function grantRoles() internal {
|
||||
owner.grantRole(SECURITY_COUNCIL_NO_DELAY_ROLE, SECURITY_COUNCIL_ADDR);
|
||||
owner.grantRole(SCROLL_MULTISIG_NO_DELAY_ROLE, SCROLL_MULTISIG_ADDR);
|
||||
owner.grantRole(EMERGENCY_MULTISIG_NO_DELAY_ROLE, EMERGENCY_MULTISIG_ADDR);
|
||||
owner.grantRole(TIMELOCK_1DAY_DELAY_ROLE, L1_1D_TIMELOCK_ADDR);
|
||||
owner.grantRole(TIMELOCK_7DAY_DELAY_ROLE, L1_7D_TIMELOCK_ADDR);
|
||||
|
||||
owner.grantRole(owner.DEFAULT_ADMIN_ROLE(), L1_14D_TIMELOCK_ADDR);
|
||||
owner.revokeRole(owner.DEFAULT_ADMIN_ROLE(), vm.addr(L1_DEPLOYER_PRIVATE_KEY));
|
||||
}
|
||||
|
||||
function configProxyAdmin() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, security council
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = ProxyAdmin.upgrade.selector;
|
||||
_selectors[1] = ProxyAdmin.upgradeAndCall.selector;
|
||||
owner.updateAccess(L1_PROXY_ADMIN_ADDR, _selectors, SECURITY_COUNCIL_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configScrollChain() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](4);
|
||||
_selectors[0] = ScrollChain.revertBatch.selector;
|
||||
_selectors[1] = ScrollChain.removeSequencer.selector;
|
||||
_selectors[2] = ScrollChain.removeProver.selector;
|
||||
_selectors[3] = ScrollChain.setPause.selector;
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = ScrollChain.addSequencer.selector;
|
||||
_selectors[1] = ScrollChain.addProver.selector;
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = ScrollChain.updateMaxNumTxInChunk.selector;
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1MessageQueue() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = L1MessageQueue.updateGasOracle.selector;
|
||||
_selectors[1] = L1MessageQueue.updateMaxGasLimit.selector;
|
||||
owner.updateAccess(L1_MESSAGE_QUEUE_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1ScrollMessenger() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = ScrollMessengerBase.setPause.selector;
|
||||
owner.updateAccess(L1_SCROLL_MESSENGER_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_SCROLL_MESSENGER_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1ScrollMessenger.updateMaxReplayTimes.selector;
|
||||
owner.updateAccess(L1_SCROLL_MESSENGER_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2GasPriceOracle() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2GasPriceOracle.setIntrinsicParams.selector;
|
||||
owner.updateAccess(L2_GAS_PRICE_ORACLE_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_GAS_PRICE_ORACLE_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1Whitelist() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = Whitelist.updateWhitelistStatus.selector;
|
||||
owner.updateAccess(L1_WHITELIST_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configMultipleVersionRollupVerifier() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, security council
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = MultipleVersionRollupVerifier.updateVerifier.selector;
|
||||
owner.updateAccess(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR, _selectors, SECURITY_COUNCIL_NO_DELAY_ROLE, true);
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = MultipleVersionRollupVerifier.updateVerifier.selector;
|
||||
owner.updateAccess(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1GatewayRouter() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1GatewayRouter.setERC20Gateway.selector;
|
||||
owner.updateAccess(L1_GATEWAY_ROUTER_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1CustomERC20Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1CustomERC20Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1ERC721Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1ERC721Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L1_ERC721_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1ERC1155Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1ERC1155Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L1_ERC1155_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
/*
|
||||
function configL1USDCGateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](3);
|
||||
_selectors[0] = L1USDCGateway.updateCircleCaller.selector;
|
||||
_selectors[1] = L1USDCGateway.pauseDeposit.selector;
|
||||
_selectors[2] = L1USDCGateway.pauseWithdraw.selector;
|
||||
owner.updateAccess(L1_USDC_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configEnforcedTxGateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = EnforcedTxGateway.setPause.selector;
|
||||
owner.updateAccess(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import {L2ETHGateway} from "../../src/L2/gateways/L2ETHGateway.sol";
|
||||
import {L2GatewayRouter} from "../../src/L2/gateways/L2GatewayRouter.sol";
|
||||
import {L2StandardERC20Gateway} from "../../src/L2/gateways/L2StandardERC20Gateway.sol";
|
||||
import {L2WETHGateway} from "../../src/L2/gateways/L2WETHGateway.sol";
|
||||
import {L2DAIGateway} from "../../src/L2/gateways/L2DAIGateway.sol";
|
||||
import {L2MessageQueue} from "../../src/L2/predeploys/L2MessageQueue.sol";
|
||||
import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol";
|
||||
import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol";
|
||||
@@ -23,9 +22,6 @@ contract InitializeL2BridgeContracts is Script {
|
||||
|
||||
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
|
||||
|
||||
address L1_DAI_ADDR = vm.envAddress("L1_DAI_ADDR");
|
||||
address L2_DAI_ADDR = vm.envAddress("L2_DAI_ADDR");
|
||||
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L1_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L1_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
@@ -34,7 +30,6 @@ contract InitializeL2BridgeContracts is Script {
|
||||
address L1_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L1_DAI_GATEWAY_PROXY_ADDR");
|
||||
|
||||
address L2_TX_FEE_VAULT_ADDR = vm.envAddress("L2_TX_FEE_VAULT_ADDR");
|
||||
address L1_GAS_PRICE_ORACLE_ADDR = vm.envAddress("L1_GAS_PRICE_ORACLE_ADDR");
|
||||
@@ -49,7 +44,6 @@ contract InitializeL2BridgeContracts is Script {
|
||||
address L2_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L2_DAI_GATEWAY_PROXY_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR");
|
||||
|
||||
function run() external {
|
||||
@@ -114,22 +108,12 @@ contract InitializeL2BridgeContracts is Script {
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L2DAIGateway
|
||||
L2DAIGateway(L2_DAI_GATEWAY_PROXY_ADDR).initialize(
|
||||
L1_DAI_GATEWAY_PROXY_ADDR,
|
||||
L2_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
L2DAIGateway(L2_DAI_GATEWAY_PROXY_ADDR).updateTokenMapping(L2_DAI_ADDR, L1_DAI_ADDR);
|
||||
|
||||
// set WETH and DAI gateways in router
|
||||
// set WETH gateway in router
|
||||
{
|
||||
address[] memory _tokens = new address[](2);
|
||||
address[] memory _tokens = new address[](1);
|
||||
_tokens[0] = L2_WETH_ADDR;
|
||||
_tokens[1] = L2_DAI_ADDR;
|
||||
address[] memory _gateways = new address[](2);
|
||||
address[] memory _gateways = new address[](1);
|
||||
_gateways[0] = L2_WETH_GATEWAY_PROXY_ADDR;
|
||||
_gateways[1] = L2_DAI_GATEWAY_PROXY_ADDR;
|
||||
L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways);
|
||||
}
|
||||
|
||||
|
||||
216
contracts/scripts/foundry/InitializeL2ScrollOwner.s.sol
Normal file
216
contracts/scripts/foundry/InitializeL2ScrollOwner.s.sol
Normal file
@@ -0,0 +1,216 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
import {AccessControlEnumerable} from "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
|
||||
import {L2USDCGateway} from "../../src/L2/gateways/usdc/L2USDCGateway.sol";
|
||||
import {L2CustomERC20Gateway} from "../../src/L2/gateways/L2CustomERC20Gateway.sol";
|
||||
import {L2CustomERC20Gateway} from "../../src/L2/gateways/L2CustomERC20Gateway.sol";
|
||||
import {L2ERC1155Gateway} from "../../src/L2/gateways/L2ERC1155Gateway.sol";
|
||||
import {L2ERC721Gateway} from "../../src/L2/gateways/L2ERC721Gateway.sol";
|
||||
import {L2GatewayRouter} from "../../src/L2/gateways/L2GatewayRouter.sol";
|
||||
import {ScrollMessengerBase} from "../../src/libraries/ScrollMessengerBase.sol";
|
||||
import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol";
|
||||
import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol";
|
||||
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract InitializeL2ScrollOwner is Script {
|
||||
uint256 L2_DEPLOYER_PRIVATE_KEY = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
bytes32 constant SECURITY_COUNCIL_NO_DELAY_ROLE = keccak256("SECURITY_COUNCIL_NO_DELAY_ROLE");
|
||||
bytes32 constant SCROLL_MULTISIG_NO_DELAY_ROLE = keccak256("SCROLL_MULTISIG_NO_DELAY_ROLE");
|
||||
bytes32 constant EMERGENCY_MULTISIG_NO_DELAY_ROLE = keccak256("EMERGENCY_MULTISIG_NO_DELAY_ROLE");
|
||||
|
||||
bytes32 constant TIMELOCK_1DAY_DELAY_ROLE = keccak256("TIMELOCK_1DAY_DELAY_ROLE");
|
||||
bytes32 constant TIMELOCK_7DAY_DELAY_ROLE = keccak256("TIMELOCK_7DAY_DELAY_ROLE");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L2_SCROLL_MULTISIG_ADDR");
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L2_SECURITY_COUNCIL_ADDR");
|
||||
address EMERGENCY_MULTISIG_ADDR = vm.envAddress("L2_EMERGENCY_MULTISIG_ADDR");
|
||||
|
||||
address L2_SCROLL_OWNER_ADDR = vm.envAddress("L2_SCROLL_OWNER_ADDR");
|
||||
address L2_1D_TIMELOCK_ADDR = vm.envAddress("L2_1D_TIMELOCK_ADDR");
|
||||
address L2_7D_TIMELOCK_ADDR = vm.envAddress("L2_7D_TIMELOCK_ADDR");
|
||||
address L2_14D_TIMELOCK_ADDR = vm.envAddress("L2_14D_TIMELOCK_ADDR");
|
||||
|
||||
address L2_PROXY_ADMIN_ADDR = vm.envAddress("L2_PROXY_ADMIN_ADDR");
|
||||
address L2_TX_FEE_VAULT_ADDR = vm.envAddress("L2_TX_FEE_VAULT_ADDR");
|
||||
address L1_GAS_PRICE_ORACLE_ADDR = vm.envAddress("L1_GAS_PRICE_ORACLE_ADDR");
|
||||
address L2_WHITELIST_ADDR = vm.envAddress("L2_WHITELIST_ADDR");
|
||||
address L2_MESSAGE_QUEUE_ADDR = vm.envAddress("L2_MESSAGE_QUEUE_ADDR");
|
||||
|
||||
address L2_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L2_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L2_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
// address L2_USDC_GATEWAY_PROXY_ADDR = vm.envAddress("L2_USDC_GATEWAY_PROXY_ADDR");
|
||||
address L2_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
|
||||
ScrollOwner owner;
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L2_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
owner = ScrollOwner(payable(L2_SCROLL_OWNER_ADDR));
|
||||
|
||||
// @note we don't config 14D access, since the default admin is a 14D timelock which can access all methods.
|
||||
configProxyAdmin();
|
||||
configL1GasPriceOracle();
|
||||
configL2TxFeeVault();
|
||||
configL2Whitelist();
|
||||
configL2ScrollMessenger();
|
||||
configL2GatewayRouter();
|
||||
configL2CustomERC20Gateway();
|
||||
configL2ERC721Gateway();
|
||||
configL2ERC1155Gateway();
|
||||
|
||||
// @note comments out for testnet
|
||||
// configL2USDCGateway();
|
||||
|
||||
grantRoles();
|
||||
transferOwnership();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function transferOwnership() internal {
|
||||
Ownable(L2_PROXY_ADMIN_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_MESSAGE_QUEUE_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_GAS_PRICE_ORACLE_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_TX_FEE_VAULT_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_WHITELIST_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_SCROLL_MESSENGER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_GATEWAY_ROUTER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_ETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_WETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_ERC721_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_ERC1155_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
|
||||
// Ownable(L2_USDC_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
}
|
||||
|
||||
function grantRoles() internal {
|
||||
owner.grantRole(SECURITY_COUNCIL_NO_DELAY_ROLE, SECURITY_COUNCIL_ADDR);
|
||||
owner.grantRole(SCROLL_MULTISIG_NO_DELAY_ROLE, SCROLL_MULTISIG_ADDR);
|
||||
owner.grantRole(EMERGENCY_MULTISIG_NO_DELAY_ROLE, EMERGENCY_MULTISIG_ADDR);
|
||||
owner.grantRole(TIMELOCK_1DAY_DELAY_ROLE, L2_1D_TIMELOCK_ADDR);
|
||||
owner.grantRole(TIMELOCK_7DAY_DELAY_ROLE, L2_7D_TIMELOCK_ADDR);
|
||||
|
||||
owner.grantRole(owner.DEFAULT_ADMIN_ROLE(), L2_14D_TIMELOCK_ADDR);
|
||||
owner.revokeRole(owner.DEFAULT_ADMIN_ROLE(), vm.addr(L2_DEPLOYER_PRIVATE_KEY));
|
||||
}
|
||||
|
||||
function configProxyAdmin() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, security council
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = ProxyAdmin.upgrade.selector;
|
||||
_selectors[1] = ProxyAdmin.upgradeAndCall.selector;
|
||||
owner.updateAccess(L2_PROXY_ADMIN_ADDR, _selectors, SECURITY_COUNCIL_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1GasPriceOracle() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = L1GasPriceOracle.setOverhead.selector;
|
||||
_selectors[1] = L1GasPriceOracle.setScalar.selector;
|
||||
owner.updateAccess(L1_GAS_PRICE_ORACLE_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_GAS_PRICE_ORACLE_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2TxFeeVault() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2TxFeeVault.updateMinWithdrawAmount.selector;
|
||||
owner.updateAccess(L2_TX_FEE_VAULT_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_TX_FEE_VAULT_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2Whitelist() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = Whitelist.updateWhitelistStatus.selector;
|
||||
owner.updateAccess(L2_WHITELIST_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2ScrollMessenger() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = ScrollMessengerBase.setPause.selector;
|
||||
owner.updateAccess(L2_SCROLL_MESSENGER_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_SCROLL_MESSENGER_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2GatewayRouter() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2GatewayRouter.setERC20Gateway.selector;
|
||||
owner.updateAccess(L2_GATEWAY_ROUTER_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2CustomERC20Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2CustomERC20Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2ERC721Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2ERC721Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L2_ERC721_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2ERC1155Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2ERC1155Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L2_ERC1155_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
/*
|
||||
function configL2USDCGateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](3);
|
||||
_selectors[0] = L2USDCGateway.updateCircleCaller.selector;
|
||||
_selectors[1] = L2USDCGateway.pauseDeposit.selector;
|
||||
_selectors[2] = L2USDCGateway.pauseWithdraw.selector;
|
||||
owner.updateAccess(L2_USDC_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
pragma solidity =0.8.16;
|
||||
|
||||
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
import {MinimalForwarder} from "@openzeppelin/contracts/metatx/MinimalForwarder.sol";
|
||||
|
||||
@@ -115,7 +115,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external payable override whenNotPaused {
|
||||
_sendMessage(_to, _value, _message, _gasLimit, msg.sender);
|
||||
_sendMessage(_to, _value, _message, _gasLimit, _msgSender());
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollMessenger
|
||||
@@ -316,14 +316,12 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
uint256 _gasLimit,
|
||||
address _refundAddress
|
||||
) internal nonReentrant {
|
||||
_addUsedAmount(_value);
|
||||
|
||||
address _messageQueue = messageQueue; // gas saving
|
||||
address _counterpart = counterpart; // gas saving
|
||||
|
||||
// compute the actual cross domain message calldata.
|
||||
uint256 _messageNonce = IL1MessageQueue(_messageQueue).nextCrossDomainMessageIndex();
|
||||
bytes memory _xDomainCalldata = _encodeXDomainCalldata(msg.sender, _to, _value, _messageNonce, _message);
|
||||
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_msgSender(), _to, _value, _messageNonce, _message);
|
||||
|
||||
// compute and deduct the messaging fee to fee vault.
|
||||
uint256 _fee = IL1MessageQueue(_messageQueue).estimateCrossDomainMessageFee(_gasLimit);
|
||||
@@ -343,7 +341,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
require(messageSendTimestamp[_xDomainCalldataHash] == 0, "Duplicated message");
|
||||
messageSendTimestamp[_xDomainCalldataHash] = block.timestamp;
|
||||
|
||||
emit SentMessage(msg.sender, _to, _value, _messageNonce, _gasLimit, _message);
|
||||
emit SentMessage(_msgSender(), _to, _value, _messageNonce, _gasLimit, _message);
|
||||
|
||||
// refund fee to `_refundAddress`
|
||||
unchecked {
|
||||
|
||||
@@ -66,7 +66,7 @@ contract L1ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC1155(_token, msg.sender, _tokenId, _amount, _gasLimit);
|
||||
_depositERC1155(_token, _msgSender(), _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
@@ -87,7 +87,7 @@ contract L1ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC1155(_token, msg.sender, _tokenIds, _amounts, _gasLimit);
|
||||
_batchDepositERC1155(_token, _msgSender(), _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
@@ -198,19 +198,21 @@ contract L1ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "no corresponding l2 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC1155Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId, _amount, "");
|
||||
IERC1155Upgradeable(_token).safeTransferFrom(_sender, address(this), _tokenId, _amount, "");
|
||||
|
||||
// 2. Generate message passed to L2ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL2ERC1155Gateway.finalizeDepositERC1155,
|
||||
(_token, _l2Token, msg.sender, _to, _tokenId, _amount)
|
||||
(_token, _l2Token, _sender, _to, _tokenId, _amount)
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
|
||||
|
||||
emit DepositERC1155(_token, _l2Token, msg.sender, _to, _tokenId, _amount);
|
||||
emit DepositERC1155(_token, _l2Token, _sender, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch deposit ERC1155 NFT to layer 2.
|
||||
@@ -236,18 +238,20 @@ contract L1ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "no corresponding l2 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC1155Upgradeable(_token).safeBatchTransferFrom(msg.sender, address(this), _tokenIds, _amounts, "");
|
||||
IERC1155Upgradeable(_token).safeBatchTransferFrom(_sender, address(this), _tokenIds, _amounts, "");
|
||||
|
||||
// 2. Generate message passed to L2ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL2ERC1155Gateway.finalizeBatchDepositERC1155,
|
||||
(_token, _l2Token, msg.sender, _to, _tokenIds, _amounts)
|
||||
(_token, _l2Token, _sender, _to, _tokenIds, _amounts)
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
|
||||
|
||||
emit BatchDepositERC1155(_token, _l2Token, msg.sender, _to, _tokenIds, _amounts);
|
||||
emit BatchDepositERC1155(_token, _l2Token, _sender, _to, _tokenIds, _amounts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
_deposit(_token, _msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
@@ -144,11 +144,12 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
|
||||
bytes memory
|
||||
)
|
||||
{
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _sender = _msgSender();
|
||||
address _from = _sender;
|
||||
if (router == _sender) {
|
||||
// Extract real sender if this call is from L1GatewayRouter.
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
_amount = IL1GatewayRouter(msg.sender).requestERC20(_from, _token, _amount);
|
||||
_amount = IL1GatewayRouter(_sender).requestERC20(_from, _token, _amount);
|
||||
} else {
|
||||
// common practice to handle fee on transfer token.
|
||||
uint256 _before = IERC20Upgradeable(_token).balanceOf(address(this));
|
||||
@@ -160,9 +161,6 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
|
||||
// ignore weird fee on transfer token
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
|
||||
// rate limit
|
||||
_addUsedAmount(_token, _amount);
|
||||
|
||||
return (_from, _amount, _data);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC72
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC721(_token, msg.sender, _tokenId, _gasLimit);
|
||||
_depositERC721(_token, _msgSender(), _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
@@ -83,7 +83,7 @@ contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC72
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC721(_token, msg.sender, _tokenIds, _gasLimit);
|
||||
_batchDepositERC721(_token, _msgSender(), _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
@@ -190,19 +190,21 @@ contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC72
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "no corresponding l2 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId);
|
||||
IERC721Upgradeable(_token).safeTransferFrom(_sender, address(this), _tokenId);
|
||||
|
||||
// 2. Generate message passed to L2ERC721Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL2ERC721Gateway.finalizeDepositERC721,
|
||||
(_token, _l2Token, msg.sender, _to, _tokenId)
|
||||
(_token, _l2Token, _sender, _to, _tokenId)
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
|
||||
|
||||
emit DepositERC721(_token, _l2Token, msg.sender, _to, _tokenId);
|
||||
emit DepositERC721(_token, _l2Token, _sender, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch deposit ERC721 NFT to layer 2.
|
||||
@@ -221,20 +223,22 @@ contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC72
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "no corresponding l2 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. transfer token to this contract
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenIds[i]);
|
||||
IERC721Upgradeable(_token).safeTransferFrom(_sender, address(this), _tokenIds[i]);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L2ERC721Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL2ERC721Gateway.finalizeBatchDepositERC721,
|
||||
(_token, _l2Token, msg.sender, _to, _tokenIds)
|
||||
(_token, _l2Token, _sender, _to, _tokenIds)
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
|
||||
|
||||
emit BatchDepositERC721(_token, _l2Token, msg.sender, _to, _tokenIds);
|
||||
emit BatchDepositERC721(_token, _l2Token, _sender, _to, _tokenIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ contract L1ETHGateway is ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
_deposit(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
_deposit(_msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
@@ -119,8 +119,8 @@ contract L1ETHGateway is ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback
|
||||
require(_amount > 0, "deposit zero eth");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _from = _msgSender();
|
||||
if (router == _from) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
|
||||
}
|
||||
|
||||
modifier onlyInContext() {
|
||||
require(msg.sender == gatewayInContext, "Only in deposit context");
|
||||
require(_msgSender() == gatewayInContext, "Only in deposit context");
|
||||
_;
|
||||
}
|
||||
|
||||
@@ -110,9 +110,10 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
|
||||
address _token,
|
||||
uint256 _amount
|
||||
) external onlyInContext returns (uint256) {
|
||||
uint256 _balance = IERC20Upgradeable(_token).balanceOf(msg.sender);
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_sender, msg.sender, _amount);
|
||||
_amount = IERC20Upgradeable(_token).balanceOf(msg.sender) - _balance;
|
||||
address _caller = _msgSender();
|
||||
uint256 _balance = IERC20Upgradeable(_token).balanceOf(_caller);
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_sender, _caller, _amount);
|
||||
_amount = IERC20Upgradeable(_token).balanceOf(_caller) - _balance;
|
||||
return _amount;
|
||||
}
|
||||
|
||||
@@ -126,7 +127,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
depositERC20AndCall(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
depositERC20AndCall(_token, _msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
@@ -154,7 +155,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
|
||||
gatewayInContext = _gateway;
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
bytes memory _routerData = abi.encode(_msgSender(), _data);
|
||||
|
||||
IL1ERC20Gateway(_gateway).depositERC20AndCall{value: msg.value}(_token, _to, _amount, _routerData, _gasLimit);
|
||||
|
||||
@@ -180,7 +181,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
depositETHAndCall(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
depositETHAndCall(_msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
@@ -203,7 +204,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
|
||||
require(_gateway != address(0), "eth gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
bytes memory _routerData = abi.encode(_msgSender(), _data);
|
||||
|
||||
IL1ETHGateway(_gateway).depositETHAndCall{value: msg.value}(_to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ contract L1WETHGateway is L1ERC20Gateway {
|
||||
}
|
||||
|
||||
receive() external payable {
|
||||
require(msg.sender == WETH, "only WETH");
|
||||
require(_msgSender() == WETH, "only WETH");
|
||||
}
|
||||
|
||||
/*************************
|
||||
|
||||
@@ -84,7 +84,7 @@ contract L1USDCGateway is L1ERC20Gateway, IUSDCBurnableSourceBridge {
|
||||
|
||||
/// @inheritdoc IUSDCBurnableSourceBridge
|
||||
function burnAllLockedUSDC() external override {
|
||||
require(msg.sender == circleCaller, "only circle caller");
|
||||
require(_msgSender() == circleCaller, "only circle caller");
|
||||
|
||||
// @note Only bridged USDC will be burned. We may refund the rest if possible.
|
||||
uint256 _balance = totalBridgedUSDC;
|
||||
|
||||
@@ -64,7 +64,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
/// @notice The max gas limit of L1 transactions.
|
||||
uint256 public maxGasLimit;
|
||||
|
||||
/// @dev The bitmap for skipped messages.
|
||||
/// @dev The bitmap for dropped messages, where `droppedMessageBitmap[i]` keeps the bits from `[i*256, (i+1)*256)`.
|
||||
BitMapsUpgradeable.BitMap private droppedMessageBitmap;
|
||||
|
||||
/// @dev The bitmap for skipped messages, where `skippedMessageBitmap[i]` keeps the bits from `[i*256, (i+1)*256)`.
|
||||
@@ -75,7 +75,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
**********************/
|
||||
|
||||
modifier onlyMessenger() {
|
||||
require(msg.sender == messenger, "Only callable by the L1ScrollMessenger");
|
||||
require(_msgSender() == messenger, "Only callable by the L1ScrollMessenger");
|
||||
_;
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
_validateGasLimit(_gasLimit, _data);
|
||||
|
||||
// do address alias to avoid replay attack in L2.
|
||||
address _sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
|
||||
address _sender = AddressAliasHelper.applyL1ToL2Alias(_msgSender());
|
||||
|
||||
_queueTransaction(_sender, _target, 0, _gasLimit, _data);
|
||||
}
|
||||
@@ -305,7 +305,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
uint256 _gasLimit,
|
||||
bytes calldata _data
|
||||
) external override {
|
||||
require(msg.sender == enforcedTxGateway, "Only callable by the EnforcedTxGateway");
|
||||
require(_msgSender() == enforcedTxGateway, "Only callable by the EnforcedTxGateway");
|
||||
// We will check it in EnforcedTxGateway, just in case.
|
||||
require(_sender.code.length == 0, "only EOA");
|
||||
|
||||
@@ -321,7 +321,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
uint256 _count,
|
||||
uint256 _skippedBitmap
|
||||
) external {
|
||||
require(msg.sender == scrollChain, "Only callable by the ScrollChain");
|
||||
require(_msgSender() == scrollChain, "Only callable by the ScrollChain");
|
||||
|
||||
require(_count <= 256, "pop too many messages");
|
||||
require(pendingQueueIndex == _startIndex, "start index mismatch");
|
||||
|
||||
@@ -108,26 +108,10 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Allows the owner to update parameters for intrinsic gas calculation.
|
||||
/// @param _txGas The intrinsic gas for transaction.
|
||||
/// @param _txGasContractCreation The intrinsic gas for contract creation.
|
||||
/// @param _zeroGas The intrinsic gas for each zero byte.
|
||||
/// @param _nonZeroGas The intrinsic gas for each nonzero byte.
|
||||
function setIntrinsicParams(
|
||||
uint64 _txGas,
|
||||
uint64 _txGasContractCreation,
|
||||
uint64 _zeroGas,
|
||||
uint64 _nonZeroGas
|
||||
) external {
|
||||
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
|
||||
|
||||
_setIntrinsicParams(_txGas, _txGasContractCreation, _zeroGas, _nonZeroGas);
|
||||
}
|
||||
|
||||
/// @notice Allows the owner to modify the l2 base fee.
|
||||
/// @notice Allows whitelisted caller to modify the l2 base fee.
|
||||
/// @param _newL2BaseFee The new l2 base fee.
|
||||
function setL2BaseFee(uint256 _newL2BaseFee) external {
|
||||
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
|
||||
require(whitelist.isSenderAllowed(_msgSender()), "Not whitelisted sender");
|
||||
|
||||
uint256 _oldL2BaseFee = l2BaseFee;
|
||||
l2BaseFee = _newL2BaseFee;
|
||||
@@ -149,6 +133,20 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
|
||||
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
|
||||
}
|
||||
|
||||
/// @notice Allows the owner to update parameters for intrinsic gas calculation.
|
||||
/// @param _txGas The intrinsic gas for transaction.
|
||||
/// @param _txGasContractCreation The intrinsic gas for contract creation.
|
||||
/// @param _zeroGas The intrinsic gas for each zero byte.
|
||||
/// @param _nonZeroGas The intrinsic gas for each nonzero byte.
|
||||
function setIntrinsicParams(
|
||||
uint64 _txGas,
|
||||
uint64 _txGasContractCreation,
|
||||
uint64 _zeroGas,
|
||||
uint64 _nonZeroGas
|
||||
) external onlyOwner {
|
||||
_setIntrinsicParams(_txGas, _txGasContractCreation, _zeroGas, _nonZeroGas);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
@@ -85,12 +85,12 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
|
||||
|
||||
modifier OnlySequencer() {
|
||||
// @note In the decentralized mode, it should be only called by a list of validator.
|
||||
require(isSequencer[msg.sender], "caller not sequencer");
|
||||
require(isSequencer[_msgSender()], "caller not sequencer");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier OnlyProver() {
|
||||
require(isProver[msg.sender], "caller not prover");
|
||||
require(isProver[_msgSender()], "caller not prover");
|
||||
_;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ contract L2ScrollMessenger is ScrollMessengerBase, IL2ScrollMessenger {
|
||||
bytes memory _message
|
||||
) external override whenNotPaused {
|
||||
// It is impossible to deploy a contract with the same address, reentrance is prevented in nature.
|
||||
require(AddressAliasHelper.undoL1ToL2Alias(msg.sender) == counterpart, "Caller is not L1ScrollMessenger");
|
||||
require(AddressAliasHelper.undoL1ToL2Alias(_msgSender()) == counterpart, "Caller is not L1ScrollMessenger");
|
||||
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
|
||||
|
||||
@@ -117,10 +117,9 @@ contract L2ScrollMessenger is ScrollMessengerBase, IL2ScrollMessenger {
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(msg.value == _value, "msg.value mismatch");
|
||||
_addUsedAmount(_value);
|
||||
|
||||
uint256 _nonce = L2MessageQueue(messageQueue).nextMessageIndex();
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(msg.sender, _to, _value, _nonce, _message));
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_msgSender(), _to, _value, _nonce, _message));
|
||||
|
||||
// normally this won't happen, since each message has different nonce, but just in case.
|
||||
require(messageSendTimestamp[_xDomainCalldataHash] == 0, "Duplicated message");
|
||||
@@ -128,7 +127,7 @@ contract L2ScrollMessenger is ScrollMessengerBase, IL2ScrollMessenger {
|
||||
|
||||
L2MessageQueue(messageQueue).appendMessage(_xDomainCalldataHash);
|
||||
|
||||
emit SentMessage(msg.sender, _to, _value, _nonce, _gasLimit, _message);
|
||||
emit SentMessage(_msgSender(), _to, _value, _nonce, _gasLimit, _message);
|
||||
}
|
||||
|
||||
/// @dev Internal function to execute a L1 => L2 message.
|
||||
|
||||
@@ -121,14 +121,11 @@ contract L2CustomERC20Gateway is L2ERC20Gateway {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
|
||||
// 1. Extract real sender if this call is from L2GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _from = _msgSender();
|
||||
if (router == _from) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// rate limit
|
||||
_addUsedAmount(_token, _amount);
|
||||
|
||||
// 2. Burn token.
|
||||
IScrollERC20Upgradeable(_token).burn(_from, _amount);
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ contract L2ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdrawERC1155(_token, msg.sender, _tokenId, _amount, _gasLimit);
|
||||
_withdrawERC1155(_token, _msgSender(), _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
@@ -82,7 +82,7 @@ contract L2ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchWithdrawERC1155(_token, msg.sender, _tokenIds, _amounts, _gasLimit);
|
||||
_batchWithdrawERC1155(_token, _msgSender(), _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
@@ -168,19 +168,21 @@ contract L2ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. burn token
|
||||
IScrollERC1155(_token).burn(msg.sender, _tokenId, _amount);
|
||||
IScrollERC1155(_token).burn(_sender, _tokenId, _amount);
|
||||
|
||||
// 2. Generate message passed to L1ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL1ERC1155Gateway.finalizeWithdrawERC1155,
|
||||
(_l1Token, _token, msg.sender, _to, _tokenId, _amount)
|
||||
(_l1Token, _token, _sender, _to, _tokenId, _amount)
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC1155(_l1Token, _token, msg.sender, _to, _tokenId, _amount);
|
||||
emit WithdrawERC1155(_l1Token, _token, _sender, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch withdraw ERC1155 NFT to layer 2.
|
||||
@@ -206,18 +208,20 @@ contract L2ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IScrollERC1155(_token).batchBurn(msg.sender, _tokenIds, _amounts);
|
||||
IScrollERC1155(_token).batchBurn(_sender, _tokenIds, _amounts);
|
||||
|
||||
// 2. Generate message passed to L1ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL1ERC1155Gateway.finalizeBatchWithdrawERC1155,
|
||||
(_l1Token, _token, msg.sender, _to, _tokenIds, _amounts)
|
||||
(_l1Token, _token, _sender, _to, _tokenIds, _amounts)
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit BatchWithdrawERC1155(_l1Token, _token, msg.sender, _to, _tokenIds, _amounts);
|
||||
emit BatchWithdrawERC1155(_l1Token, _token, _sender, _to, _tokenIds, _amounts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ abstract contract L2ERC20Gateway is ScrollGatewayBase, IL2ERC20Gateway {
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdraw(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
_withdraw(_token, _msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
|
||||
@@ -59,7 +59,7 @@ contract L2ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC72
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdrawERC721(_token, msg.sender, _tokenId, _gasLimit);
|
||||
_withdrawERC721(_token, _msgSender(), _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
@@ -78,7 +78,7 @@ contract L2ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC72
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchWithdrawERC721(_token, msg.sender, _tokenIds, _gasLimit);
|
||||
_batchWithdrawERC721(_token, _msgSender(), _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
@@ -159,21 +159,23 @@ contract L2ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC72
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. burn token
|
||||
// @note in case the token has given too much power to the gateway, we check owner here.
|
||||
require(IScrollERC721(_token).ownerOf(_tokenId) == msg.sender, "token not owned");
|
||||
require(IScrollERC721(_token).ownerOf(_tokenId) == _sender, "token not owned");
|
||||
IScrollERC721(_token).burn(_tokenId);
|
||||
|
||||
// 2. Generate message passed to L1ERC721Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL1ERC721Gateway.finalizeWithdrawERC721,
|
||||
(_l1Token, _token, msg.sender, _to, _tokenId)
|
||||
(_l1Token, _token, _sender, _to, _tokenId)
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC721(_l1Token, _token, msg.sender, _to, _tokenId);
|
||||
emit WithdrawERC721(_l1Token, _token, _sender, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch withdraw ERC721 NFT to layer 1.
|
||||
@@ -192,22 +194,24 @@ contract L2ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC72
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
address _sender = _msgSender();
|
||||
|
||||
// 1. transfer token to this contract
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
// @note in case the token has given too much power to the gateway, we check owner here.
|
||||
require(IScrollERC721(_token).ownerOf(_tokenIds[i]) == msg.sender, "token not owned");
|
||||
require(IScrollERC721(_token).ownerOf(_tokenIds[i]) == _sender, "token not owned");
|
||||
IScrollERC721(_token).burn(_tokenIds[i]);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L1ERC721Gateway.
|
||||
bytes memory _message = abi.encodeCall(
|
||||
IL1ERC721Gateway.finalizeBatchWithdrawERC721,
|
||||
(_l1Token, _token, msg.sender, _to, _tokenIds)
|
||||
(_l1Token, _token, _sender, _to, _tokenIds)
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit BatchWithdrawERC721(_l1Token, _token, msg.sender, _to, _tokenIds);
|
||||
emit BatchWithdrawERC721(_l1Token, _token, _sender, _to, _tokenIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ contract L2ETHGateway is ScrollGatewayBase, IL2ETHGateway {
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
_withdraw(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
_withdraw(_msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
@@ -93,8 +93,8 @@ contract L2ETHGateway is ScrollGatewayBase, IL2ETHGateway {
|
||||
require(msg.value > 0, "withdraw zero eth");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _from = _msgSender();
|
||||
if (router == _from) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ contract L2GatewayRouter is OwnableUpgradeable, IL2GatewayRouter {
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
withdrawERC20AndCall(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
withdrawERC20AndCall(_token, _msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
@@ -116,14 +116,14 @@ contract L2GatewayRouter is OwnableUpgradeable, IL2GatewayRouter {
|
||||
require(_gateway != address(0), "no gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
bytes memory _routerData = abi.encode(_msgSender(), _data);
|
||||
|
||||
IL2ERC20Gateway(_gateway).withdrawERC20AndCall{value: msg.value}(_token, _to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
withdrawETHAndCall(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
withdrawETHAndCall(_msgSender(), _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
@@ -146,7 +146,7 @@ contract L2GatewayRouter is OwnableUpgradeable, IL2GatewayRouter {
|
||||
require(_gateway != address(0), "eth gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
bytes memory _routerData = abi.encode(_msgSender(), _data);
|
||||
|
||||
IL2ETHGateway(_gateway).withdrawETHAndCall{value: msg.value}(_to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
@@ -132,17 +132,14 @@ contract L2StandardERC20Gateway is L2ERC20Gateway {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
|
||||
// 1. Extract real sender if this call is from L2GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _from = _msgSender();
|
||||
if (router == _from) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
// rate limit
|
||||
_addUsedAmount(_token, _amount);
|
||||
|
||||
// 2. Burn token.
|
||||
IScrollERC20Upgradeable(_token).burn(_from, _amount);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ contract L2WETHGateway is L2ERC20Gateway {
|
||||
}
|
||||
|
||||
receive() external payable {
|
||||
require(msg.sender == WETH, "only WETH");
|
||||
require(_msgSender() == WETH, "only WETH");
|
||||
}
|
||||
|
||||
/*************************
|
||||
@@ -111,14 +111,11 @@ contract L2WETHGateway is L2ERC20Gateway {
|
||||
require(_token == WETH, "only WETH is allowed");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _from = _msgSender();
|
||||
if (router == _from) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// rate limit
|
||||
_addUsedAmount(_token, _amount);
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
IWETH(_token).withdraw(_amount);
|
||||
|
||||
@@ -116,7 +116,7 @@ contract L2USDCGateway is L2ERC20Gateway, IUSDCDestinationBridge {
|
||||
|
||||
/// @inheritdoc IUSDCDestinationBridge
|
||||
function transferUSDCRoles(address _owner) external {
|
||||
require(msg.sender == circleCaller, "only circle caller");
|
||||
require(_msgSender() == circleCaller, "only circle caller");
|
||||
|
||||
OwnableUpgradeable(l2USDC).transferOwnership(_owner);
|
||||
}
|
||||
@@ -156,15 +156,12 @@ contract L2USDCGateway is L2ERC20Gateway, IUSDCDestinationBridge {
|
||||
require(!withdrawPaused, "withdraw paused");
|
||||
|
||||
// 1. Extract real sender if this call is from L2GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _from = _msgSender();
|
||||
if (router == _from) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
require(_data.length == 0, "call is not allowed");
|
||||
|
||||
// rate limit
|
||||
_addUsedAmount(_token, _amount);
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
IFiatToken(_token).burn(_amount);
|
||||
|
||||
@@ -119,8 +119,8 @@ contract L2USDCGatewayCCTP is CCTPGatewayBase, L2ERC20Gateway {
|
||||
require(_token == l2USDC, "only USDC is allowed");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
address _from = _msgSender();
|
||||
if (router == _from) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import {OwnableBase} from "../../libraries/common/OwnableBase.sol";
|
||||
// solhint-disable reason-string
|
||||
|
||||
/// @title L2TxFeeVault
|
||||
/// @notice The L2TxFeeVault contract contains the basic logic for the various different vault contracts
|
||||
/// @notice The L2TxFeeVault contract contains the logic for the vault contracts
|
||||
/// used to hold fee revenue generated by the L2 system.
|
||||
contract L2TxFeeVault is OwnableBase {
|
||||
/**********
|
||||
@@ -110,6 +110,9 @@ contract L2TxFeeVault is OwnableBase {
|
||||
"FeeVault: withdrawal amount must be greater than minimum withdrawal amount"
|
||||
);
|
||||
|
||||
uint256 _balance = address(this).balance;
|
||||
require(_value <= _balance, "FeeVault: insufficient balance to withdraw");
|
||||
|
||||
unchecked {
|
||||
totalProcessed += _value;
|
||||
}
|
||||
|
||||
@@ -27,17 +27,21 @@ contract WrappedEther is ERC20Permit {
|
||||
}
|
||||
|
||||
function deposit() public payable {
|
||||
_mint(msg.sender, msg.value);
|
||||
address _sender = _msgSender();
|
||||
|
||||
emit Deposit(msg.sender, msg.value);
|
||||
_mint(_sender, msg.value);
|
||||
|
||||
emit Deposit(_sender, msg.value);
|
||||
}
|
||||
|
||||
function withdraw(uint256 wad) external {
|
||||
_burn(msg.sender, wad);
|
||||
address _sender = _msgSender();
|
||||
|
||||
(bool success, ) = msg.sender.call{value: wad}("");
|
||||
_burn(_sender, wad);
|
||||
|
||||
(bool success, ) = _sender.call{value: wad}("");
|
||||
require(success, "withdraw ETH failed");
|
||||
|
||||
emit Withdrawal(msg.sender, wad);
|
||||
emit Withdrawal(_sender, wad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
pragma solidity =0.8.16;
|
||||
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
|
||||
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
|
||||
|
||||
import {OwnableBase} from "../libraries/common/OwnableBase.sol";
|
||||
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
|
||||
contract GasSwap is ERC2771Context, ReentrancyGuard, OwnableBase {
|
||||
contract GasSwap is ERC2771Context, Ownable, ReentrancyGuard {
|
||||
using SafeERC20 for IERC20;
|
||||
using SafeERC20 for IERC20Permit;
|
||||
|
||||
@@ -76,9 +76,7 @@ contract GasSwap is ERC2771Context, ReentrancyGuard, OwnableBase {
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
constructor(address trustedForwarder) ERC2771Context(trustedForwarder) {
|
||||
owner = msg.sender;
|
||||
}
|
||||
constructor(address trustedForwarder) ERC2771Context(trustedForwarder) {}
|
||||
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
@@ -146,10 +144,10 @@ contract GasSwap is ERC2771Context, ReentrancyGuard, OwnableBase {
|
||||
/// @param _amount The amount of token to withdraw.
|
||||
function withdraw(address _token, uint256 _amount) external onlyOwner {
|
||||
if (_token == address(0)) {
|
||||
(bool success, ) = msg.sender.call{value: _amount}("");
|
||||
(bool success, ) = _msgSender().call{value: _amount}("");
|
||||
require(success, "ETH transfer failed");
|
||||
} else {
|
||||
IERC20(_token).safeTransfer(msg.sender, _amount);
|
||||
IERC20(_token).safeTransfer(_msgSender(), _amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +172,16 @@ contract GasSwap is ERC2771Context, ReentrancyGuard, OwnableBase {
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc Context
|
||||
function _msgData() internal view virtual override(Context, ERC2771Context) returns (bytes calldata) {
|
||||
return ERC2771Context._msgData();
|
||||
}
|
||||
|
||||
/// @inheritdoc Context
|
||||
function _msgSender() internal view virtual override(Context, ERC2771Context) returns (address) {
|
||||
return ERC2771Context._msgSender();
|
||||
}
|
||||
|
||||
/// @dev Internal function to concat two bytes array.
|
||||
function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory) {
|
||||
return abi.encodePacked(a, b);
|
||||
|
||||
@@ -7,7 +7,6 @@ import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/
|
||||
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
|
||||
|
||||
import {ScrollConstants} from "./constants/ScrollConstants.sol";
|
||||
import {IETHRateLimiter} from "../rate-limiter/IETHRateLimiter.sol";
|
||||
import {IScrollMessenger} from "./IScrollMessenger.sol";
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
@@ -27,11 +26,6 @@ abstract contract ScrollMessengerBase is
|
||||
/// @param _newFeeVault The address of new fee vault contract.
|
||||
event UpdateFeeVault(address _oldFeeVault, address _newFeeVault);
|
||||
|
||||
/// @notice Emitted when owner updates rate limiter contract.
|
||||
/// @param _oldRateLimiter The address of old rate limiter contract.
|
||||
/// @param _newRateLimiter The address of new rate limiter contract.
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
@@ -45,8 +39,8 @@ abstract contract ScrollMessengerBase is
|
||||
/// @notice The address of fee vault, collecting cross domain messaging fee.
|
||||
address public feeVault;
|
||||
|
||||
/// @notice The address of ETH rate limiter contract.
|
||||
address public rateLimiter;
|
||||
/// @dev The storage slot used as ETH rate limiter contract, which is deprecated now.
|
||||
address private __rateLimiter;
|
||||
|
||||
/// @dev The storage slots for future usage.
|
||||
uint256[46] private __gap;
|
||||
@@ -98,16 +92,6 @@ abstract contract ScrollMessengerBase is
|
||||
emit UpdateFeeVault(_oldFeeVault, _newFeeVault);
|
||||
}
|
||||
|
||||
/// @notice Update rate limiter contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newRateLimiter The address of new rate limiter contract.
|
||||
function updateRateLimiter(address _newRateLimiter) external onlyOwner {
|
||||
address _oldRateLimiter = rateLimiter;
|
||||
|
||||
rateLimiter = _newRateLimiter;
|
||||
emit UpdateRateLimiter(_oldRateLimiter, _newRateLimiter);
|
||||
}
|
||||
|
||||
/// @notice Pause the contract
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _status The pause status to update.
|
||||
@@ -148,26 +132,11 @@ abstract contract ScrollMessengerBase is
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Internal function to increase ETH usage for the given `_sender`.
|
||||
/// @param _amount The amount of ETH used.
|
||||
function _addUsedAmount(uint256 _amount) internal {
|
||||
if (_amount == 0) return;
|
||||
|
||||
address _rateLimiter = rateLimiter;
|
||||
if (_rateLimiter != address(0)) {
|
||||
IETHRateLimiter(_rateLimiter).addUsedAmount(_amount);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Internal function to check whether the `_target` address is allowed to avoid attack.
|
||||
/// @param _target The address of target address to check.
|
||||
function _validateTargetAddress(address _target) internal view {
|
||||
// @note check more `_target` address to avoid attack in the future when we add more external contracts.
|
||||
|
||||
address _rateLimiter = rateLimiter;
|
||||
if (_rateLimiter != address(0)) {
|
||||
require(_target != _rateLimiter, "Forbid to call rate limiter");
|
||||
}
|
||||
require(_target != address(this), "Forbid to call self");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,6 @@ import {ITokenRateLimiter} from "../../rate-limiter/ITokenRateLimiter.sol";
|
||||
/// @title ScrollGatewayBase
|
||||
/// @notice The `ScrollGatewayBase` is a base contract for gateway contracts used in both in L1 and L2.
|
||||
abstract contract ScrollGatewayBase is ReentrancyGuardUpgradeable, OwnableUpgradeable, IScrollGateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when owner updates rate limiter contract.
|
||||
/// @param _oldRateLimiter The address of old rate limiter contract.
|
||||
/// @param _newRateLimiter The address of new rate limiter contract.
|
||||
event UpdateRateLimiter(address indexed _oldRateLimiter, address indexed _newRateLimiter);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
@@ -36,8 +27,8 @@ abstract contract ScrollGatewayBase is ReentrancyGuardUpgradeable, OwnableUpgrad
|
||||
/// @inheritdoc IScrollGateway
|
||||
address public override messenger;
|
||||
|
||||
/// @notice The address of token rate limiter contract.
|
||||
address public rateLimiter;
|
||||
/// @dev The storage slot used as token rate limiter contract, which is deprecated now.
|
||||
address private __rateLimiter;
|
||||
|
||||
/// @dev The storage slots for future usage.
|
||||
uint256[46] private __gap;
|
||||
@@ -48,14 +39,14 @@ abstract contract ScrollGatewayBase is ReentrancyGuardUpgradeable, OwnableUpgrad
|
||||
|
||||
modifier onlyCallByCounterpart() {
|
||||
address _messenger = messenger; // gas saving
|
||||
require(msg.sender == _messenger, "only messenger can call");
|
||||
require(_msgSender() == _messenger, "only messenger can call");
|
||||
require(counterpart == IScrollMessenger(_messenger).xDomainMessageSender(), "only call by counterpart");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyInDropContext() {
|
||||
address _messenger = messenger; // gas saving
|
||||
require(msg.sender == _messenger, "only messenger can call");
|
||||
require(_msgSender() == _messenger, "only messenger can call");
|
||||
require(
|
||||
ScrollConstants.DROP_XDOMAIN_MESSAGE_SENDER == IScrollMessenger(_messenger).xDomainMessageSender(),
|
||||
"only called in drop context"
|
||||
@@ -87,20 +78,6 @@ abstract contract ScrollGatewayBase is ReentrancyGuardUpgradeable, OwnableUpgrad
|
||||
}
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update rate limiter contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newRateLimiter The address of new rate limiter contract.
|
||||
function updateRateLimiter(address _newRateLimiter) external onlyOwner {
|
||||
address _oldRateLimiter = rateLimiter;
|
||||
|
||||
rateLimiter = _newRateLimiter;
|
||||
emit UpdateRateLimiter(_oldRateLimiter, _newRateLimiter);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
@@ -113,16 +90,4 @@ abstract contract ScrollGatewayBase is ReentrancyGuardUpgradeable, OwnableUpgrad
|
||||
IScrollGatewayCallback(_to).onScrollGatewayCallback(_data);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Internal function to increase token usage for the given `_sender`.
|
||||
/// @param _token The address of token.
|
||||
/// @param _amount The amount of token used.
|
||||
function _addUsedAmount(address _token, uint256 _amount) internal {
|
||||
if (_amount == 0) return;
|
||||
|
||||
address _rateLimiter = rateLimiter;
|
||||
if (_rateLimiter != address(0)) {
|
||||
ITokenRateLimiter(_rateLimiter).addUsedAmount(_token, _amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ contract ScrollStandardERC20 is ERC20PermitUpgradeable, IScrollERC20Upgradeable
|
||||
uint8 private decimals_;
|
||||
|
||||
modifier onlyGateway() {
|
||||
require(gateway == msg.sender, "Only Gateway");
|
||||
require(gateway == _msgSender(), "Only Gateway");
|
||||
_;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ contract ScrollStandardERC20 is ERC20PermitUpgradeable, IScrollERC20Upgradeable
|
||||
bytes memory data
|
||||
) private {
|
||||
IERC677Receiver receiver = IERC677Receiver(to);
|
||||
receiver.onTokenTransfer(msg.sender, value, data);
|
||||
receiver.onTokenTransfer(_msgSender(), value, data);
|
||||
}
|
||||
|
||||
function isContract(address _addr) private view returns (bool hasCode) {
|
||||
|
||||
@@ -52,7 +52,7 @@ contract ScrollOwner is AccessControlEnumerable {
|
||||
***************/
|
||||
|
||||
constructor() {
|
||||
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
||||
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
|
||||
}
|
||||
|
||||
/*************************
|
||||
|
||||
@@ -67,7 +67,7 @@ contract ETHRateLimiter is Ownable, IETHRateLimiter {
|
||||
|
||||
/// @inheritdoc IETHRateLimiter
|
||||
function addUsedAmount(uint256 _amount) external override {
|
||||
if (msg.sender != spender) {
|
||||
if (_msgSender() != spender) {
|
||||
revert CallerNotSpender();
|
||||
}
|
||||
if (_amount == 0) return;
|
||||
|
||||
@@ -54,7 +54,7 @@ contract TokenRateLimiter is AccessControlEnumerable, ITokenRateLimiter {
|
||||
revert PeriodIsZero();
|
||||
}
|
||||
|
||||
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
||||
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
|
||||
|
||||
periodDuration = _periodDuration;
|
||||
}
|
||||
|
||||
@@ -42,26 +42,6 @@ contract L1ScrollMessengerTest is L1GatewayTestBase {
|
||||
l1Messenger.relayMessageWithProof(address(this), address(messageQueue), 0, 0, new bytes(0), proof);
|
||||
}
|
||||
|
||||
function testForbidCallRateLimiterFromL2() external {
|
||||
l1Messenger.updateRateLimiter(address(1));
|
||||
bytes32 _xDomainCalldataHash = keccak256(
|
||||
abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(this),
|
||||
address(1),
|
||||
0,
|
||||
0,
|
||||
new bytes(0)
|
||||
)
|
||||
);
|
||||
prepareL2MessageRoot(_xDomainCalldataHash);
|
||||
IL1ScrollMessenger.L2MessageProof memory proof;
|
||||
proof.batchIndex = rollup.lastFinalizedBatchIndex();
|
||||
|
||||
hevm.expectRevert("Forbid to call rate limiter");
|
||||
l1Messenger.relayMessageWithProof(address(this), address(1), 0, 0, new bytes(0), proof);
|
||||
}
|
||||
|
||||
function testForbidCallSelfFromL2() external {
|
||||
bytes32 _xDomainCalldataHash = keccak256(
|
||||
abi.encodeWithSignature(
|
||||
|
||||
@@ -50,7 +50,7 @@ contract L2GasPriceOracleTest is DSTestPlus {
|
||||
|
||||
function testSetIntrinsicParamsAccess() external {
|
||||
hevm.startPrank(address(4));
|
||||
hevm.expectRevert("Not whitelisted sender");
|
||||
hevm.expectRevert("Ownable: caller is not the owner");
|
||||
oracle.setIntrinsicParams(1, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,15 +51,10 @@ contract L2ScrollMessengerTest is DSTestPlus {
|
||||
}
|
||||
|
||||
function testForbidCallFromL1() external {
|
||||
l2Messenger.updateRateLimiter(address(1));
|
||||
|
||||
hevm.startPrank(AddressAliasHelper.applyL1ToL2Alias(address(l1Messenger)));
|
||||
hevm.expectRevert("Forbid to call message queue");
|
||||
l2Messenger.relayMessage(address(this), address(l2MessageQueue), 0, 0, new bytes(0));
|
||||
|
||||
hevm.expectRevert("Forbid to call rate limiter");
|
||||
l2Messenger.relayMessage(address(this), address(1), 0, 0, new bytes(0));
|
||||
|
||||
hevm.expectRevert("Forbid to call self");
|
||||
l2Messenger.relayMessage(address(this), address(l2Messenger), 0, 0, new bytes(0));
|
||||
hevm.stopPrank();
|
||||
|
||||
@@ -33,7 +33,7 @@ contract L2TxFeeVaultTest is DSTestPlus {
|
||||
function testCantWithdrawMoreThanBalance(uint256 amount) public {
|
||||
hevm.assume(amount >= 10 ether);
|
||||
hevm.deal(address(vault), amount - 1);
|
||||
hevm.expectRevert(new bytes(0));
|
||||
hevm.expectRevert("FeeVault: insufficient balance to withdraw");
|
||||
vault.withdraw(amount);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -61,13 +62,48 @@ func (bp *BatchProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato
|
||||
|
||||
maxActiveAttempts := bp.cfg.ProverManager.ProversPerSession
|
||||
maxTotalAttempts := bp.cfg.ProverManager.SessionAttempts
|
||||
batchTask, err := bp.batchOrm.UpdateBatchAttemptsReturning(ctx, maxActiveAttempts, maxTotalAttempts)
|
||||
if err != nil {
|
||||
log.Error("failed to get unassigned batch proving tasks", "err", err)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
var batchTask *orm.Batch
|
||||
for i := 0; i < 5; i++ {
|
||||
var getTaskError error
|
||||
var tmpBatchTask *orm.Batch
|
||||
tmpBatchTask, getTaskError = bp.batchOrm.GetAssignedBatch(ctx, maxActiveAttempts, maxTotalAttempts)
|
||||
if getTaskError != nil {
|
||||
log.Error("failed to get assigned batch proving tasks", "height", getTaskParameter.ProverHeight, "err", getTaskError)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
}
|
||||
|
||||
// Why here need get again? In order to support a task can assign to multiple prover, need also assign `ProvingTaskAssigned`
|
||||
// batch to prover. But use `proving_status in (1, 2)` will not use the postgres index. So need split the sql.
|
||||
if tmpBatchTask == nil {
|
||||
tmpBatchTask, getTaskError = bp.batchOrm.GetUnassignedBatch(ctx, maxActiveAttempts, maxTotalAttempts)
|
||||
if getTaskError != nil {
|
||||
log.Error("failed to get unassigned batch proving tasks", "height", getTaskParameter.ProverHeight, "err", getTaskError)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
}
|
||||
}
|
||||
|
||||
if tmpBatchTask == nil {
|
||||
log.Debug("get empty batch", "height", getTaskParameter.ProverHeight)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rowsAffected, updateAttemptsErr := bp.batchOrm.UpdateBatchAttempts(ctx, tmpBatchTask.Index, tmpBatchTask.ActiveAttempts, tmpBatchTask.TotalAttempts)
|
||||
if updateAttemptsErr != nil {
|
||||
log.Error("failed to update batch attempts", "height", getTaskParameter.ProverHeight, "err", updateAttemptsErr)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
batchTask = tmpBatchTask
|
||||
break
|
||||
}
|
||||
|
||||
if batchTask == nil {
|
||||
log.Debug("get empty unassigned batch after retry 5 times", "height", getTaskParameter.ProverHeight)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -64,13 +65,48 @@ func (cp *ChunkProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato
|
||||
|
||||
maxActiveAttempts := cp.cfg.ProverManager.ProversPerSession
|
||||
maxTotalAttempts := cp.cfg.ProverManager.SessionAttempts
|
||||
chunkTask, err := cp.chunkOrm.UpdateChunkAttemptsReturning(ctx, getTaskParameter.ProverHeight, maxActiveAttempts, maxTotalAttempts)
|
||||
if err != nil {
|
||||
log.Error("failed to get unassigned chunk proving tasks", "height", getTaskParameter.ProverHeight, "err", err)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
var chunkTask *orm.Chunk
|
||||
for i := 0; i < 5; i++ {
|
||||
var getTaskError error
|
||||
var tmpChunkTask *orm.Chunk
|
||||
tmpChunkTask, getTaskError = cp.chunkOrm.GetAssignedChunk(ctx, getTaskParameter.ProverHeight, maxActiveAttempts, maxTotalAttempts)
|
||||
if getTaskError != nil {
|
||||
log.Error("failed to get assigned chunk proving tasks", "height", getTaskParameter.ProverHeight, "err", getTaskError)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
}
|
||||
|
||||
// Why here need get again? In order to support a task can assign to multiple prover, need also assign `ProvingTaskAssigned`
|
||||
// chunk to prover. But use `proving_status in (1, 2)` will not use the postgres index. So need split the sql.
|
||||
if tmpChunkTask == nil {
|
||||
tmpChunkTask, getTaskError = cp.chunkOrm.GetUnassignedChunk(ctx, getTaskParameter.ProverHeight, maxActiveAttempts, maxTotalAttempts)
|
||||
if getTaskError != nil {
|
||||
log.Error("failed to get unassigned chunk proving tasks", "height", getTaskParameter.ProverHeight, "err", getTaskError)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
}
|
||||
}
|
||||
|
||||
if tmpChunkTask == nil {
|
||||
log.Debug("get empty chunk", "height", getTaskParameter.ProverHeight)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rowsAffected, updateAttemptsErr := cp.chunkOrm.UpdateChunkAttempts(ctx, tmpChunkTask.Index, tmpChunkTask.ActiveAttempts, tmpChunkTask.TotalAttempts)
|
||||
if updateAttemptsErr != nil {
|
||||
log.Error("failed to update chunk attempts", "height", getTaskParameter.ProverHeight, "err", updateAttemptsErr)
|
||||
return nil, ErrCoordinatorInternalFailure
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
chunkTask = tmpChunkTask
|
||||
break
|
||||
}
|
||||
|
||||
if chunkTask == nil {
|
||||
log.Debug("get empty unassigned chunk after retry 5 times", "height", getTaskParameter.ProverHeight)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"scroll-tech/common/types"
|
||||
"scroll-tech/common/types/message"
|
||||
@@ -72,26 +71,46 @@ func (*Batch) TableName() string {
|
||||
return "batch"
|
||||
}
|
||||
|
||||
// GetUnassignedBatches retrieves unassigned batches based on the specified limit.
|
||||
// The returned batches are sorted in ascending order by their index.
|
||||
func (o *Batch) GetUnassignedBatches(ctx context.Context, limit int) ([]*Batch, error) {
|
||||
if limit < 0 {
|
||||
return nil, errors.New("limit must not be smaller than zero")
|
||||
}
|
||||
if limit == 0 {
|
||||
// GetUnassignedBatch retrieves unassigned batch based on the specified limit.
|
||||
// The returned batch are sorted in ascending order by their index.
|
||||
func (o *Batch) GetUnassignedBatch(ctx context.Context, maxActiveAttempts, maxTotalAttempts uint8) (*Batch, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Where("proving_status = ?", int(types.ProvingTaskUnassigned))
|
||||
db = db.Where("total_attempts < ?", maxTotalAttempts)
|
||||
db = db.Where("active_attempts < ?", maxActiveAttempts)
|
||||
db = db.Where("chunk_proofs_status = ?", int(types.ChunkProofsStatusReady))
|
||||
|
||||
var batch Batch
|
||||
err := db.First(&batch).Error
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Where("proving_status = ? AND chunk_proofs_status = ?", types.ProvingTaskUnassigned, types.ChunkProofsStatusReady)
|
||||
db = db.Order("index ASC")
|
||||
db = db.Limit(limit)
|
||||
|
||||
var batches []*Batch
|
||||
if err := db.Find(&batches).Error; err != nil {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Batch.GetUnassignedBatches error: %w", err)
|
||||
}
|
||||
return batches, nil
|
||||
return &batch, nil
|
||||
}
|
||||
|
||||
// GetAssignedBatch retrieves assigned batch based on the specified limit.
|
||||
// The returned batch are sorted in ascending order by their index.
|
||||
func (o *Batch) GetAssignedBatch(ctx context.Context, maxActiveAttempts, maxTotalAttempts uint8) (*Batch, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Where("proving_status = ?", int(types.ProvingTaskAssigned))
|
||||
db = db.Where("total_attempts < ?", maxTotalAttempts)
|
||||
db = db.Where("active_attempts < ?", maxActiveAttempts)
|
||||
db = db.Where("chunk_proofs_status = ?", int(types.ChunkProofsStatusReady))
|
||||
|
||||
var batch Batch
|
||||
err := db.First(&batch).Error
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Batch.GetAssignedBatches error: %w", err)
|
||||
}
|
||||
return &batch, nil
|
||||
}
|
||||
|
||||
// GetUnassignedAndChunksUnreadyBatches get the batches which is unassigned and chunks is not ready
|
||||
@@ -303,22 +322,13 @@ func (o *Batch) UpdateProofAndProvingStatusByHash(ctx context.Context, hash stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateBatchAttemptsReturning atomically increments the attempts count for the earliest available batch that meets the conditions.
|
||||
func (o *Batch) UpdateBatchAttemptsReturning(ctx context.Context, maxActiveAttempts, maxTotalAttempts uint8) (*Batch, error) {
|
||||
// UpdateBatchAttempts atomically increments the attempts count for the earliest available batch that meets the conditions.
|
||||
func (o *Batch) UpdateBatchAttempts(ctx context.Context, index uint64, curActiveAttempts, curTotalAttempts int16) (int64, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
|
||||
subQueryDB := db.Model(&Batch{}).Select("index")
|
||||
subQueryDB = subQueryDB.Clauses(clause.Locking{Strength: "UPDATE"})
|
||||
subQueryDB = subQueryDB.Where("proving_status not in (?)", []int{int(types.ProvingTaskVerified), int(types.ProvingTaskFailed)})
|
||||
subQueryDB = subQueryDB.Where("total_attempts < ?", maxTotalAttempts)
|
||||
subQueryDB = subQueryDB.Where("active_attempts < ?", maxActiveAttempts)
|
||||
subQueryDB = subQueryDB.Where("chunk_proofs_status = ?", int(types.ChunkProofsStatusReady))
|
||||
subQueryDB = subQueryDB.Order("index ASC")
|
||||
subQueryDB = subQueryDB.Limit(1)
|
||||
|
||||
var updatedBatch Batch
|
||||
db = db.Model(&updatedBatch).Clauses(clause.Returning{})
|
||||
db = db.Where("index = (?)", subQueryDB)
|
||||
db = db.Model(&Batch{})
|
||||
db = db.Where("index = ?", index)
|
||||
db = db.Where("active_attempts = ?", curActiveAttempts)
|
||||
db = db.Where("total_attempts = ?", curTotalAttempts)
|
||||
result := db.Updates(map[string]interface{}{
|
||||
"proving_status": types.ProvingTaskAssigned,
|
||||
"total_attempts": gorm.Expr("total_attempts + 1"),
|
||||
@@ -326,13 +336,9 @@ func (o *Batch) UpdateBatchAttemptsReturning(ctx context.Context, maxActiveAttem
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
return nil, fmt.Errorf("failed to select and update batch, max active attempts: %v, max total attempts: %v, err: %w",
|
||||
maxActiveAttempts, maxTotalAttempts, result.Error)
|
||||
return 0, fmt.Errorf("failed to update batch, err:%w", result.Error)
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &updatedBatch, nil
|
||||
return result.RowsAffected, nil
|
||||
}
|
||||
|
||||
// DecreaseActiveAttemptsByHash decrements the active_attempts of a batch given its hash.
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"scroll-tech/common/types"
|
||||
"scroll-tech/common/types/message"
|
||||
@@ -67,27 +66,48 @@ func (*Chunk) TableName() string {
|
||||
return "chunk"
|
||||
}
|
||||
|
||||
// GetUnassignedChunks retrieves unassigned chunks based on the specified limit.
|
||||
// GetUnassignedChunk retrieves unassigned chunk based on the specified limit.
|
||||
// The returned chunks are sorted in ascending order by their index.
|
||||
func (o *Chunk) GetUnassignedChunks(ctx context.Context, limit int) ([]*Chunk, error) {
|
||||
if limit < 0 {
|
||||
return nil, errors.New("limit must not be smaller than zero")
|
||||
}
|
||||
if limit == 0 {
|
||||
func (o *Chunk) GetUnassignedChunk(ctx context.Context, height int, maxActiveAttempts, maxTotalAttempts uint8) (*Chunk, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Model(&Chunk{})
|
||||
db = db.Where("proving_status = ?", int(types.ProvingTaskUnassigned))
|
||||
db = db.Where("total_attempts < ?", maxTotalAttempts)
|
||||
db = db.Where("active_attempts < ?", maxActiveAttempts)
|
||||
db = db.Where("end_block_number <= ?", height)
|
||||
|
||||
var chunk Chunk
|
||||
err := db.First(&chunk).Error
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Model(&Chunk{})
|
||||
db = db.Where("proving_status = ?", types.ProvingTaskUnassigned)
|
||||
db = db.Order("index ASC")
|
||||
db = db.Limit(limit)
|
||||
|
||||
var chunks []*Chunk
|
||||
if err := db.Find(&chunks).Error; err != nil {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Chunk.GetUnassignedChunks error: %w", err)
|
||||
}
|
||||
return chunks, nil
|
||||
return &chunk, nil
|
||||
}
|
||||
|
||||
// GetAssignedChunk retrieves assigned chunk based on the specified limit.
|
||||
// The returned chunks are sorted in ascending order by their index.
|
||||
func (o *Chunk) GetAssignedChunk(ctx context.Context, height int, maxActiveAttempts, maxTotalAttempts uint8) (*Chunk, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Model(&Chunk{})
|
||||
db = db.Where("proving_status = ?", int(types.ProvingTaskAssigned))
|
||||
db = db.Where("total_attempts < ?", maxTotalAttempts)
|
||||
db = db.Where("active_attempts < ?", maxActiveAttempts)
|
||||
db = db.Where("end_block_number <= ?", height)
|
||||
|
||||
var chunk Chunk
|
||||
err := db.First(&chunk).Error
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Chunk.GetAssignedChunks error: %w", err)
|
||||
}
|
||||
return &chunk, nil
|
||||
}
|
||||
|
||||
// GetChunksByBatchHash retrieves the chunks associated with a specific batch hash.
|
||||
@@ -158,19 +178,6 @@ func (o *Chunk) GetProvingStatusByHash(ctx context.Context, hash string) (types.
|
||||
return types.ProvingStatus(chunk.ProvingStatus), nil
|
||||
}
|
||||
|
||||
// GetAssignedChunks retrieves all chunks whose proving_status is either types.ProvingTaskAssigned.
|
||||
func (o *Chunk) GetAssignedChunks(ctx context.Context) ([]*Chunk, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Model(&Chunk{})
|
||||
db = db.Where("proving_status = ?", int(types.ProvingTaskAssigned))
|
||||
|
||||
var chunks []*Chunk
|
||||
if err := db.Find(&chunks).Error; err != nil {
|
||||
return nil, fmt.Errorf("Chunk.GetAssignedChunks error: %w", err)
|
||||
}
|
||||
return chunks, nil
|
||||
}
|
||||
|
||||
// CheckIfBatchChunkProofsAreReady checks if all proofs for all chunks of a given batchHash are collected.
|
||||
func (o *Chunk) CheckIfBatchChunkProofsAreReady(ctx context.Context, batchHash string) (bool, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
@@ -350,26 +357,13 @@ func (o *Chunk) UpdateBatchHashInRange(ctx context.Context, startIndex uint64, e
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateChunkAttemptsReturning atomically increments the attempts count for the earliest available chunk that meets the conditions.
|
||||
func (o *Chunk) UpdateChunkAttemptsReturning(ctx context.Context, height int, maxActiveAttempts, maxTotalAttempts uint8) (*Chunk, error) {
|
||||
if height <= 0 {
|
||||
return nil, errors.New("Chunk.UpdateChunkAttemptsReturning error: height must be larger than zero")
|
||||
}
|
||||
|
||||
// UpdateChunkAttempts atomically increments the attempts count for the earliest available chunk that meets the conditions.
|
||||
func (o *Chunk) UpdateChunkAttempts(ctx context.Context, index uint64, curActiveAttempts, curTotalAttempts int16) (int64, error) {
|
||||
db := o.db.WithContext(ctx)
|
||||
|
||||
subQueryDB := db.Model(&Chunk{}).Select("index")
|
||||
subQueryDB = subQueryDB.Clauses(clause.Locking{Strength: "UPDATE"})
|
||||
subQueryDB = subQueryDB.Where("proving_status not in (?)", []int{int(types.ProvingTaskVerified), int(types.ProvingTaskFailed)})
|
||||
subQueryDB = subQueryDB.Where("total_attempts < ?", maxTotalAttempts)
|
||||
subQueryDB = subQueryDB.Where("active_attempts < ?", maxActiveAttempts)
|
||||
subQueryDB = subQueryDB.Where("end_block_number <= ?", height)
|
||||
subQueryDB = subQueryDB.Order("index ASC")
|
||||
subQueryDB = subQueryDB.Limit(1)
|
||||
|
||||
var updatedChunk Chunk
|
||||
db = db.Model(&updatedChunk).Clauses(clause.Returning{})
|
||||
db = db.Where("index = (?)", subQueryDB)
|
||||
db = db.Model(&Chunk{})
|
||||
db = db.Where("index = ?", index)
|
||||
db = db.Where("active_attempts = ?", curActiveAttempts)
|
||||
db = db.Where("total_attempts = ?", curTotalAttempts)
|
||||
result := db.Updates(map[string]interface{}{
|
||||
"proving_status": types.ProvingTaskAssigned,
|
||||
"total_attempts": gorm.Expr("total_attempts + 1"),
|
||||
@@ -377,13 +371,9 @@ func (o *Chunk) UpdateChunkAttemptsReturning(ctx context.Context, height int, ma
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
return nil, fmt.Errorf("failed to select and update batch, max active attempts: %v, max total attempts: %v, err: %w",
|
||||
maxActiveAttempts, maxTotalAttempts, result.Error)
|
||||
return 0, fmt.Errorf("failed to update chunk, err:%w", result.Error)
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &updatedChunk, nil
|
||||
return result.RowsAffected, nil
|
||||
}
|
||||
|
||||
// DecreaseActiveAttemptsByHash decrements the active_attempts of a chunk given its hash.
|
||||
|
||||
@@ -63,7 +63,7 @@ func testResetDB(t *testing.T) {
|
||||
cur, err := Current(pgDB.DB)
|
||||
assert.NoError(t, err)
|
||||
// total number of tables.
|
||||
assert.Equal(t, 13, int(cur))
|
||||
assert.Equal(t, 14, int(cur))
|
||||
}
|
||||
|
||||
func testMigrate(t *testing.T) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
drop index if exists idx_total_attempts_active_attempts_end_block_number;
|
||||
drop index if exists idx_total_attempts_active_attempts_chunk_proofs_status;
|
||||
|
||||
create index if not exists idx_chunk_proving_status_index on chunk (proving_status, index) where deleted_at IS NULL;
|
||||
create index if not exists idx_batch_proving_status_index on batch (proving_status, chunk_proofs_status, index) where deleted_at IS NULL;
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
create index if not exists idx_total_attempts_active_attempts_end_block_number
|
||||
on chunk (total_attempts, active_attempts, end_block_number)
|
||||
where deleted_at IS NULL;
|
||||
|
||||
create index if not exists idx_total_attempts_active_attempts_chunk_proofs_status
|
||||
on batch (total_attempts, active_attempts, chunk_proofs_status)
|
||||
where deleted_at IS NULL;
|
||||
|
||||
|
||||
drop index if exists idx_chunk_proving_status_index;
|
||||
drop index if exists idx_batch_proving_status_index;
|
||||
|
||||
-- +goose StatementEnd
|
||||
@@ -307,12 +307,12 @@ func (r *Layer2Relayer) ProcessGasPriceOracle() {
|
||||
// ProcessPendingBatches processes the pending batches by sending commitBatch transactions to layer 1.
|
||||
func (r *Layer2Relayer) ProcessPendingBatches() {
|
||||
// get pending batches from database in ascending order by their index.
|
||||
pendingBatches, err := r.batchOrm.GetPendingBatches(r.ctx, 5)
|
||||
batches, err := r.batchOrm.GetFailedAndPendingBatches(r.ctx, 5)
|
||||
if err != nil {
|
||||
log.Error("Failed to fetch pending L2 batches", "err", err)
|
||||
return
|
||||
}
|
||||
for _, batch := range pendingBatches {
|
||||
for _, batch := range batches {
|
||||
r.metrics.rollupL2RelayerProcessPendingBatchTotal.Inc()
|
||||
// get current header and parent header.
|
||||
currentBatchHeader, err := types.DecodeBatchHeader(batch.BatchHeader)
|
||||
@@ -327,6 +327,12 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
|
||||
log.Error("Failed to get parent batch header", "index", batch.Index-1, "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if types.RollupStatus(parentBatch.RollupStatus) == types.RollupCommitFailed {
|
||||
log.Error("Previous batch commit failed, halting further committing",
|
||||
"index", parentBatch.Index, "tx hash", parentBatch.CommitTxHash)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// get the chunks for the batch
|
||||
@@ -371,6 +377,11 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
|
||||
// send transaction
|
||||
txID := batch.Hash + "-commit"
|
||||
fallbackGasLimit := uint64(float64(batch.TotalL1CommitGas) * r.cfg.L1CommitGasLimitMultiplier)
|
||||
if types.RollupStatus(batch.RollupStatus) == types.RollupCommitFailed {
|
||||
// use eth_estimateGas if this batch has been committed failed.
|
||||
fallbackGasLimit = 0
|
||||
log.Warn("Batch commit previously failed, using eth_estimateGas for the re-submission", "hash", batch.Hash)
|
||||
}
|
||||
txHash, err := r.commitSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), calldata, fallbackGasLimit)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
@@ -582,7 +593,8 @@ func (r *Layer2Relayer) handleConfirmation(confirmation *sender.Confirmation) {
|
||||
status = types.RollupCommitted
|
||||
} else {
|
||||
status = types.RollupCommitFailed
|
||||
log.Warn("transaction confirmed but failed in layer1", "confirmation", confirmation)
|
||||
r.metrics.rollupL2BatchesCommittedConfirmedFailedTotal.Inc()
|
||||
log.Warn("commitBatch transaction confirmed but failed in layer1", "confirmation", confirmation)
|
||||
}
|
||||
// @todo handle db error
|
||||
err := r.batchOrm.UpdateCommitTxHashAndRollupStatus(r.ctx, batchHash.(string), confirmation.TxHash.String(), status)
|
||||
@@ -603,7 +615,8 @@ func (r *Layer2Relayer) handleConfirmation(confirmation *sender.Confirmation) {
|
||||
status = types.RollupFinalized
|
||||
} else {
|
||||
status = types.RollupFinalizeFailed
|
||||
log.Warn("transaction confirmed but failed in layer1", "confirmation", confirmation)
|
||||
r.metrics.rollupL2BatchesFinalizedConfirmedFailedTotal.Inc()
|
||||
log.Warn("finalizeBatchWithProof transaction confirmed but failed in layer1", "confirmation", confirmation)
|
||||
}
|
||||
|
||||
// @todo handle db error
|
||||
|
||||
@@ -16,7 +16,9 @@ type l2RelayerMetrics struct {
|
||||
rollupL2RelayerProcessCommittedBatchesFinalizedTotal prometheus.Counter
|
||||
rollupL2RelayerProcessCommittedBatchesFinalizedSuccessTotal prometheus.Counter
|
||||
rollupL2BatchesCommittedConfirmedTotal prometheus.Counter
|
||||
rollupL2BatchesCommittedConfirmedFailedTotal prometheus.Counter
|
||||
rollupL2BatchesFinalizedConfirmedTotal prometheus.Counter
|
||||
rollupL2BatchesFinalizedConfirmedFailedTotal prometheus.Counter
|
||||
rollupL2BatchesGasOraclerConfirmedTotal prometheus.Counter
|
||||
rollupL2ChainMonitorLatestFailedCall prometheus.Counter
|
||||
rollupL2ChainMonitorLatestFailedBatchStatus prometheus.Counter
|
||||
@@ -62,10 +64,18 @@ func initL2RelayerMetrics(reg prometheus.Registerer) *l2RelayerMetrics {
|
||||
Name: "rollup_layer2_process_committed_batches_confirmed_total",
|
||||
Help: "The total number of layer2 process committed batches confirmed total",
|
||||
}),
|
||||
rollupL2BatchesCommittedConfirmedFailedTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_layer2_process_committed_batches_confirmed_failed_total",
|
||||
Help: "The total number of layer2 process committed batches confirmed failed total",
|
||||
}),
|
||||
rollupL2BatchesFinalizedConfirmedTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_layer2_process_finalized_batches_confirmed_total",
|
||||
Help: "The total number of layer2 process finalized batches confirmed total",
|
||||
}),
|
||||
rollupL2BatchesFinalizedConfirmedFailedTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_layer2_process_finalized_batches_confirmed_failed_total",
|
||||
Help: "The total number of layer2 process finalized batches confirmed failed total",
|
||||
}),
|
||||
rollupL2BatchesGasOraclerConfirmedTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_layer2_process_gras_oracler_confirmed_total",
|
||||
Help: "The total number of layer2 process finalized batches confirmed total",
|
||||
|
||||
@@ -177,6 +177,7 @@ func (p *BatchProposer) proposeBatchChunks() ([]*orm.Chunk, *types.BatchMeta, er
|
||||
}
|
||||
|
||||
// Add extra gas costs
|
||||
totalL1CommitGas += 100000 // constant to account for ops like _getAdmin, _implementation, _requireNotPaused, etc
|
||||
totalL1CommitGas += 4 * 2100 // 4 one-time cold sload for commitBatch
|
||||
totalL1CommitGas += 20000 // 1 time sstore
|
||||
totalL1CommitGas += 21000 // base fee for tx
|
||||
@@ -206,9 +207,11 @@ func (p *BatchProposer) proposeBatchChunks() ([]*orm.Chunk, *types.BatchMeta, er
|
||||
// adjust batch header hash gas cost, batch header size: 89 + 32 * ceil(l1MessagePopped / 256)
|
||||
totalL1CommitGas -= types.GetKeccak256Gas(89 + 32*(totalL1MessagePopped+255)/256)
|
||||
totalL1CommitGas -= types.CalldataNonZeroByteGas * (32 * (totalL1MessagePopped + 255) / 256)
|
||||
totalL1CommitGas -= types.GetMemoryExpansionCost(uint64(totalL1CommitCalldataSize))
|
||||
totalL1MessagePopped += uint64(chunk.TotalL1MessagesPoppedInChunk)
|
||||
totalL1CommitGas += types.CalldataNonZeroByteGas * (32 * (totalL1MessagePopped + 255) / 256)
|
||||
totalL1CommitGas += types.GetKeccak256Gas(89 + 32*(totalL1MessagePopped+255)/256)
|
||||
totalL1CommitGas += types.GetMemoryExpansionCost(uint64(totalL1CommitCalldataSize))
|
||||
totalOverEstimateL1CommitGas := uint64(p.gasCostIncreaseMultiplier * float64(totalL1CommitGas))
|
||||
if totalL1CommitCalldataSize > p.maxL1CommitCalldataSizePerBatch ||
|
||||
totalOverEstimateL1CommitGas > p.maxL1CommitGasPerBatch {
|
||||
|
||||
@@ -68,7 +68,7 @@ func testBatchProposerLimits(t *testing.T) {
|
||||
{
|
||||
name: "MaxL1CommitGasPerBatchIsFirstChunk",
|
||||
maxChunkNum: 10,
|
||||
maxL1CommitGas: 100000,
|
||||
maxL1CommitGas: 200000,
|
||||
maxL1CommitCalldataSize: 1000000,
|
||||
batchTimeoutSec: 1000000000000,
|
||||
expectedBatchesLen: 1,
|
||||
@@ -109,9 +109,9 @@ func testBatchProposerLimits(t *testing.T) {
|
||||
chunkOrm := orm.NewChunk(db)
|
||||
chunks, err := chunkOrm.GetChunksInRange(context.Background(), 0, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint64(6006), chunks[0].TotalL1CommitGas)
|
||||
assert.Equal(t, uint64(6042), chunks[0].TotalL1CommitGas)
|
||||
assert.Equal(t, uint32(298), chunks[0].TotalL1CommitCalldataSize)
|
||||
assert.Equal(t, uint64(93982), chunks[1].TotalL1CommitGas)
|
||||
assert.Equal(t, uint64(94586), chunks[1].TotalL1CommitGas)
|
||||
assert.Equal(t, uint32(5735), chunks[1].TotalL1CommitCalldataSize)
|
||||
|
||||
bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{
|
||||
@@ -168,9 +168,9 @@ func testBatchCommitGasAndCalldataSizeEstimation(t *testing.T) {
|
||||
chunkOrm := orm.NewChunk(db)
|
||||
chunks, err := chunkOrm.GetChunksInRange(context.Background(), 0, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint64(6006), chunks[0].TotalL1CommitGas)
|
||||
assert.Equal(t, uint64(6042), chunks[0].TotalL1CommitGas)
|
||||
assert.Equal(t, uint32(298), chunks[0].TotalL1CommitCalldataSize)
|
||||
assert.Equal(t, uint64(93982), chunks[1].TotalL1CommitGas)
|
||||
assert.Equal(t, uint64(94586), chunks[1].TotalL1CommitGas)
|
||||
assert.Equal(t, uint32(5735), chunks[1].TotalL1CommitCalldataSize)
|
||||
|
||||
bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{
|
||||
@@ -199,6 +199,6 @@ func testBatchCommitGasAndCalldataSizeEstimation(t *testing.T) {
|
||||
assert.Equal(t, types.ProvingTaskUnassigned, types.ProvingStatus(chunk.ProvingStatus))
|
||||
}
|
||||
|
||||
assert.Equal(t, uint64(153916), batches[0].TotalL1CommitGas)
|
||||
assert.Equal(t, uint64(254562), batches[0].TotalL1CommitGas)
|
||||
assert.Equal(t, uint32(6033), batches[0].TotalL1CommitCalldataSize)
|
||||
}
|
||||
|
||||
@@ -180,6 +180,9 @@ func (w *L2WatcherClient) getAndStoreBlockTraces(ctx context.Context, from, to u
|
||||
}
|
||||
|
||||
if len(blocks) > 0 {
|
||||
for _, block := range blocks {
|
||||
w.metrics.rollupL2BlockL1CommitCalldataSize.Set(float64(block.EstimateL1CommitCalldataSize()))
|
||||
}
|
||||
if err := w.l2BlockOrm.InsertL2Blocks(w.ctx, blocks); err != nil {
|
||||
return fmt.Errorf("failed to batch insert BlockTraces: %v", err)
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ import (
|
||||
)
|
||||
|
||||
type l2WatcherMetrics struct {
|
||||
fetchRunningMissingBlocksTotal prometheus.Counter
|
||||
fetchRunningMissingBlocksHeight prometheus.Gauge
|
||||
fetchContractEventTotal prometheus.Counter
|
||||
fetchContractEventHeight prometheus.Gauge
|
||||
rollupL2MsgsRelayedEventsTotal prometheus.Counter
|
||||
rollupL2BlocksFetchedGap prometheus.Gauge
|
||||
fetchRunningMissingBlocksTotal prometheus.Counter
|
||||
fetchRunningMissingBlocksHeight prometheus.Gauge
|
||||
fetchContractEventTotal prometheus.Counter
|
||||
fetchContractEventHeight prometheus.Gauge
|
||||
rollupL2MsgsRelayedEventsTotal prometheus.Counter
|
||||
rollupL2BlocksFetchedGap prometheus.Gauge
|
||||
rollupL2BlockL1CommitCalldataSize prometheus.Gauge
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -48,6 +49,10 @@ func initL2WatcherMetrics(reg prometheus.Registerer) *l2WatcherMetrics {
|
||||
Name: "rollup_l2_watcher_blocks_fetched_gap",
|
||||
Help: "The gap of l2 fetch",
|
||||
}),
|
||||
rollupL2BlockL1CommitCalldataSize: promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "rollup_l2_block_l1_commit_calldata_size",
|
||||
Help: "The l1 commitBatch calldata size of the l2 block",
|
||||
}),
|
||||
}
|
||||
})
|
||||
return l2WatcherMetric
|
||||
|
||||
@@ -192,22 +192,22 @@ func (o *Batch) GetRollupStatusByHashList(ctx context.Context, hashes []string)
|
||||
return statuses, nil
|
||||
}
|
||||
|
||||
// GetPendingBatches retrieves pending batches up to the specified limit.
|
||||
// GetFailedAndPendingBatches retrieves batches with failed or pending status up to the specified limit.
|
||||
// The returned batches are sorted in ascending order by their index.
|
||||
func (o *Batch) GetPendingBatches(ctx context.Context, limit int) ([]*Batch, error) {
|
||||
func (o *Batch) GetFailedAndPendingBatches(ctx context.Context, limit int) ([]*Batch, error) {
|
||||
if limit <= 0 {
|
||||
return nil, errors.New("limit must be greater than zero")
|
||||
}
|
||||
|
||||
db := o.db.WithContext(ctx)
|
||||
db = db.Model(&Batch{})
|
||||
db = db.Where("rollup_status = ?", types.RollupPending)
|
||||
db = db.Where("rollup_status = ? OR rollup_status = ?", types.RollupCommitFailed, types.RollupPending)
|
||||
db = db.Order("index ASC")
|
||||
db = db.Limit(limit)
|
||||
|
||||
var batches []*Batch
|
||||
if err := db.Find(&batches).Error; err != nil {
|
||||
return nil, fmt.Errorf("Batch.GetPendingBatches error: %w", err)
|
||||
return nil, fmt.Errorf("Batch.GetFailedAndPendingBatches error: %w", err)
|
||||
}
|
||||
return batches, nil
|
||||
}
|
||||
|
||||
@@ -258,14 +258,17 @@ func TestBatchOrm(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint64(2), count)
|
||||
|
||||
pendingBatches, err := batchOrm.GetPendingBatches(context.Background(), 100)
|
||||
err = batchOrm.UpdateRollupStatus(context.Background(), batchHash1, types.RollupCommitFailed)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pendingBatches, err := batchOrm.GetFailedAndPendingBatches(context.Background(), 100)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(pendingBatches))
|
||||
|
||||
rollupStatus, err := batchOrm.GetRollupStatusByHashList(context.Background(), []string{batchHash1, batchHash2})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(rollupStatus))
|
||||
assert.Equal(t, types.RollupPending, rollupStatus[0])
|
||||
assert.Equal(t, types.RollupCommitFailed, rollupStatus[0])
|
||||
assert.Equal(t, types.RollupPending, rollupStatus[1])
|
||||
|
||||
err = batchOrm.UpdateProvingStatus(context.Background(), batchHash2, types.ProvingTaskVerified)
|
||||
|
||||
Reference in New Issue
Block a user