mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-11 23:18:07 -05:00
Compare commits
83 Commits
v4.2.23
...
feat/test-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4eba64c3fb | ||
|
|
9a60a6bf9c | ||
|
|
bf2692b7cb | ||
|
|
566fb23b9d | ||
|
|
2e627f781a | ||
|
|
bc5ec89b70 | ||
|
|
99454e5b88 | ||
|
|
144c7ed024 | ||
|
|
4aa5d5cd37 | ||
|
|
486c7ee0f9 | ||
|
|
0243c86b3c | ||
|
|
e6db4ac3a8 | ||
|
|
50040a164e | ||
|
|
8494ab1899 | ||
|
|
2102e16fdb | ||
|
|
c2ab4bf16d | ||
|
|
1059f9d3f8 | ||
|
|
9e8c3432c3 | ||
|
|
ff380141a8 | ||
|
|
2216ad4271 | ||
|
|
25d5fabac9 | ||
|
|
d494f4419c | ||
|
|
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 | ||
|
|
dcd85b2f56 | ||
|
|
afb6476823 | ||
|
|
d991d6b99d | ||
|
|
f0920362c5 | ||
|
|
5eed174b9e | ||
|
|
a79992e772 | ||
|
|
2a54c8aae6 | ||
|
|
3bd0f2fa38 | ||
|
|
ae95e61902 | ||
|
|
8bae647921 | ||
|
|
1f4df55d12 | ||
|
|
f21d4adbfd | ||
|
|
145edfccb9 | ||
|
|
6f26114f23 | ||
|
|
56150da353 | ||
|
|
fc53572334 | ||
|
|
0730e91292 | ||
|
|
4d3ff66446 | ||
|
|
ae1cb30ed1 | ||
|
|
ad14836796 | ||
|
|
9a5517472f | ||
|
|
1c7490a88e | ||
|
|
7559dc42b4 | ||
|
|
49b72bd4e4 | ||
|
|
8c41b0b86b | ||
|
|
cd456ee3db | ||
|
|
2b6a3c9874 | ||
|
|
d39db01c5b |
2
.github/workflows/bump_version.yml
vendored
2
.github/workflows/bump_version.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Bump Version
|
||||
name: Bump version
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
14
.github/workflows/docker.yml
vendored
14
.github/workflows/docker.yml
vendored
@@ -111,7 +111,7 @@ jobs:
|
||||
tags: scrolltech/bridgehistoryapi-server:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
coordinator:
|
||||
coordinator-api:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -127,12 +127,12 @@ jobs:
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/coordinator.Dockerfile
|
||||
file: ./build/dockerfiles/coordinator-api.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/coordinator:${{github.ref_name}}
|
||||
tags: scrolltech/coordinator-api:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
prover-stats-api:
|
||||
coordinator-cron:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -144,12 +144,12 @@ jobs:
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push prover-stats-api docker
|
||||
- name: Build and push coordinator docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/prover-stats-api.Dockerfile
|
||||
file: ./build/dockerfiles/coordinator-cron.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/prover-stats-api:${{github.ref_name}}
|
||||
tags: scrolltech/coordinator-cron:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
|
||||
80
.github/workflows/prover_stats_api.yml
vendored
80
.github/workflows/prover_stats_api.yml
vendored
@@ -1,80 +0,0 @@
|
||||
name: ProverStatsAPI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'prover-stats-api/**'
|
||||
- '.github/workflows/prover_stats_api.yml'
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
paths:
|
||||
- 'prover-stats-api/**'
|
||||
- '.github/workflows/prover_stats_api.yml'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: 'prover-stats-api'
|
||||
|
||||
jobs:
|
||||
check:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Lint
|
||||
run: |
|
||||
rm -rf $HOME/.cache/golangci-lint
|
||||
make lint
|
||||
test:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Test
|
||||
run: |
|
||||
make test
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
with:
|
||||
flags: prover-stats-api
|
||||
goimports-lint:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install goimports
|
||||
run: go install golang.org/x/tools/cmd/goimports
|
||||
- run: goimports -local scroll-tech/prover-stats-api/ -w .
|
||||
- run: go mod tidy
|
||||
# If there are any diffs from goimports or go mod tidy, fail.
|
||||
- name: Verify no changes from goimports and go mod tidy
|
||||
run: |
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
exit 1
|
||||
fi
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,9 +1,6 @@
|
||||
[submodule "l2geth"]
|
||||
path = l2geth
|
||||
url = git@github.com:scroll-tech/go-ethereum.git
|
||||
[submodule "rpc-gateway"]
|
||||
path = rpc-gateway
|
||||
url = git@github.com:scroll-tech/rpc-gateway.git
|
||||
[submodule "contracts/lib/ds-test"]
|
||||
path = contracts/lib/ds-test
|
||||
url = https://github.com/dapphub/ds-test
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Scroll
|
||||
Copyright (c) 2022-2023 Scroll
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
├── <a href="./database">database</a>: Database client and schema definition
|
||||
├── <a href="./src">l2geth</a>: Scroll execution node
|
||||
├── <a href="./prover">prover</a>: Prover client that runs proof generation for zkEVM circuit and aggregation circuit
|
||||
├── <a href="./prover-stats-api">prover-stats-api</a>: Collect and show prover statistics
|
||||
├── <a href="./rollup">rollup</a>: Rollup-related services
|
||||
├── <a href="./rpc-gateway">rpc-gateway</a>: RPC gateway external repo
|
||||
└── <a href="./tests">tests</a>: Integration tests
|
||||
|
||||
@@ -1 +1,82 @@
|
||||
# bridge-history-api
|
||||
|
||||
This directory contains the `bridge-history-api` service that provides REST APIs to query txs interact with Scroll official bridge contracts
|
||||
|
||||
## Instructions
|
||||
The bridge-history-api contains three distinct components
|
||||
|
||||
### bridgehistoryapi-db-cli
|
||||
|
||||
Provide init, show version, rollback, check status services of DB
|
||||
```
|
||||
cd ./bridge-history-api
|
||||
make bridgehistoryapi-db-cli
|
||||
./build/bin/bridgehistoryapi-db-cli [command]
|
||||
```
|
||||
|
||||
### bridgehistoryapi-cross-msg-fetcher
|
||||
|
||||
Fetch the transactions from both l1 and l2
|
||||
```
|
||||
cd ./bridge-history-api
|
||||
make bridgehistoryapi-cross-msg-fetcher
|
||||
./build/bin/bridgehistoryapi-cross-msg-fetcher
|
||||
```
|
||||
|
||||
### bridgehistoryapi-server
|
||||
|
||||
provides REST APIs. Please refer to the API details below.
|
||||
```
|
||||
cd ./bridge-history-api
|
||||
make bridgehistoryapi-server
|
||||
./build/bin/bridgehistoryapi-server
|
||||
```
|
||||
|
||||
## APIs provided by bridgehistoryapi-server
|
||||
|
||||
assume `bridgehistoryapi-server` listening on `https://localhost:8080`
|
||||
can change this port thru modify `config.json`
|
||||
|
||||
1. `/txs`
|
||||
```
|
||||
// @Summary get all txs under given address
|
||||
// @Accept plain
|
||||
// @Produce plain
|
||||
// @Param address query string true "wallet address"
|
||||
// @Param page_size query int true "page size"
|
||||
// @Param page query int true "page"
|
||||
// @Success 200
|
||||
// @Router /api/txs [get]
|
||||
```
|
||||
|
||||
2. `/txsbyhashes`
|
||||
```
|
||||
// @Summary get txs by given tx hashes
|
||||
// @Accept plain
|
||||
// @Produce plain
|
||||
// @Param hashes query string array true "array of hashes list"
|
||||
// @Success 200
|
||||
// @Router /api/txsbyhashes [post]
|
||||
```
|
||||
|
||||
3. `/claimable`
|
||||
```
|
||||
// @Summary get all claimable txs under given address
|
||||
// @Accept plain
|
||||
// @Produce plain
|
||||
// @Param address query string true "wallet address"
|
||||
// @Param page_size query int true "page size"
|
||||
// @Param page query int true "page"
|
||||
// @Success 200
|
||||
// @Router /api/claimable [get]
|
||||
```
|
||||
|
||||
4. `/withdraw_root`
|
||||
```
|
||||
// @Summary get withdraw_root of given batch index
|
||||
// @Accept plain
|
||||
// @Produce plain
|
||||
// @Param batch_index query string true "batch_index"
|
||||
// @Success 200
|
||||
// @Router /api/withdraw_root [get]
|
||||
```
|
||||
@@ -45,7 +45,7 @@ var (
|
||||
L2BatchWithdrawERC721Sig common.Hash
|
||||
L2BatchWithdrawERC1155Sig common.Hash
|
||||
|
||||
// scroll mono repo
|
||||
// scroll monorepo
|
||||
|
||||
// ScrollChainABI holds information about ScrollChain's context and available invokable methods.
|
||||
ScrollChainABI *abi.ABI
|
||||
@@ -323,7 +323,7 @@ type L1RelayedMessageEvent struct {
|
||||
MessageHash common.Hash
|
||||
}
|
||||
|
||||
// L2AppendMessageEvent represents a AppendMessage event raised by the L2MessageQueue contract.
|
||||
// L2AppendMessageEvent represents an AppendMessage event raised by the L2MessageQueue contract.
|
||||
type L2AppendMessageEvent struct {
|
||||
Index *big.Int
|
||||
MessageHash common.Hash
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -82,6 +82,18 @@ func action(ctx *cli.Context) error {
|
||||
common.HexToAddress(cfg.L1.WETHGatewayAddr),
|
||||
}
|
||||
|
||||
if cfg.L1.USDCGatewayAddr != "" {
|
||||
l1AddressList = append(l1AddressList, common.HexToAddress(cfg.L1.USDCGatewayAddr))
|
||||
}
|
||||
|
||||
if cfg.L1.LIDOGatewayAddr != "" {
|
||||
l1AddressList = append(l1AddressList, common.HexToAddress(cfg.L1.LIDOGatewayAddr))
|
||||
}
|
||||
|
||||
if cfg.L2.DAIGatewayAddr != "" {
|
||||
l1AddressList = append(l1AddressList, common.HexToAddress(cfg.L1.DAIGatewayAddr))
|
||||
}
|
||||
|
||||
l2AddressList := []common.Address{
|
||||
common.HexToAddress(cfg.L2.CustomERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.L2.ERC721GatewayAddr),
|
||||
@@ -92,6 +104,18 @@ func action(ctx *cli.Context) error {
|
||||
common.HexToAddress(cfg.L2.WETHGatewayAddr),
|
||||
}
|
||||
|
||||
if cfg.L2.USDCGatewayAddr != "" {
|
||||
l2AddressList = append(l2AddressList, common.HexToAddress(cfg.L2.USDCGatewayAddr))
|
||||
}
|
||||
|
||||
if cfg.L2.LIDOGatewayAddr != "" {
|
||||
l2AddressList = append(l2AddressList, common.HexToAddress(cfg.L2.LIDOGatewayAddr))
|
||||
}
|
||||
|
||||
if cfg.L2.DAIGatewayAddr != "" {
|
||||
l2AddressList = append(l2AddressList, common.HexToAddress(cfg.L2.DAIGatewayAddr))
|
||||
}
|
||||
|
||||
l1crossMsgFetcher, err := crossmsg.NewMsgFetcher(subCtx, cfg.L1, db, l1client, l1worker, l1AddressList, crossmsg.L1ReorgHandling)
|
||||
if err != nil {
|
||||
log.Crit("failed to create l1 cross message fetcher", "error", err)
|
||||
|
||||
@@ -1,33 +1,39 @@
|
||||
{
|
||||
"batchInfoFetcher": {
|
||||
"batchIndexStartBlock": 9091265,
|
||||
"ScrollChainAddr": "0xcD00DB804C819175B381b2B44Aa16A391c8a01D6"
|
||||
"ScrollChainAddr": "0x1799c3Df650caB9DFBb228C971016707D8f8721D"
|
||||
},
|
||||
"l1": {
|
||||
"confirmation": 64,
|
||||
"endpoint": "https://rpc.ankr.com/eth_goerli",
|
||||
"startHeight": 9090194 ,
|
||||
"endpoint": "https://rpc.ankr.com/eth",
|
||||
"startHeight": 18310747,
|
||||
"blockTime": 10,
|
||||
"MessengerAddr": "0x326517Eb8eB1Ce5eaB5b513C2e9A24839b402d90",
|
||||
"ETHGatewayAddr": "0x8305cB7B8448677736095965B63d7431017328fe",
|
||||
"WETHGatewayAddr": "0xe3bA3c60d99a2d9a5f817734bC85353470b23931",
|
||||
"StandardERC20Gateway": "0x16c1079B27eD9c363B7D08aC5Ae937A398972A5C",
|
||||
"CustomERC20GatewayAddr": "0x61f08caD3d6F77801167d3bA8669433701586643",
|
||||
"ERC721GatewayAddr": "0x4A73D25A4C99CB912acaf6C5B5e554f2982201c5",
|
||||
"ERC1155GatewayAddr": "0xa3F5DD3033698c2832C53f3C3Fe6E062F58cD808"
|
||||
"MessengerAddr": "0x7318152B19c3c97c886D5ee6C2525E62ce8e2abA",
|
||||
"ETHGatewayAddr": "0xd165b42d857eae2915625819464a2a1f91E5d0A5",
|
||||
"WETHGatewayAddr": "0xb0255e4C1a919619D1CafBA51021d638c4F71b89",
|
||||
"StandardERC20Gateway": "0x00fEc01A9b975bA37466B4E9006dF2C71BFE0e48",
|
||||
"CustomERC20GatewayAddr": "0xD8874B0E6C3CC43C00B69D60c21Ef452d1159bDe",
|
||||
"ERC721GatewayAddr": "0x131B46649F6882d686a766cb8b68c4cB0ACdeb24",
|
||||
"ERC1155GatewayAddr": "0xCeE721789FAA05c7F4463efB664520656aB7C7d5",
|
||||
"USDCGatewayAddr": "0x37ba659D6CC380D12Fb96567CC52FC8e1DF4E334",
|
||||
"LIDOGatewayAddr": "0x892dDB2899325aBBA1fD00FDA8249B40Cbbc33F9",
|
||||
"DAIGatewayAddr": "0xD8dD7787f89c7E6243AD32E0d0cCf460243C8130"
|
||||
},
|
||||
"l2": {
|
||||
"confirmation": 1,
|
||||
"endpoint": "http://staging-l2geth-rpc0.scroll.tech:8545",
|
||||
"endpoint": "http://mainnet-l2geth-internal-1.mainnet.scroll.tech:8545",
|
||||
"blockTime": 3,
|
||||
"startHeight": 0,
|
||||
"CustomERC20GatewayAddr": "0x905db21f836749fEeD12de781afc4A5Ab4Dd0d51",
|
||||
"ERC721GatewayAddr": "0xC53D835514780664BCd7eCfcE7c2E5d9554dc41B",
|
||||
"StandardERC20Gateway": "0x90271634BCB020e06ea4840C3f7aa61b8F860651",
|
||||
"MessengerAddr": "0xE8b0956Ac75c65Aa1669e83888DA13afF2E108f4",
|
||||
"ETHGatewayAddr": "0xD5938590D5dD8ce95812D4D515a219C12C551D67",
|
||||
"WETHGatewayAddr": "0xb0aaA582564fade4232a16fdB1383004A6A7247F",
|
||||
"ERC1155GatewayAddr": "0x4f33B1655619c2C0B7C450128Df760B4365Cb549"
|
||||
"MessengerAddr": "0xda7c91Ed60DACD28Cb97B180108958c9ACC7698a",
|
||||
"ETHGatewayAddr": "0x567671187b5FFbcDFe0B6EcF3e56C05508a31A87",
|
||||
"WETHGatewayAddr": "0x3b03aE2F27d62E0B2b6740CA20Fc07Af4338B791",
|
||||
"StandardERC20Gateway": "0xb00cb1F6f7C43D2EE8C4e2163a6bEA22441A5B7c",
|
||||
"CustomERC20GatewayAddr": "0x63CCb38E9d21A72777b203267F2e4ba5C974fC62",
|
||||
"ERC721GatewayAddr": "0xE2c36a2D8B5528719aE7A42A778b2D08b18d134a",
|
||||
"ERC1155GatewayAddr": "0xfF14870512e42BFb85a9B7bEfDc06e9aB5A37269",
|
||||
"USDCGatewayAddr": "0x97D5799CDC8eE2A7452913d7548c7cEE285719FA",
|
||||
"LIDOGatewayAddr": "0xE9c5C9f67ec7B773fC76440845751F657bb953FF",
|
||||
"DAIGatewayAddr": "0xC5034eB8F682b73F93C9246aa95A8eBbF82793aA"
|
||||
},
|
||||
"db": {
|
||||
"dsn": "postgres://postgres:1234@localhost:5444/test?sslmode=disable",
|
||||
|
||||
@@ -31,6 +31,9 @@ type LayerConfig struct {
|
||||
MessengerAddr string `json:"MessengerAddr"`
|
||||
ETHGatewayAddr string `json:"ETHGatewayAddr"`
|
||||
WETHGatewayAddr string `json:"WETHGatewayAddr"`
|
||||
USDCGatewayAddr string `json:"USDCGatewayAddr"`
|
||||
LIDOGatewayAddr string `json:"LIDOGatewayAddr"`
|
||||
DAIGatewayAddr string `json:"DAIGatewayAddr"`
|
||||
StandardERC20Gateway string `json:"StandardERC20Gateway"`
|
||||
ERC721GatewayAddr string `json:"ERC721GatewayAddr"`
|
||||
ERC1155GatewayAddr string `json:"ERC1155GatewayAddr"`
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -24,14 +24,14 @@ func NewBatchController(db *gorm.DB) *BatchController {
|
||||
func (b *BatchController) GetWithdrawRootByBatchIndex(ctx *gin.Context) {
|
||||
var req types.QueryByBatchIndexRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
|
||||
return
|
||||
}
|
||||
result, err := b.batchLogic.GetWithdrawRootByBatchIndex(ctx, req.BatchIndex)
|
||||
if err != nil {
|
||||
types.RenderJSON(ctx, types.ErrGetWithdrawRootByBatchIndexFailure, err, nil)
|
||||
types.RenderFailure(ctx, types.ErrGetWithdrawRootByBatchIndexFailure, err)
|
||||
return
|
||||
}
|
||||
|
||||
types.RenderJSON(ctx, types.Success, nil, result)
|
||||
types.RenderSuccess(ctx, result)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ var (
|
||||
// HistoryCtrler is controller instance
|
||||
HistoryCtrler *HistoryController
|
||||
// BatchCtrler is controller instance
|
||||
BatchCtrler *BatchController
|
||||
BatchCtrler *BatchController
|
||||
|
||||
initControllerOnce sync.Once
|
||||
)
|
||||
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,48 +42,120 @@ func NewHistoryController(db *gorm.DB) *HistoryController {
|
||||
func (c *HistoryController) GetAllClaimableTxsByAddr(ctx *gin.Context) {
|
||||
var req types.QueryByAddressRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
|
||||
return
|
||||
}
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
limit := req.PageSize
|
||||
txs, total, err := c.historyLogic.GetClaimableTxsByAddress(ctx, common.HexToAddress(req.Address), offset, limit)
|
||||
if err != nil {
|
||||
types.RenderJSON(ctx, types.ErrGetClaimablesFailure, err, nil)
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
|
||||
return
|
||||
}
|
||||
|
||||
types.RenderJSON(ctx, types.Success, nil, &types.ResultData{Result: txs, Total: total})
|
||||
}
|
||||
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
|
||||
})
|
||||
|
||||
// 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
|
||||
}
|
||||
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.RenderJSON(ctx, types.ErrGetTxsByAddrFailure, err, nil)
|
||||
types.RenderFailure(ctx, types.ErrGetClaimablesFailure, err)
|
||||
return
|
||||
}
|
||||
types.RenderJSON(ctx, types.Success, nil, &types.ResultData{Result: message, Total: total})
|
||||
|
||||
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"))
|
||||
}
|
||||
}
|
||||
|
||||
// PostQueryTxsByHash defines the http post method behavior
|
||||
func (c *HistoryController) PostQueryTxsByHash(ctx *gin.Context) {
|
||||
var req types.QueryByHashRequest
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
|
||||
return
|
||||
}
|
||||
result, err := c.historyLogic.GetTxsByHashes(ctx, req.Txs)
|
||||
if err != nil {
|
||||
types.RenderJSON(ctx, types.ErrGetTxsByHashFailure, err, nil)
|
||||
|
||||
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.RenderJSON(ctx, types.Success, nil, &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
|
||||
}
|
||||
@@ -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,9 +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)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
const (
|
||||
// Success shows OK.
|
||||
Success = 0
|
||||
// InternalServerError shows a fatal error in the server
|
||||
InternalServerError = 500
|
||||
// ErrParameterInvalidNo is invalid params
|
||||
ErrParameterInvalidNo = 40001
|
||||
// ErrGetClaimablesFailure is getting all claimables txs error
|
||||
@@ -24,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
|
||||
@@ -78,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"`
|
||||
@@ -103,3 +104,28 @@ func RenderJSON(ctx *gin.Context, errCode int, err error, data interface{}) {
|
||||
}
|
||||
ctx.JSON(http.StatusOK, renderData)
|
||||
}
|
||||
|
||||
// RenderSuccess renders success response with json
|
||||
func RenderSuccess(ctx *gin.Context, data interface{}) {
|
||||
RenderJSON(ctx, Success, nil, data)
|
||||
}
|
||||
|
||||
// RenderFailure renders failure response with json
|
||||
func RenderFailure(ctx *gin.Context, errCode int, err error) {
|
||||
RenderJSON(ctx, errCode, err, nil)
|
||||
}
|
||||
|
||||
// RenderFatal renders fatal response with json
|
||||
func RenderFatal(ctx *gin.Context, err error) {
|
||||
var errMsg string
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
renderData := Response{
|
||||
ErrCode: InternalServerError,
|
||||
ErrMsg: errMsg,
|
||||
Data: nil,
|
||||
}
|
||||
ctx.Set("errcode", InternalServerError)
|
||||
ctx.JSON(http.StatusInternalServerError, renderData)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package metrics
|
||||
package observability
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"scroll-tech/common/metrics/ginmetrics"
|
||||
"bridge-history-api/observability/ginmetrics"
|
||||
)
|
||||
|
||||
// Use register the gin metric
|
||||
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
|
||||
|
||||
@@ -2,6 +2,7 @@ package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -67,18 +68,31 @@ func InitDB(config *config.DBConfig) (*gorm.DB, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sqlDB, pingErr := Ping(db)
|
||||
if pingErr != nil {
|
||||
return nil, pingErr
|
||||
}
|
||||
|
||||
sqlDB.SetConnMaxLifetime(time.Minute * 10)
|
||||
sqlDB.SetConnMaxIdleTime(time.Minute * 5)
|
||||
sqlDB.SetMaxOpenConns(config.MaxOpenNum)
|
||||
sqlDB.SetMaxIdleConns(config.MaxIdleNum)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// Ping check db status
|
||||
func Ping(db *gorm.DB) (*sql.DB, error) {
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sqlDB.SetMaxOpenConns(config.MaxOpenNum)
|
||||
sqlDB.SetMaxIdleConns(config.MaxIdleNum)
|
||||
|
||||
if err = sqlDB.Ping(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
return sqlDB, nil
|
||||
}
|
||||
|
||||
// CloseDB close the db handler. notice the db handler only can close when then program exit.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,7 +24,6 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover-stats-api/go.* ./prover-stats-api/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
@@ -37,7 +36,7 @@ COPY . .
|
||||
RUN cp -r ./common/libzkp/interface ./coordinator/internal/logic/verifier/lib
|
||||
COPY --from=zkp-builder /app/target/release/libzkp.so ./coordinator/internal/logic/verifier/lib/
|
||||
COPY --from=zkp-builder /app/target/release/libzktrie.so ./coordinator/internal/logic/verifier/lib/
|
||||
RUN cd ./coordinator && make coordinator_skip_libzkp && mv ./build/bin/coordinator /bin/coordinator && mv internal/logic/verifier/lib /bin/
|
||||
RUN cd ./coordinator && make coordinator_api_skip_libzkp && mv ./build/bin/coordinator_api /bin/coordinator_api && mv internal/logic/verifier/lib /bin/
|
||||
|
||||
# Pull coordinator into a second stage deploy alpine container
|
||||
FROM ubuntu:20.04
|
||||
@@ -45,7 +44,7 @@ ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/src/coordinator/internal/logic/verifier/li
|
||||
# ENV CHAIN_ID=534353
|
||||
RUN mkdir -p /src/coordinator/internal/logic/verifier/lib
|
||||
COPY --from=builder /bin/lib /src/coordinator/internal/logic/verifier/lib
|
||||
COPY --from=builder /bin/coordinator /bin/
|
||||
RUN /bin/coordinator --version
|
||||
COPY --from=builder /bin/coordinator_api /bin/
|
||||
RUN /bin/coordinator_api --version
|
||||
|
||||
ENTRYPOINT ["/bin/coordinator"]
|
||||
ENTRYPOINT ["/bin/coordinator_api"]
|
||||
@@ -7,25 +7,19 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover-stats-api/go.* ./prover-stats-api/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
# Support mainland environment.
|
||||
#ENV GOPROXY="https://goproxy.cn,direct"
|
||||
RUN go mod download -x
|
||||
|
||||
|
||||
# Build prover-stats-api
|
||||
# Build coordinator
|
||||
FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/prover-stats-api/cmd/ && go build -v -p 4 -o /bin/prover-stats-api
|
||||
cd /src/coordinator/cmd/cron/ && go build -v -p 4 -o /bin/coordinator_cron
|
||||
|
||||
# Pull prover-stats-api into a second stage deploy alpine container \
|
||||
# Pull coordinator into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /bin/coordinator_cron /bin/
|
||||
|
||||
COPY --from=builder /bin/prover-stats-api /bin/
|
||||
|
||||
ENTRYPOINT ["prover-stats-api"]
|
||||
ENTRYPOINT ["coordinator_cron"]
|
||||
@@ -0,0 +1,6 @@
|
||||
assets/
|
||||
contracts/
|
||||
docs/
|
||||
l2geth/
|
||||
rpc-gateway/
|
||||
*target/*
|
||||
@@ -7,7 +7,6 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover-stats-api/go.* ./prover-stats-api/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
|
||||
@@ -7,7 +7,6 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover-stats-api/go.* ./prover-stats-api/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
|
||||
@@ -7,7 +7,6 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover-stats-api/go.* ./prover-stats-api/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
|
||||
@@ -7,7 +7,6 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover-stats-api/go.* ./prover-stats-api/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
|
||||
@@ -15,7 +15,7 @@ var verbose bool
|
||||
|
||||
func init() {
|
||||
v := os.Getenv("LOG_DOCKER")
|
||||
if v == "true" || v == "TRUE" {
|
||||
if strings.ToLower(v) == "true" {
|
||||
verbose = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -63,17 +64,18 @@ func InitDB(config *Config) (*gorm.DB, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
sqlDB, pingErr := Ping(db)
|
||||
if pingErr != nil {
|
||||
return nil, pingErr
|
||||
}
|
||||
|
||||
sqlDB.SetConnMaxLifetime(time.Minute * 10)
|
||||
sqlDB.SetConnMaxIdleTime(time.Minute * 5)
|
||||
|
||||
sqlDB.SetMaxOpenConns(config.MaxOpenNum)
|
||||
sqlDB.SetMaxIdleConns(config.MaxIdleNum)
|
||||
|
||||
if err = sqlDB.Ping(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@@ -88,3 +90,16 @@ func CloseDB(db *gorm.DB) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ping check db status
|
||||
func Ping(db *gorm.DB) (*sql.DB, error) {
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = sqlDB.Ping(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sqlDB, nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ import (
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"scroll-tech/common/docker"
|
||||
"scroll-tech/common/version"
|
||||
)
|
||||
|
||||
func TestGormLogger(t *testing.T) {
|
||||
@@ -33,3 +37,26 @@ func TestGormLogger(t *testing.T) {
|
||||
gl.Info(context.Background(), "test %s warn:%v", "testInfo", errors.New("test info"))
|
||||
gl.Trace(context.Background(), time.Now(), func() (string, int64) { return "test trace", 1 }, nil)
|
||||
}
|
||||
|
||||
func TestDB(t *testing.T) {
|
||||
version.Version = "v4.1.98-aaa-bbb-ccc"
|
||||
base := docker.NewDockerApp()
|
||||
base.RunDBImage(t)
|
||||
|
||||
dbCfg := &Config{
|
||||
DSN: base.DBConfig.DSN,
|
||||
DriverName: base.DBConfig.DriverName,
|
||||
MaxOpenNum: base.DBConfig.MaxOpenNum,
|
||||
MaxIdleNum: base.DBConfig.MaxIdleNum,
|
||||
}
|
||||
|
||||
var err error
|
||||
db, err := InitDB(dbCfg)
|
||||
assert.NoError(t, err)
|
||||
|
||||
sqlDB, err := Ping(db)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, sqlDB)
|
||||
|
||||
assert.NoError(t, CloseDB(db))
|
||||
}
|
||||
|
||||
1361
common/libzkp/impl/Cargo.lock
generated
1361
common/libzkp/impl/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ edition = "2021"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[patch.crates-io]
|
||||
ethers-core = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v0.17.0" }
|
||||
ethers-core = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }
|
||||
[patch."https://github.com/privacy-scaling-explorations/halo2.git"]
|
||||
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
|
||||
[patch."https://github.com/privacy-scaling-explorations/poseidon.git"]
|
||||
@@ -20,9 +20,8 @@ maingate = { git = "https://github.com/scroll-tech/halo2wrong", branch = "halo2-
|
||||
halo2curves = { git = "https://github.com/scroll-tech/halo2curves.git", branch = "0.3.1-derive-serde" }
|
||||
|
||||
[dependencies]
|
||||
prover = { git = "https://github.com/scroll-tech/scroll-prover", tag = "v0.7.5" }
|
||||
types = { git = "https://github.com/scroll-tech/scroll-prover", tag = "v0.7.5" }
|
||||
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.8", default-features = false, features = ["parallel_syn", "scroll", "shanghai", "strict-ccc"] }
|
||||
|
||||
base64 = "0.13.0"
|
||||
env_logger = "0.9.0"
|
||||
|
||||
8
common/libzkp/impl/Makefile
Normal file
8
common/libzkp/impl/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
.PHONY: help fmt clippy test test-ci test-all
|
||||
|
||||
fmt:
|
||||
@cargo fmt --all -- --check
|
||||
|
||||
clippy:
|
||||
@cargo check --all-features
|
||||
@cargo clippy --release -- -D warnings
|
||||
@@ -1,15 +1,18 @@
|
||||
use crate::{
|
||||
types::{CheckChunkProofsResponse, ProofResult},
|
||||
utils::{c_char_to_str, c_char_to_vec, string_to_c_char, vec_to_c_char, OUTPUT_DIR},
|
||||
utils::{
|
||||
c_char_to_str, c_char_to_vec, file_exists, panic_catch, string_to_c_char, vec_to_c_char,
|
||||
OUTPUT_DIR,
|
||||
},
|
||||
};
|
||||
use libc::c_char;
|
||||
use prover::{
|
||||
aggregator::{Prover, Verifier},
|
||||
consts::AGG_VK_FILENAME,
|
||||
utils::{chunk_trace_to_witness_block, init_env_and_log},
|
||||
BatchProof, ChunkHash, ChunkProof,
|
||||
BatchProof, BlockTrace, ChunkHash, ChunkProof,
|
||||
};
|
||||
use std::{cell::OnceCell, env, panic, ptr::null};
|
||||
use types::eth::BlockTrace;
|
||||
use std::{cell::OnceCell, env, ptr::null};
|
||||
|
||||
static mut PROVER: OnceCell<Prover> = OnceCell::new();
|
||||
static mut VERIFIER: OnceCell<Verifier> = OnceCell::new();
|
||||
@@ -24,6 +27,12 @@ pub unsafe extern "C" fn init_batch_prover(params_dir: *const c_char, assets_dir
|
||||
|
||||
// TODO: add a settings in scroll-prover.
|
||||
env::set_var("SCROLL_PROVER_ASSETS_DIR", assets_dir);
|
||||
|
||||
// VK file must exist, it is optional and logged as a warning in prover.
|
||||
if !file_exists(assets_dir, &AGG_VK_FILENAME) {
|
||||
panic!("{} must exist in folder {}", *AGG_VK_FILENAME, assets_dir);
|
||||
}
|
||||
|
||||
let prover = Prover::from_dirs(params_dir, assets_dir);
|
||||
|
||||
PROVER.set(prover).unwrap();
|
||||
@@ -47,7 +56,7 @@ pub unsafe extern "C" fn init_batch_verifier(params_dir: *const c_char, assets_d
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_batch_vk() -> *const c_char {
|
||||
let vk_result = panic::catch_unwind(|| PROVER.get_mut().unwrap().get_vk());
|
||||
let vk_result = panic_catch(|| PROVER.get_mut().unwrap().get_vk());
|
||||
|
||||
vk_result
|
||||
.ok()
|
||||
@@ -58,7 +67,7 @@ pub unsafe extern "C" fn get_batch_vk() -> *const c_char {
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn check_chunk_proofs(chunk_proofs: *const c_char) -> *const c_char {
|
||||
let check_result: Result<bool, String> = panic::catch_unwind(|| {
|
||||
let check_result: Result<bool, String> = panic_catch(|| {
|
||||
let chunk_proofs = c_char_to_vec(chunk_proofs);
|
||||
let chunk_proofs = serde_json::from_slice::<Vec<ChunkProof>>(&chunk_proofs)
|
||||
.map_err(|e| format!("failed to deserialize chunk proofs: {e:?}"))?;
|
||||
@@ -94,7 +103,7 @@ pub unsafe extern "C" fn gen_batch_proof(
|
||||
chunk_hashes: *const c_char,
|
||||
chunk_proofs: *const c_char,
|
||||
) -> *const c_char {
|
||||
let proof_result: Result<Vec<u8>, String> = panic::catch_unwind(|| {
|
||||
let proof_result: Result<Vec<u8>, String> = panic_catch(|| {
|
||||
let chunk_hashes = c_char_to_vec(chunk_hashes);
|
||||
let chunk_proofs = c_char_to_vec(chunk_proofs);
|
||||
|
||||
@@ -143,7 +152,7 @@ pub unsafe extern "C" fn verify_batch_proof(proof: *const c_char) -> c_char {
|
||||
let proof = c_char_to_vec(proof);
|
||||
let proof = serde_json::from_slice::<BatchProof>(proof.as_slice()).unwrap();
|
||||
|
||||
let verified = panic::catch_unwind(|| VERIFIER.get().unwrap().verify_agg_evm_proof(proof));
|
||||
let verified = panic_catch(|| VERIFIER.get().unwrap().verify_agg_evm_proof(proof));
|
||||
verified.unwrap_or(false) as c_char
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
use crate::{
|
||||
types::ProofResult,
|
||||
utils::{c_char_to_str, c_char_to_vec, string_to_c_char, vec_to_c_char, OUTPUT_DIR},
|
||||
utils::{
|
||||
c_char_to_str, c_char_to_vec, file_exists, panic_catch, string_to_c_char, vec_to_c_char,
|
||||
OUTPUT_DIR,
|
||||
},
|
||||
};
|
||||
use libc::c_char;
|
||||
use prover::{
|
||||
consts::CHUNK_VK_FILENAME,
|
||||
utils::init_env_and_log,
|
||||
zkevm::{Prover, Verifier},
|
||||
ChunkProof,
|
||||
BlockTrace, ChunkProof,
|
||||
};
|
||||
use std::{cell::OnceCell, env, panic, ptr::null};
|
||||
use types::eth::BlockTrace;
|
||||
use std::{cell::OnceCell, env, ptr::null};
|
||||
|
||||
static mut PROVER: OnceCell<Prover> = OnceCell::new();
|
||||
static mut VERIFIER: OnceCell<Verifier> = OnceCell::new();
|
||||
@@ -24,7 +27,13 @@ pub unsafe extern "C" fn init_chunk_prover(params_dir: *const c_char, assets_dir
|
||||
|
||||
// TODO: add a settings in scroll-prover.
|
||||
env::set_var("SCROLL_PROVER_ASSETS_DIR", assets_dir);
|
||||
let prover = Prover::from_params_dir(params_dir);
|
||||
|
||||
// VK file must exist, it is optional and logged as a warning in prover.
|
||||
if !file_exists(assets_dir, &CHUNK_VK_FILENAME) {
|
||||
panic!("{} must exist in folder {}", *CHUNK_VK_FILENAME, assets_dir);
|
||||
}
|
||||
|
||||
let prover = Prover::from_dirs(params_dir, assets_dir);
|
||||
|
||||
PROVER.set(prover).unwrap();
|
||||
}
|
||||
@@ -47,7 +56,7 @@ pub unsafe extern "C" fn init_chunk_verifier(params_dir: *const c_char, assets_d
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_chunk_vk() -> *const c_char {
|
||||
let vk_result = panic::catch_unwind(|| PROVER.get_mut().unwrap().get_vk());
|
||||
let vk_result = panic_catch(|| PROVER.get_mut().unwrap().get_vk());
|
||||
|
||||
vk_result
|
||||
.ok()
|
||||
@@ -58,7 +67,7 @@ pub unsafe extern "C" fn get_chunk_vk() -> *const c_char {
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn gen_chunk_proof(block_traces: *const c_char) -> *const c_char {
|
||||
let proof_result: Result<Vec<u8>, String> = panic::catch_unwind(|| {
|
||||
let proof_result: Result<Vec<u8>, String> = panic_catch(|| {
|
||||
let block_traces = c_char_to_vec(block_traces);
|
||||
let block_traces = serde_json::from_slice::<Vec<BlockTrace>>(&block_traces)
|
||||
.map_err(|e| format!("failed to deserialize block traces: {e:?}"))?;
|
||||
@@ -66,7 +75,7 @@ pub unsafe extern "C" fn gen_chunk_proof(block_traces: *const c_char) -> *const
|
||||
let proof = PROVER
|
||||
.get_mut()
|
||||
.expect("failed to get mutable reference to PROVER.")
|
||||
.gen_chunk_proof(block_traces, None, OUTPUT_DIR.as_deref())
|
||||
.gen_chunk_proof(block_traces, None, None, OUTPUT_DIR.as_deref())
|
||||
.map_err(|e| format!("failed to generate proof: {e:?}"))?;
|
||||
|
||||
serde_json::to_vec(&proof).map_err(|e| format!("failed to serialize the proof: {e:?}"))
|
||||
@@ -93,6 +102,6 @@ pub unsafe extern "C" fn verify_chunk_proof(proof: *const c_char) -> c_char {
|
||||
let proof = c_char_to_vec(proof);
|
||||
let proof = serde_json::from_slice::<ChunkProof>(proof.as_slice()).unwrap();
|
||||
|
||||
let verified = panic::catch_unwind(|| VERIFIER.get().unwrap().verify_chunk_proof(proof));
|
||||
let verified = panic_catch(|| VERIFIER.get().unwrap().verify_chunk_proof(proof));
|
||||
verified.unwrap_or(false) as c_char
|
||||
}
|
||||
|
||||
@@ -3,12 +3,27 @@ use std::{
|
||||
env,
|
||||
ffi::{CStr, CString},
|
||||
os::raw::c_char,
|
||||
panic::{catch_unwind, AssertUnwindSafe},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
// Only used for debugging.
|
||||
pub(crate) static OUTPUT_DIR: Lazy<Option<String>> =
|
||||
Lazy::new(|| env::var("PROVER_OUTPUT_DIR").ok());
|
||||
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub extern "C" fn free_c_chars(ptr: *mut c_char) {
|
||||
if ptr.is_null() {
|
||||
log::warn!("Try to free an empty pointer!");
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let _ = CString::from_raw(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn c_char_to_str(c: *const c_char) -> &'static str {
|
||||
let cstr = unsafe { CStr::from_ptr(c) };
|
||||
cstr.to_str().unwrap()
|
||||
@@ -26,3 +41,22 @@ pub(crate) fn string_to_c_char(string: String) -> *const c_char {
|
||||
pub(crate) fn vec_to_c_char(bytes: Vec<u8>) -> *const c_char {
|
||||
CString::new(bytes).unwrap().into_raw()
|
||||
}
|
||||
|
||||
pub(crate) fn file_exists(dir: &str, filename: &str) -> bool {
|
||||
let mut path = PathBuf::from(dir);
|
||||
path.push(filename);
|
||||
|
||||
path.exists()
|
||||
}
|
||||
|
||||
pub(crate) fn panic_catch<F: FnOnce() -> R, R>(f: F) -> Result<R, String> {
|
||||
catch_unwind(AssertUnwindSafe(f)).map_err(|err| {
|
||||
if let Some(s) = err.downcast_ref::<String>() {
|
||||
s.to_string()
|
||||
} else if let Some(s) = err.downcast_ref::<&str>() {
|
||||
s.to_string()
|
||||
} else {
|
||||
format!("unable to get panic info {err:?}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,3 +12,4 @@ char* gen_chunk_proof(char* block_traces);
|
||||
char verify_chunk_proof(char* proof);
|
||||
|
||||
char* block_traces_to_chunk_info(char* block_traces);
|
||||
void free_c_chars(char* ptr);
|
||||
|
||||
57
common/observability/ginmetrics/bloom.go
Normal file
57
common/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
common/observability/ginmetrics/metric.go
Normal file
89
common/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
common/observability/ginmetrics/middleware.go
Normal file
155
common/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
common/observability/ginmetrics/types.go
Normal file
158
common/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
common/observability/middleware.go
Normal file
18
common/observability/middleware.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package observability
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"scroll-tech/common/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
common/observability/probes.go
Normal file
35
common/observability/probes.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package observability
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"scroll-tech/common/database"
|
||||
"scroll-tech/common/types"
|
||||
)
|
||||
|
||||
// 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 := database.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)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package metrics
|
||||
package observability
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -11,17 +11,17 @@ import (
|
||||
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
// Server starts the metrics server on the given address, will be closed when the given
|
||||
// context is canceled.
|
||||
func Server(c *cli.Context, reg *prometheus.Registry) {
|
||||
func Server(c *cli.Context, db *gorm.DB) {
|
||||
if !c.Bool(utils.MetricsEnabled.Name) {
|
||||
return
|
||||
}
|
||||
@@ -33,6 +33,10 @@ func Server(c *cli.Context, reg *prometheus.Registry) {
|
||||
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,
|
||||
@@ -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)
|
||||
|
||||
@@ -103,7 +103,7 @@ const (
|
||||
ProverTaskFailureTypeUndefined ProverTaskFailureType = iota
|
||||
// ProverTaskFailureTypeTimeout prover task failure of timeout
|
||||
ProverTaskFailureTypeTimeout
|
||||
// ProverTaskFailureTypeSubmitStatusNotOk prover task failure of validated failed by coordinator
|
||||
// ProverTaskFailureTypeSubmitStatusNotOk prover task failure of submit status not ok
|
||||
ProverTaskFailureTypeSubmitStatusNotOk
|
||||
// ProverTaskFailureTypeVerifiedFailed prover task failure of verified failed by coordinator
|
||||
ProverTaskFailureTypeVerifiedFailed
|
||||
|
||||
@@ -3,12 +3,21 @@ package types
|
||||
const (
|
||||
// Success shows OK.
|
||||
Success = 0
|
||||
// InternalServerError shows a fatal error in the server
|
||||
InternalServerError = 500
|
||||
|
||||
// ErrJWTCommonErr jwt common error
|
||||
ErrJWTCommonErr = 50000
|
||||
// ErrJWTTokenExpired jwt token expired
|
||||
ErrJWTTokenExpired = 50001
|
||||
|
||||
// ErrProverStatsAPIParameterInvalidNo is invalid params
|
||||
ErrProverStatsAPIParameterInvalidNo = 10001
|
||||
// ErrProverStatsAPIProverTaskFailure is getting prover task error
|
||||
ErrProverStatsAPIProverTaskFailure = 10002
|
||||
// ErrProverStatsAPIProverTotalRewardFailure is getting total rewards error
|
||||
ErrProverStatsAPIProverTotalRewardFailure = 10003
|
||||
|
||||
// ErrCoordinatorParameterInvalidNo is invalid params
|
||||
ErrCoordinatorParameterInvalidNo = 20001
|
||||
// ErrCoordinatorGetTaskFailure is getting prover task error
|
||||
|
||||
@@ -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"`
|
||||
|
||||
53
common/types/response.go
Normal file
53
common/types/response.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Response the response schema
|
||||
type Response struct {
|
||||
ErrCode int `json:"errcode"`
|
||||
ErrMsg string `json:"errmsg"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// RenderJSON renders response with json
|
||||
func RenderJSON(ctx *gin.Context, errCode int, err error, data interface{}) {
|
||||
var errMsg string
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
renderData := Response{
|
||||
ErrCode: errCode,
|
||||
ErrMsg: errMsg,
|
||||
Data: data,
|
||||
}
|
||||
ctx.JSON(http.StatusOK, renderData)
|
||||
}
|
||||
|
||||
// RenderSuccess renders success response with json
|
||||
func RenderSuccess(ctx *gin.Context, data interface{}) {
|
||||
RenderJSON(ctx, Success, nil, data)
|
||||
}
|
||||
|
||||
// RenderFailure renders failure response with json
|
||||
func RenderFailure(ctx *gin.Context, errCode int, err error) {
|
||||
RenderJSON(ctx, errCode, err, nil)
|
||||
}
|
||||
|
||||
// RenderFatal renders fatal response with json
|
||||
func RenderFatal(ctx *gin.Context, err error) {
|
||||
var errMsg string
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
renderData := Response{
|
||||
ErrCode: InternalServerError,
|
||||
ErrMsg: errMsg,
|
||||
Data: nil,
|
||||
}
|
||||
ctx.Set("errcode", InternalServerError)
|
||||
ctx.JSON(http.StatusInternalServerError, renderData)
|
||||
}
|
||||
@@ -18,7 +18,7 @@ func LogSetup(ctx *cli.Context) error {
|
||||
if logFile := ctx.String(LogFileFlag.Name); len(logFile) > 0 {
|
||||
fp, err := os.OpenFile(filepath.Clean(logFile), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to open log file", "err", err)
|
||||
utils.Fatalf("Failed to open log file", "err", err)
|
||||
}
|
||||
if ctx.Bool(LogJSONFormat.Name) {
|
||||
ostream = log.StreamHandler(io.Writer(fp), log.JSONFormat())
|
||||
|
||||
@@ -24,8 +24,10 @@ var (
|
||||
// DBCliApp the name of mock database app.
|
||||
DBCliApp MockAppName = "db_cli-test"
|
||||
|
||||
// CoordinatorApp the name of mock coordinator app.
|
||||
CoordinatorApp MockAppName = "coordinator-test"
|
||||
// CoordinatorAPIApp the name of mock coordinator app.
|
||||
CoordinatorAPIApp MockAppName = "coordinator-api-test"
|
||||
// CoordinatorCronApp the name of mock coordinator cron app.
|
||||
CoordinatorCronApp MockAppName = "coordinator-cron-test"
|
||||
|
||||
// ChunkProverApp the name of mock chunk prover app.
|
||||
ChunkProverApp MockAppName = "chunkProver-test"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -20,36 +19,3 @@ func CheckScrollProverVersion(proverVersion string) bool {
|
||||
// compare the `scroll_prover` version
|
||||
return remote[2] == local[2]
|
||||
}
|
||||
|
||||
// CheckScrollProverVersionTag check the "scroll-prover" version's tag, if it's too old, return false
|
||||
func CheckScrollProverVersionTag(proverVersion string) bool {
|
||||
// note the the version is in fact in the format of "tag-commit-scroll_prover-halo2",
|
||||
// so split-by-'-' length should be 4
|
||||
remote := strings.Split(proverVersion, "-")
|
||||
if len(remote) != 4 {
|
||||
return false
|
||||
}
|
||||
remoteTagNums := strings.Split(strings.TrimPrefix(remote[0], "v"), ".")
|
||||
if len(remoteTagNums) != 3 {
|
||||
return false
|
||||
}
|
||||
remoteTagMajor, err := strconv.Atoi(remoteTagNums[0])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
remoteTagMinor, err := strconv.Atoi(remoteTagNums[1])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
remoteTagPatch, err := strconv.Atoi(remoteTagNums[2])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if remoteTagMajor < 4 {
|
||||
return false
|
||||
}
|
||||
if remoteTagMinor == 1 && remoteTagPatch < 98 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var tag = "v4.2.23"
|
||||
var tag = "v4.3.43"
|
||||
|
||||
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
|
||||
|
||||
@@ -93,28 +93,6 @@ Mapping from L1 message hash to drop status.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### isL1MessageSent
|
||||
|
||||
```solidity
|
||||
function isL1MessageSent(bytes32) external view returns (bool)
|
||||
```
|
||||
|
||||
Mapping from L1 message hash to sent status.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -183,6 +161,28 @@ The address of L1MessageQueue contract.
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### messageSendTimestamp
|
||||
|
||||
```solidity
|
||||
function messageSendTimestamp(bytes32) external view returns (uint256)
|
||||
```
|
||||
|
||||
Mapping from L1 message hash to the timestamp when the message is sent.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```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
|
||||
|
||||
@@ -70,28 +70,6 @@ Mapping from L1 message hash to a boolean value indicating if the message has be
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### isL2MessageSent
|
||||
|
||||
```solidity
|
||||
function isL2MessageSent(bytes32) external view returns (bool)
|
||||
```
|
||||
|
||||
Mapping from L2 message hash to sent status.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
@@ -121,6 +99,28 @@ The address of L2MessageQueue.
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### messageSendTimestamp
|
||||
|
||||
```solidity
|
||||
function messageSendTimestamp(bytes32) external view returns (uint256)
|
||||
```
|
||||
|
||||
Mapping from L2 message hash to the timestamp when the message is sent.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```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
|
||||
|
||||
@@ -10,6 +10,38 @@ This contract maintains data for the Scroll rollup.
|
||||
|
||||
## Methods
|
||||
|
||||
### addProver
|
||||
|
||||
```solidity
|
||||
function addProver(address _account) external nonpayable
|
||||
```
|
||||
|
||||
Add an account to the prover list.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _account | address | The address of account to add. |
|
||||
|
||||
### addSequencer
|
||||
|
||||
```solidity
|
||||
function addSequencer(address _account) external nonpayable
|
||||
```
|
||||
|
||||
Add an account to the sequencer list.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _account | address | The address of account to add. |
|
||||
|
||||
### commitBatch
|
||||
|
||||
```solidity
|
||||
@@ -113,7 +145,7 @@ Import layer 2 genesis block
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _messageQueue, address _verifier, uint256 _maxNumL2TxInChunk) external nonpayable
|
||||
function initialize(address _messageQueue, address _verifier, uint256 _maxNumTxInChunk) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
@@ -126,7 +158,7 @@ function initialize(address _messageQueue, address _verifier, uint256 _maxNumL2T
|
||||
|---|---|---|
|
||||
| _messageQueue | address | undefined |
|
||||
| _verifier | address | undefined |
|
||||
| _maxNumL2TxInChunk | uint256 | undefined |
|
||||
| _maxNumTxInChunk | uint256 | undefined |
|
||||
|
||||
### isBatchFinalized
|
||||
|
||||
@@ -228,10 +260,10 @@ The chain id of the corresponding layer 2 chain.
|
||||
|---|---|---|
|
||||
| _0 | uint64 | undefined |
|
||||
|
||||
### maxNumL2TxInChunk
|
||||
### maxNumTxInChunk
|
||||
|
||||
```solidity
|
||||
function maxNumL2TxInChunk() external view returns (uint256)
|
||||
function maxNumTxInChunk() external view returns (uint256)
|
||||
```
|
||||
|
||||
The maximum number of transactions allowed in each chunk.
|
||||
@@ -279,6 +311,55 @@ function owner() external view returns (address)
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### paused
|
||||
|
||||
```solidity
|
||||
function paused() external view returns (bool)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns true if the contract is paused, and false otherwise.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### removeProver
|
||||
|
||||
```solidity
|
||||
function removeProver(address _account) external nonpayable
|
||||
```
|
||||
|
||||
Add an account from the prover list.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _account | address | The address of account to remove. |
|
||||
|
||||
### removeSequencer
|
||||
|
||||
```solidity
|
||||
function removeSequencer(address _account) external nonpayable
|
||||
```
|
||||
|
||||
Remove an account from the sequencer list.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _account | address | The address of account to remove. |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
@@ -287,7 +368,7 @@ function renounceOwnership() external nonpayable
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.*
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### revertBatch
|
||||
@@ -298,7 +379,7 @@ function revertBatch(bytes _batchHeader, uint256 _count) external nonpayable
|
||||
|
||||
Revert a pending batch.
|
||||
|
||||
*one can only revert unfinalized batches.*
|
||||
*If the owner want to revert a sequence of batches by sending multiple transactions, make sure to revert recent batches first.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
@@ -307,6 +388,22 @@ Revert a pending batch.
|
||||
| _batchHeader | bytes | undefined |
|
||||
| _count | uint256 | undefined |
|
||||
|
||||
### setPause
|
||||
|
||||
```solidity
|
||||
function setPause(bool _status) external nonpayable
|
||||
```
|
||||
|
||||
Pause the contract
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _status | bool | The pause status to update. |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
@@ -323,13 +420,13 @@ function transferOwnership(address newOwner) external nonpayable
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateMaxNumL2TxInChunk
|
||||
### updateMaxNumTxInChunk
|
||||
|
||||
```solidity
|
||||
function updateMaxNumL2TxInChunk(uint256 _maxNumL2TxInChunk) external nonpayable
|
||||
function updateMaxNumTxInChunk(uint256 _maxNumTxInChunk) external nonpayable
|
||||
```
|
||||
|
||||
Update the value of `maxNumL2TxInChunk`.
|
||||
Update the value of `maxNumTxInChunk`.
|
||||
|
||||
|
||||
|
||||
@@ -337,41 +434,7 @@ Update the value of `maxNumL2TxInChunk`.
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _maxNumL2TxInChunk | uint256 | The new value of `maxNumL2TxInChunk`. |
|
||||
|
||||
### updateProver
|
||||
|
||||
```solidity
|
||||
function updateProver(address _account, bool _status) external nonpayable
|
||||
```
|
||||
|
||||
Update the status of prover.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _account | address | The address of account to update. |
|
||||
| _status | bool | The status of the account to update. |
|
||||
|
||||
### updateSequencer
|
||||
|
||||
```solidity
|
||||
function updateSequencer(address _account, bool _status) external nonpayable
|
||||
```
|
||||
|
||||
Update the status of sequencer.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _account | address | The address of account to update. |
|
||||
| _status | bool | The status of the account to update. |
|
||||
| _maxNumTxInChunk | uint256 | The new value of `maxNumTxInChunk`. |
|
||||
|
||||
### updateVerifier
|
||||
|
||||
@@ -435,7 +498,7 @@ Return the message root of a committed batch.
|
||||
### CommitBatch
|
||||
|
||||
```solidity
|
||||
event CommitBatch(bytes32 indexed batchHash)
|
||||
event CommitBatch(uint256 indexed batchIndex, bytes32 indexed batchHash)
|
||||
```
|
||||
|
||||
Emitted when a new batch is committed.
|
||||
@@ -446,12 +509,13 @@ Emitted when a new batch is committed.
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| batchIndex `indexed` | uint256 | undefined |
|
||||
| batchHash `indexed` | bytes32 | undefined |
|
||||
|
||||
### FinalizeBatch
|
||||
|
||||
```solidity
|
||||
event FinalizeBatch(bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot)
|
||||
event FinalizeBatch(uint256 indexed batchIndex, bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot)
|
||||
```
|
||||
|
||||
Emitted when a batch is finalized.
|
||||
@@ -462,10 +526,27 @@ Emitted when a batch is finalized.
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| batchIndex `indexed` | uint256 | undefined |
|
||||
| batchHash `indexed` | bytes32 | undefined |
|
||||
| stateRoot | bytes32 | undefined |
|
||||
| withdrawRoot | bytes32 | undefined |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
@@ -483,10 +564,26 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### Paused
|
||||
|
||||
```solidity
|
||||
event Paused(address account)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| account | address | undefined |
|
||||
|
||||
### RevertBatch
|
||||
|
||||
```solidity
|
||||
event RevertBatch(bytes32 indexed batchHash)
|
||||
event RevertBatch(uint256 indexed batchIndex, bytes32 indexed batchHash)
|
||||
```
|
||||
|
||||
revert a pending batch.
|
||||
@@ -497,15 +594,16 @@ revert a pending batch.
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| batchIndex `indexed` | uint256 | undefined |
|
||||
| batchHash `indexed` | bytes32 | undefined |
|
||||
|
||||
### UpdateMaxNumL2TxInChunk
|
||||
### Unpaused
|
||||
|
||||
```solidity
|
||||
event UpdateMaxNumL2TxInChunk(uint256 oldMaxNumL2TxInChunk, uint256 newMaxNumL2TxInChunk)
|
||||
event Unpaused(address account)
|
||||
```
|
||||
|
||||
Emitted when the value of `maxNumL2TxInChunk` is updated.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -513,8 +611,24 @@ Emitted when the value of `maxNumL2TxInChunk` is updated.
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldMaxNumL2TxInChunk | uint256 | The old value of `maxNumL2TxInChunk`. |
|
||||
| newMaxNumL2TxInChunk | uint256 | The new value of `maxNumL2TxInChunk`. |
|
||||
| account | address | undefined |
|
||||
|
||||
### UpdateMaxNumTxInChunk
|
||||
|
||||
```solidity
|
||||
event UpdateMaxNumTxInChunk(uint256 oldMaxNumTxInChunk, uint256 newMaxNumTxInChunk)
|
||||
```
|
||||
|
||||
Emitted when the value of `maxNumTxInChunk` is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldMaxNumTxInChunk | uint256 | The old value of `maxNumTxInChunk`. |
|
||||
| newMaxNumTxInChunk | uint256 | The new value of `maxNumTxInChunk`. |
|
||||
|
||||
### UpdateProver
|
||||
|
||||
@@ -553,7 +667,7 @@ Emitted when owner updates the status of sequencer.
|
||||
### UpdateVerifier
|
||||
|
||||
```solidity
|
||||
event UpdateVerifier(address oldVerifier, address newVerifier)
|
||||
event UpdateVerifier(address indexed oldVerifier, address indexed newVerifier)
|
||||
```
|
||||
|
||||
Emitted when the address of rollup verifier is updated.
|
||||
@@ -564,8 +678,8 @@ Emitted when the address of rollup verifier is updated.
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldVerifier | address | The address of old rollup verifier. |
|
||||
| newVerifier | address | The address of new rollup verifier. |
|
||||
| oldVerifier `indexed` | address | The address of old rollup verifier. |
|
||||
| newVerifier `indexed` | address | The address of new rollup verifier. |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ describe("EnforcedTxGateway.spec", async () => {
|
||||
|
||||
await queue.initialize(constants.AddressZero, constants.AddressZero, gateway.address, oracle.address, 10000000);
|
||||
await gateway.initialize(queue.address, feeVault.address);
|
||||
await oracle.initialize(21000, 0, 8, 16);
|
||||
await oracle.initialize(21000, 51000, 8, 16);
|
||||
|
||||
const Whitelist = await ethers.getContractFactory("Whitelist", deployer);
|
||||
const whitelist = await Whitelist.deploy(deployer.address);
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("L1MessageQueue", async () => {
|
||||
deployer
|
||||
);
|
||||
|
||||
await oracle.initialize(21000, 0, 8, 16);
|
||||
await oracle.initialize(21000, 50000, 8, 16);
|
||||
await queue.initialize(messenger.address, scrollChain.address, gateway.address, oracle.address, 10000000);
|
||||
});
|
||||
|
||||
@@ -264,8 +264,8 @@ describe("L1MessageQueue", async () => {
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
// append 100 messages
|
||||
for (let i = 0; i < 100; i++) {
|
||||
// append 512 messages
|
||||
for (let i = 0; i < 256 * 2; i++) {
|
||||
await queue.connect(messenger).appendCrossDomainMessage(constants.AddressZero, 1000000, "0x");
|
||||
}
|
||||
|
||||
@@ -274,7 +274,8 @@ describe("L1MessageQueue", async () => {
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(0, 50, 0);
|
||||
for (let i = 0; i < 50; i++) {
|
||||
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(false);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
expect(await queue.pendingQueueIndex()).to.eq(50);
|
||||
|
||||
@@ -284,7 +285,8 @@ describe("L1MessageQueue", async () => {
|
||||
.withArgs(50, 10, 1023);
|
||||
expect(await queue.pendingQueueIndex()).to.eq(60);
|
||||
for (let i = 50; i < 60; i++) {
|
||||
expect(BigNumber.from(await queue.getCrossDomainMessage(i))).to.gt(constants.Zero);
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
|
||||
// pop 20 messages, skip first 5
|
||||
@@ -293,12 +295,76 @@ describe("L1MessageQueue", async () => {
|
||||
.withArgs(60, 20, 31);
|
||||
expect(await queue.pendingQueueIndex()).to.eq(80);
|
||||
for (let i = 60; i < 65; i++) {
|
||||
expect(BigNumber.from(await queue.getCrossDomainMessage(i))).to.gt(constants.Zero);
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
for (let i = 65; i < 80; i++) {
|
||||
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(false);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
|
||||
// pop 256 messages with random skip
|
||||
const bitmap = BigNumber.from("0x496525059c3f33758d17030403e45afe067b8a0ae1317cda0487fd2932cbea1a");
|
||||
const tx = await queue.connect(scrollChain).popCrossDomainMessage(80, 256, bitmap);
|
||||
await expect(tx).to.emit(queue, "DequeueTransaction").withArgs(80, 256, bitmap);
|
||||
console.log("gas used:", (await tx.wait()).gasUsed.toString());
|
||||
for (let i = 80; i < 80 + 256; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(
|
||||
bitmap
|
||||
.shr(i - 80)
|
||||
.and(1)
|
||||
.eq(1)
|
||||
);
|
||||
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 () => {
|
||||
@@ -308,7 +374,7 @@ describe("L1MessageQueue", async () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when drop executed message", async () => {
|
||||
it("should revert, when drop non-skipped message", async () => {
|
||||
// append 10 messages
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await queue.connect(messenger).appendCrossDomainMessage(constants.AddressZero, 1000000, "0x");
|
||||
@@ -318,14 +384,13 @@ describe("L1MessageQueue", async () => {
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(0, 5, 0);
|
||||
for (let i = 0; i < 5; i++) {
|
||||
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(false);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
expect(await queue.pendingQueueIndex()).to.eq(5);
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith(
|
||||
"message already dropped or executed"
|
||||
);
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("drop non-skipped message");
|
||||
}
|
||||
|
||||
// drop pending message
|
||||
@@ -345,9 +410,12 @@ describe("L1MessageQueue", async () => {
|
||||
.withArgs(0, 10, 0x3ff);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
expect(BigNumber.from(await queue.getCrossDomainMessage(i))).to.gt(constants.Zero);
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.emit(queue, "DropTransaction").withArgs(i);
|
||||
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("message already dropped");
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^v4.9.2",
|
||||
"@openzeppelin/contracts-upgradeable": "^v4.9.2"
|
||||
"@openzeppelin/contracts": "^v4.9.3",
|
||||
"@openzeppelin/contracts-upgradeable": "^v4.9.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts}": "npx eslint --cache --fix",
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -98,7 +96,7 @@ contract DeployL2BridgeContracts is Script {
|
||||
}
|
||||
|
||||
address owner = vm.addr(L2_DEPLOYER_PRIVATE_KEY);
|
||||
L2TxFeeVault feeVault = new L2TxFeeVault(address(owner), L1_TX_FEE_RECIPIENT_ADDR);
|
||||
L2TxFeeVault feeVault = new L2TxFeeVault(address(owner), L1_TX_FEE_RECIPIENT_ADDR, 10 ether);
|
||||
|
||||
logAddress("L2_TX_FEE_VAULT_ADDR", address(feeVault));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
275
contracts/scripts/foundry/InitializeL1ScrollOwner.s.sol
Normal file
275
contracts/scripts/foundry/InitializeL1ScrollOwner.s.sol
Normal file
@@ -0,0 +1,275 @@
|
||||
// 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_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L1_DAI_GATEWAY_PROXY_ADDR");
|
||||
address L1_LIDO_GATEWAY_PROXY_ADDR = vm.envAddress("L1_LIDO_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();
|
||||
|
||||
configL1USDCGateway();
|
||||
configEnforcedTxGateway();
|
||||
|
||||
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_DAI_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_LIDO_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);
|
||||
}
|
||||
|
||||
|
||||
228
contracts/scripts/foundry/InitializeL2ScrollOwner.s.sol
Normal file
228
contracts/scripts/foundry/InitializeL2ScrollOwner.s.sol
Normal file
@@ -0,0 +1,228 @@
|
||||
// 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_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L2_DAI_GATEWAY_PROXY_ADDR");
|
||||
address L2_LIDO_GATEWAY_PROXY_ADDR = vm.envAddress("L2_LIDO_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");
|
||||
|
||||
address L2_USDC_PROXY_ADDR = vm.envAddress("L2_USDC_PROXY_ADDR");
|
||||
address L2_USDC_MASTER_MINTER_ADDR = vm.envAddress("L2_USDC_MASTER_MINTER_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();
|
||||
|
||||
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_DAI_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_LIDO_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));
|
||||
Ownable(L2_USDC_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_USDC_MASTER_MINTER_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);
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = Ownable.transferOwnership.selector;
|
||||
owner.updateAccess(L2_USDC_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_USDC_MASTER_MINTER_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";
|
||||
|
||||
@@ -13,6 +13,7 @@ import {WithdrawTrieVerifier} from "../libraries/verifier/WithdrawTrieVerifier.s
|
||||
import {IMessageDropCallback} from "../libraries/callbacks/IMessageDropCallback.sol";
|
||||
|
||||
// solhint-disable avoid-low-level-calls
|
||||
// solhint-disable not-rely-on-time
|
||||
// solhint-disable reason-string
|
||||
|
||||
/// @title L1ScrollMessenger
|
||||
@@ -41,8 +42,8 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from L1 message hash to sent status.
|
||||
mapping(bytes32 => bool) public isL1MessageSent;
|
||||
/// @notice Mapping from L1 message hash to the timestamp when the message is sent.
|
||||
mapping(bytes32 => uint256) public messageSendTimestamp;
|
||||
|
||||
/// @notice Mapping from L2 message hash to a boolean value indicating if the message has been successfully executed.
|
||||
mapping(bytes32 => bool) public isL2MessageExecuted;
|
||||
@@ -94,6 +95,9 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
address _rollup,
|
||||
address _messageQueue
|
||||
) public initializer {
|
||||
if (_counterpart == address(0) || _rollup == address(0) || _messageQueue == address(0)) {
|
||||
revert ErrZeroAddress();
|
||||
}
|
||||
ScrollMessengerBase.__ScrollMessengerBase_init(_counterpart, _feeVault);
|
||||
|
||||
rollup = _rollup;
|
||||
@@ -114,7 +118,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
|
||||
@@ -189,7 +193,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_from, _to, _value, _messageNonce, _message);
|
||||
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
|
||||
|
||||
require(isL1MessageSent[_xDomainCalldataHash], "Provided message has not been enqueued");
|
||||
require(messageSendTimestamp[_xDomainCalldataHash] > 0, "Provided message has not been enqueued");
|
||||
// cannot replay dropped message
|
||||
require(!isL1MessageDropped[_xDomainCalldataHash], "Message already dropped");
|
||||
|
||||
@@ -261,7 +265,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
// check message exists
|
||||
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_from, _to, _value, _messageNonce, _message);
|
||||
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
|
||||
require(isL1MessageSent[_xDomainCalldataHash], "Provided message has not been enqueued");
|
||||
require(messageSendTimestamp[_xDomainCalldataHash] > 0, "Provided message has not been enqueued");
|
||||
|
||||
// check message not dropped
|
||||
require(!isL1MessageDropped[_xDomainCalldataHash], "Message already dropped");
|
||||
@@ -315,14 +319,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);
|
||||
@@ -339,10 +341,10 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
|
||||
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
|
||||
|
||||
// normally this won't happen, since each message has different nonce, but just in case.
|
||||
require(!isL1MessageSent[_xDomainCalldataHash], "Duplicated message");
|
||||
isL1MessageSent[_xDomainCalldataHash] = true;
|
||||
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 {
|
||||
|
||||
134
contracts/src/L1/ecc.sol
Normal file
134
contracts/src/L1/ecc.sol
Normal file
@@ -0,0 +1,134 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
|
||||
contract Ecc {
|
||||
/* ECC Functions */
|
||||
// https://etherscan.io/address/0x41bf00f080ed41fa86201eac56b8afb170d9e36d#code
|
||||
function ecAdd(uint256[2] memory p0, uint256[2] memory p1) public view
|
||||
returns (uint256[2] memory retP)
|
||||
{
|
||||
uint256[4] memory i = [p0[0], p0[1], p1[0], p1[1]];
|
||||
|
||||
assembly {
|
||||
// call ecadd precompile
|
||||
// inputs are: x1, y1, x2, y2
|
||||
if iszero(staticcall(not(0), 0x06, i, 0x80, retP, 0x40)) {
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://etherscan.io/address/0x41bf00f080ed41fa86201eac56b8afb170d9e36d#code
|
||||
function ecMul(uint256[2] memory p, uint256 s) public view
|
||||
returns (uint256[2] memory retP)
|
||||
{
|
||||
// With a public key (x, y), this computes p = scalar * (x, y).
|
||||
uint256[3] memory i = [p[0], p[1], s];
|
||||
|
||||
assembly {
|
||||
// call ecmul precompile
|
||||
// inputs are: x, y, scalar
|
||||
if iszero(staticcall(not(0), 0x07, i, 0x60, retP, 0x40)) {
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scroll-tech/scroll/contracts/src/libraries/verifier/RollupVerifier.sol
|
||||
struct G1Point {
|
||||
uint256 x;
|
||||
uint256 y;
|
||||
}
|
||||
struct G2Point {
|
||||
uint256[2] x;
|
||||
uint256[2] y;
|
||||
}
|
||||
function ecPairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) {
|
||||
uint256 length = p1.length * 6;
|
||||
uint256[] memory input = new uint256[](length);
|
||||
uint256[1] memory result;
|
||||
bool ret;
|
||||
|
||||
require(p1.length == p2.length);
|
||||
|
||||
for (uint256 i = 0; i < p1.length; i++) {
|
||||
input[0 + i * 6] = p1[i].x;
|
||||
input[1 + i * 6] = p1[i].y;
|
||||
input[2 + i * 6] = p2[i].x[0];
|
||||
input[3 + i * 6] = p2[i].x[1];
|
||||
input[4 + i * 6] = p2[i].y[0];
|
||||
input[5 + i * 6] = p2[i].y[1];
|
||||
}
|
||||
|
||||
assembly {
|
||||
ret := staticcall(gas(), 8, add(input, 0x20), mul(length, 0x20), result, 0x20)
|
||||
}
|
||||
require(ret);
|
||||
return result[0] != 0;
|
||||
}
|
||||
|
||||
/* Bench */
|
||||
function ecAdds(uint256 n) public
|
||||
{
|
||||
uint256[2] memory p0;
|
||||
p0[0] = 1;
|
||||
p0[1] = 2;
|
||||
uint256[2] memory p1;
|
||||
p1[0] = 1;
|
||||
p1[1] = 2;
|
||||
|
||||
for (uint i = 0; i < n; i++) {
|
||||
ecAdd(p0, p1);
|
||||
}
|
||||
}
|
||||
|
||||
function ecMuls(uint256 n) public
|
||||
{
|
||||
uint256[2] memory p0;
|
||||
p0[0] = 1;
|
||||
p0[1] = 2;
|
||||
|
||||
for (uint i = 0; i < n; i++) {
|
||||
ecMul(p0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
function ecPairings(uint256 n) public
|
||||
{
|
||||
G1Point[] memory g1_points = new G1Point[](2);
|
||||
G2Point[] memory g2_points = new G2Point[](2);
|
||||
g1_points[0].x = 0x0000000000000000000000000000000000000000000000000000000000000001;
|
||||
g1_points[0].y = 0x0000000000000000000000000000000000000000000000000000000000000002;
|
||||
g2_points[0].x[1] = 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed;
|
||||
g2_points[0].x[0] = 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2;
|
||||
g2_points[0].y[1] = 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa;
|
||||
g2_points[0].y[0] = 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b;
|
||||
g1_points[1].x = 0x1aa125a22bd902874034e67868aed40267e5575d5919677987e3bc6dd42a32fe;
|
||||
g1_points[1].y = 0x1bacc186725464068956d9a191455c2d6f6db282d83645c610510d8d4efbaee0;
|
||||
g2_points[1].x[1] = 0x1b7734c80605f71f1e2de61e998ce5854ff2abebb76537c3d67e50d71422a852;
|
||||
g2_points[1].x[0] = 0x10d5a1e34b2388a5ebe266033a5e0e63c89084203784da0c6bd9b052a78a2cac;
|
||||
g2_points[1].y[1] = 0x275739c5c2cdbc72e37c689e2ab441ea76c1d284b9c46ae8f5c42ead937819e1;
|
||||
g2_points[1].y[0] = 0x018de34c5b7c3d3d75428bbe050f1449ea3d9961d563291f307a1874f7332e65;
|
||||
|
||||
for (uint i = 0; i < n; i++) {
|
||||
ecPairing(g1_points, g2_points);
|
||||
// bool checked = false;
|
||||
// checked = ecPairing(g1_points, g2_points);
|
||||
// require(checked);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/8a0b7bed82d6b8053872c3fd40703efd58f5699d/test/utils/cryptography/ECDSA.test.js#L230
|
||||
function ecRecovers(uint256 n) public
|
||||
{
|
||||
bytes32 hash = 0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9;
|
||||
bytes32 r = 0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bd;
|
||||
uint8 v = 0x1b;
|
||||
bytes32 s = 0xe0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d;
|
||||
|
||||
for (uint i = 0; i < n; i++) {
|
||||
ecrecover(hash, v, r, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {IMessageDropCallback} from "../../libraries/callbacks/IMessageDropCallback.sol";
|
||||
|
||||
/// @title L1ERC20Gateway
|
||||
/// @notice The `L1ERC20Gateway` as a base contract for ERC20 gateways in L1.
|
||||
/// It has implementation of common used functions for ERC20 gateways.
|
||||
abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, ScrollGatewayBase {
|
||||
using SafeERC20Upgradeable for IERC20Upgradeable;
|
||||
|
||||
@@ -32,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
|
||||
@@ -141,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));
|
||||
@@ -157,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);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user