Compare commits

..

94 Commits

Author SHA1 Message Date
georgehao
d9c1000443 feat: update 2023-09-14 16:17:14 +08:00
georgehao
3f8c8d6a5f feat: update 2023-09-05 15:48:10 +08:00
georgehao
3bc3b4e306 feat: resolve conflict 2023-09-05 15:47:10 +08:00
colinlyguo
2e0340460f fix: migration 2023-08-31 16:03:37 +08:00
colin
63d0ccf364 Merge branch 'develop' into feat/one-task-multi-prover 2023-08-31 16:02:06 +08:00
georgehao
4e3a2a4745 chore: auto version bump [bot] 2023-08-29 08:24:05 +00:00
georgehao
6e880302d3 feat: add proved_at 2023-08-29 16:23:37 +08:00
georgehao
2cb64e0c17 feat: update 2023-08-28 19:54:14 +08:00
georgehao
686cb00a4c feat: update 2023-08-28 19:48:40 +08:00
georgehao
af22052a9c Merge branch 'feat/one-task-multi-prover' of github.com:scroll-tech/scroll into feat/one-task-multi-prover 2023-08-28 19:48:13 +08:00
georgehao
2a542620a1 feat: update 2023-08-28 19:48:02 +08:00
georgehao
e33b9defc6 chore: auto version bump [bot] 2023-08-28 11:44:44 +00:00
georgehao
0349993beb feat: update 2023-08-28 19:44:21 +08:00
georgehao
3a8dce6041 feat: update 2023-08-28 19:43:40 +08:00
georgehao
575ab62b5d chore: auto version bump [bot] 2023-08-28 07:20:45 +00:00
georgehao
b2b65cdb40 xx 2023-08-28 15:20:05 +08:00
georgehao
e5488afd0e feat: update 2023-08-28 15:17:30 +08:00
georgehao
4cc47481f2 chore: auto version bump [bot] 2023-08-28 07:13:19 +00:00
georgehao
69c8e40718 feat: fix conflict 2023-08-28 15:12:51 +08:00
georgehao
24dc27e7b5 feat: updagte 2023-08-25 17:57:18 +08:00
georgehao
4dd11c6475 Merge branch 'feat/one-task-multi-prover' of github.com:scroll-tech/scroll into feat/one-task-multi-prover 2023-08-25 16:46:55 +08:00
georgehao
947be434c3 Merge branch 'develop' of github.com:scroll-tech/scroll into feat/one-task-multi-prover 2023-08-25 16:46:33 +08:00
georgehao
80c011a72c chore: auto version bump [bot] 2023-08-25 08:45:10 +00:00
georgehao
841dd4354c feat: update 2023-08-25 16:44:42 +08:00
georgehao
2441cc7119 Merge branch 'feat/one-task-multi-prover' of github.com:scroll-tech/scroll into feat/one-task-multi-prover 2023-08-25 16:03:13 +08:00
georgehao
c04ffc5726 Merge branch 'develop' of github.com:scroll-tech/scroll into feat/one-task-multi-prover 2023-08-25 16:02:52 +08:00
georgehao
e72627c171 chore: auto version bump [bot] 2023-08-25 08:02:31 +00:00
georgehao
290195d927 Merge branch 'feat/one-task-multi-prover' of github.com:scroll-tech/scroll into feat/one-task-multi-prover 2023-08-25 16:02:04 +08:00
georgehao
606fdba388 feat: update 2023-08-25 15:58:13 +08:00
georgehao
3a8fbee505 chore: auto version bump [bot] 2023-08-25 07:35:28 +00:00
georgehao
a16bcd090a feat: updage 2023-08-25 15:35:06 +08:00
georgehao
670779337f feat: fix 2023-08-25 15:14:20 +08:00
georgehao
3a924f6463 feat: resolve conflict 2023-08-25 11:58:00 +08:00
georgehao
7bd9d2748f chore: auto version bump [bot] 2023-08-25 02:57:20 +00:00
georgehao
753d617cc8 feat: conflict 2023-08-25 10:56:56 +08:00
georgehao
60f8046f9a feat: golint 2023-08-25 10:47:52 +08:00
georgehao
003205a954 feat: udpate 2023-08-24 20:46:08 +08:00
georgehao
0c27c64ade feat: one task assign multiple prover 2023-08-24 20:44:54 +08:00
georgehao
640a01dff7 chore: auto version bump [bot] 2023-08-24 07:41:07 +00:00
georgehao
35a52fc38f feat: fix conflic 2023-08-24 15:40:38 +08:00
georgehao
382fad507a feat: update 2023-08-23 20:07:23 +08:00
georgehao
f3bd1349a2 Merge branch 'feat/prover_task_unique' of github.com:scroll-tech/scroll into feat/prover_task_unique 2023-08-23 20:02:37 +08:00
georgehao
42cb40745e feat: update 2023-08-23 20:02:22 +08:00
georgehao
8649d23ec1 chore: auto version bump [bot] 2023-08-23 09:29:08 +00:00
georgehao
7255f8098c feat: updatge 2023-08-23 17:28:37 +08:00
georgehao
cee5d37caa chore: auto version bump [bot] 2023-08-23 09:27:24 +00:00
georgehao
4c738d759c feat: update 2023-08-23 17:26:51 +08:00
georgehao
8a70fc8bf3 chore: auto version bump [bot] 2023-08-23 09:25:33 +00:00
georgehao
b6afe29307 Merge branch 'feat/prover_task_unique' of github.com:scroll-tech/scroll into feat/prover_task_unique 2023-08-23 17:24:59 +08:00
georgehao
f33ec93eb6 feat: update 2023-08-23 17:24:35 +08:00
georgehao
d64d646e43 chore: auto version bump [bot] 2023-08-23 09:09:07 +00:00
georgehao
3f678a0f9b Update coordinator/internal/logic/provertask/chunk_prover_task.go
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-23 17:08:45 +08:00
georgehao
5f7de85912 chore: auto version bump [bot] 2023-08-23 04:03:52 +00:00
georgehao
7dcfa17e7c Merge branch 'develop' into feat/prover_task_unique 2023-08-23 12:03:25 +08:00
georgehao
4b3a58aaa5 chore: auto version bump [bot] 2023-08-23 04:01:04 +00:00
georgehao
84bdae3a01 Merge branch 'develop' into feat/prover_task_unique 2023-08-23 12:00:39 +08:00
georgehao
404e44297d chore: auto version bump [bot] 2023-08-23 03:12:41 +00:00
georgehao
93510798d1 feat: update 2023-08-23 11:12:07 +08:00
georgehao
e4e3ca6851 Merge branch 'feat/prover_task_unique' of github.com:scroll-tech/scroll into feat/prover_task_unique 2023-08-23 11:10:50 +08:00
georgehao
2efb82d58e Merge branch 'develop' of github.com:scroll-tech/scroll into feat/prover_task_unique 2023-08-23 11:10:23 +08:00
georgehao
8499b56092 chore: auto version bump [bot] 2023-08-23 03:09:43 +00:00
georgehao
519fc61151 Merge branch 'feat/prover_task_unique' of github.com:scroll-tech/scroll into feat/prover_task_unique 2023-08-23 11:08:59 +08:00
georgehao
c5f2be41be feat: update 2023-08-23 11:08:38 +08:00
georgehao
5a3b91147a chore: auto version bump [bot] 2023-08-22 12:28:38 +00:00
georgehao
7b721a7397 feat: fix conflict 2023-08-22 20:28:09 +08:00
georgehao
e523d61d1a feat: update 2023-08-22 20:27:28 +08:00
georgehao
510a519069 feat: add migrate sql 2023-08-22 16:50:47 +08:00
georgehao
808c68b4be feat: update 2023-08-22 16:27:01 +08:00
georgehao
d0d4b6e4f3 feat: update 2023-08-22 15:49:46 +08:00
georgehao
8c05add1b2 feat: remove debug code 2023-08-22 15:46:08 +08:00
georgehao
edb75c8cb3 Merge branch 'feat/prover_task_unique' of github.com:scroll-tech/scroll into feat/prover_task_unique 2023-08-22 15:43:05 +08:00
georgehao
98135e04e1 feat: update 2023-08-22 15:42:52 +08:00
georgehao
a40e7d1534 chore: auto version bump [bot] 2023-08-22 07:41:49 +00:00
georgehao
2e858a38be feat: fix conflict 2023-08-22 15:41:22 +08:00
georgehao
95e146ab1f feat: updat
e
2023-08-22 15:37:09 +08:00
georgehao
0676f23c02 Merge branch 'feat/prover_task_unique' of github.com:scroll-tech/scroll into feat/prover_task_unique 2023-08-22 15:36:43 +08:00
georgehao
59d9bb25af feat: update uuid generate style 2023-08-22 15:36:31 +08:00
georgehao
965fbcff65 chore: auto version bump [bot] 2023-08-22 04:15:59 +00:00
georgehao
b32b023c50 Merge branch 'develop' into feat/prover_task_unique 2023-08-22 12:15:36 +08:00
georgehao
3df2e0267a chore: auto version bump [bot] 2023-08-22 01:36:52 +00:00
georgehao
ee0351907b feat: update 2023-08-22 09:36:22 +08:00
georgehao
77a3de1646 feat: update 2023-08-21 19:33:51 +08:00
georgehao
49c6e7ded7 feat: update 2023-08-21 19:31:43 +08:00
georgehao
3e8e08dccc trigger ci 2023-08-21 18:47:34 +08:00
georgehao
7bb047aadc feat: update 2023-08-21 18:14:38 +08:00
georgehao
aa2e3dc996 feat: update 2023-08-21 18:11:23 +08:00
georgehao
ab3de62357 feat: update 2023-08-21 18:08:04 +08:00
georgehao
5607d1846f feat: prover get/submit uuid 2023-08-21 18:07:10 +08:00
georgehao
e7bf8b079d feat: update 2023-08-21 17:57:11 +08:00
georgehao
0e12352be3 feat: update 2023-08-21 17:52:01 +08:00
georgehao
e16d50d912 chore: auto version bump [bot] 2023-08-21 09:48:35 +00:00
georgehao
04fe23f95c Merge branch 'develop' into feat/prover_task_unique 2023-08-21 17:48:29 +08:00
georgehao
0a5465a750 feat: update 2023-08-21 17:47:00 +08:00
georgehao
d2f2dae3de feat: make the prover_task to unique 2023-08-21 17:42:51 +08:00
226 changed files with 5216 additions and 4710 deletions

View File

@@ -1,4 +1,4 @@
name: Bump version
name: Bump Version
on:
pull_request:

View File

@@ -132,3 +132,24 @@ jobs:
tags: scrolltech/coordinator:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
prover-stats-api:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push prover-stats-api docker
uses: docker/build-push-action@v2
with:
context: .
file: ./build/dockerfiles/prover-stats-api.Dockerfile
push: true
tags: scrolltech/prover-stats-api:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}

70
.github/workflows/prover_stats_api.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: ProverStatsAPI
on:
push:
branches:
- main
- staging
- develop
- alpha
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
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
View File

@@ -1,6 +1,9 @@
[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

View File

@@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
contributor@scroll.io.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -1,42 +0,0 @@
## Contributing
[fork]: /fork
[pr]: /compare
[style]: https://standardjs.com/
[code-of-conduct]: CODE_OF_CONDUCT.md
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
## Contribute to Scroll
Did you know there are many ways of contributing to Scroll? If you are looking to contribute to by adding Scroll to existing Dev Tools or by doing integrations please go to the [Contribute to Scroll](https://github.com/scroll-tech/contribute-to-scroll) repo instead. If you are looking to contribute to Scroll's Halo2 zkEVM circuits please refer to the [zkEVM circuits](https://github.com/scroll-tech/zkevm-circuits) repo. This repository covers the Scroll infrastructure and smart contracts, if you want to contribute to these areas continue reading this document.
## Issues and PRs
If you have suggestions for how this project could be improved, or want to report a bug, open an issue! We'd love all and any contributions. If you have questions, too, we'd love to hear them.
We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it, though! Look at the links below if you're not sure how to open a PR.
## Submitting a pull request
1. [Fork][fork] and clone the repository.
1. Create a new branch: `git checkout -b my-branch-name`.
1. Make your change, add tests, and make sure the tests still pass.
1. Push to your fork and [submit a pull request][pr].
1. Pat yourself on the back and wait for your pull request to be reviewed and merged.
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
- Write and update tests.
- Keep your changes as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
Work in Progress pull requests are also welcome to get feedback early on, or if there is something that blocked you.
## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
- [GitHub Help](https://help.github.com)

View File

@@ -15,19 +15,16 @@
<pre>
├── <a href="./bridge-history-api/">bridge-history-api</a>: Bridge history service that collects deposit and withdraw events from both L1 and L2 chain and generates withdrawal proofs
├── <a href="./common/">common</a>: Common libraries and types
├── <a href="./coordinator/">coordinator</a>: Prover coordinator service that dispatches proving tasks to provers
├── <a href="./coordinator/">coordinator</a>: Prover coorindator service that dispatches proving tasks to provers
├── <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="./rollup">rollup</a>: Rollup-related services
├── <a href="./prover-stats-api">prover-stats-api</a>: Collect and show prover statistics
├── <a href="./prover-stats-api">rollup</a>: Rollup-related services
├── <a href="./rpc-gateway">rpc-gateway</a>: RPC gateway external repo
└── <a href="./tests">tests</a>: Integration tests
</pre>
## Contributing
We welcome community contributions to this repository. Before you submit any issues or PRs, please read the [Code of Conduct](CODE_OF_CONDUCT.md) and the [Contribution Guideline](CONTRIBUTING.md).
## Prerequisites
+ Go 1.19
+ Rust (for version, see [rust-toolchain](./common/libzkp/impl/rust-toolchain))

View File

@@ -1,82 +1 @@
# 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]
```

View File

@@ -7,13 +7,11 @@ 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"
)
@@ -56,18 +54,13 @@ func action(ctx *cli.Context) error {
router := gin.Default()
controller.InitController(db)
registry := prometheus.DefaultRegisterer
route.Route(router, cfg, registry)
route.Route(router, cfg)
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)

View File

@@ -82,18 +82,6 @@ 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),
@@ -104,18 +92,6 @@ 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)

View File

@@ -1,39 +1,33 @@
{
"batchInfoFetcher": {
"batchIndexStartBlock": 9091265,
"ScrollChainAddr": "0x1799c3Df650caB9DFBb228C971016707D8f8721D"
"ScrollChainAddr": "0xcD00DB804C819175B381b2B44Aa16A391c8a01D6"
},
"l1": {
"confirmation": 64,
"endpoint": "https://rpc.ankr.com/eth",
"startHeight": 18310747,
"endpoint": "https://rpc.ankr.com/eth_goerli",
"startHeight": 9090194 ,
"blockTime": 10,
"MessengerAddr": "0x7318152B19c3c97c886D5ee6C2525E62ce8e2abA",
"ETHGatewayAddr": "0xd165b42d857eae2915625819464a2a1f91E5d0A5",
"WETHGatewayAddr": "0xb0255e4C1a919619D1CafBA51021d638c4F71b89",
"StandardERC20Gateway": "0x00fEc01A9b975bA37466B4E9006dF2C71BFE0e48",
"CustomERC20GatewayAddr": "0xD8874B0E6C3CC43C00B69D60c21Ef452d1159bDe",
"ERC721GatewayAddr": "0x131B46649F6882d686a766cb8b68c4cB0ACdeb24",
"ERC1155GatewayAddr": "0xCeE721789FAA05c7F4463efB664520656aB7C7d5",
"USDCGatewayAddr": "0x37ba659D6CC380D12Fb96567CC52FC8e1DF4E334",
"LIDOGatewayAddr": "0x892dDB2899325aBBA1fD00FDA8249B40Cbbc33F9",
"DAIGatewayAddr": "0xD8dD7787f89c7E6243AD32E0d0cCf460243C8130"
"MessengerAddr": "0x326517Eb8eB1Ce5eaB5b513C2e9A24839b402d90",
"ETHGatewayAddr": "0x8305cB7B8448677736095965B63d7431017328fe",
"WETHGatewayAddr": "0xe3bA3c60d99a2d9a5f817734bC85353470b23931",
"StandardERC20Gateway": "0x16c1079B27eD9c363B7D08aC5Ae937A398972A5C",
"CustomERC20GatewayAddr": "0x61f08caD3d6F77801167d3bA8669433701586643",
"ERC721GatewayAddr": "0x4A73D25A4C99CB912acaf6C5B5e554f2982201c5",
"ERC1155GatewayAddr": "0xa3F5DD3033698c2832C53f3C3Fe6E062F58cD808"
},
"l2": {
"confirmation": 1,
"endpoint": "http://mainnet-l2geth-internal-1.mainnet.scroll.tech:8545",
"endpoint": "http://staging-l2geth-rpc0.scroll.tech:8545",
"blockTime": 3,
"startHeight": 0,
"MessengerAddr": "0xda7c91Ed60DACD28Cb97B180108958c9ACC7698a",
"ETHGatewayAddr": "0x567671187b5FFbcDFe0B6EcF3e56C05508a31A87",
"WETHGatewayAddr": "0x3b03aE2F27d62E0B2b6740CA20Fc07Af4338B791",
"StandardERC20Gateway": "0xb00cb1F6f7C43D2EE8C4e2163a6bEA22441A5B7c",
"CustomERC20GatewayAddr": "0x63CCb38E9d21A72777b203267F2e4ba5C974fC62",
"ERC721GatewayAddr": "0xE2c36a2D8B5528719aE7A42A778b2D08b18d134a",
"ERC1155GatewayAddr": "0xfF14870512e42BFb85a9B7bEfDc06e9aB5A37269",
"USDCGatewayAddr": "0x97D5799CDC8eE2A7452913d7548c7cEE285719FA",
"LIDOGatewayAddr": "0xE9c5C9f67ec7B773fC76440845751F657bb953FF",
"DAIGatewayAddr": "0xC5034eB8F682b73F93C9246aa95A8eBbF82793aA"
"CustomERC20GatewayAddr": "0x905db21f836749fEeD12de781afc4A5Ab4Dd0d51",
"ERC721GatewayAddr": "0xC53D835514780664BCd7eCfcE7c2E5d9554dc41B",
"StandardERC20Gateway": "0x90271634BCB020e06ea4840C3f7aa61b8F860651",
"MessengerAddr": "0xE8b0956Ac75c65Aa1669e83888DA13afF2E108f4",
"ETHGatewayAddr": "0xD5938590D5dD8ce95812D4D515a219C12C551D67",
"WETHGatewayAddr": "0xb0aaA582564fade4232a16fdB1383004A6A7247F",
"ERC1155GatewayAddr": "0x4f33B1655619c2C0B7C450128Df760B4365Cb549"
},
"db": {
"dsn": "postgres://postgres:1234@localhost:5444/test?sslmode=disable",

View File

@@ -31,9 +31,6 @@ 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"`

View File

@@ -3,20 +3,15 @@ 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
)
@@ -25,6 +20,7 @@ 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
@@ -98,6 +94,7 @@ 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
@@ -120,6 +117,7 @@ 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

View File

@@ -119,8 +119,6 @@ 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=
@@ -364,8 +362,6 @@ 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=

View File

@@ -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.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
return
}
result, err := b.batchLogic.GetWithdrawRootByBatchIndex(ctx, req.BatchIndex)
if err != nil {
types.RenderFailure(ctx, types.ErrGetWithdrawRootByBatchIndexFailure, err)
types.RenderJSON(ctx, types.ErrGetWithdrawRootByBatchIndexFailure, err, nil)
return
}
types.RenderSuccess(ctx, result)
types.RenderJSON(ctx, types.Success, nil, result)
}

View File

@@ -10,8 +10,7 @@ var (
// HistoryCtrler is controller instance
HistoryCtrler *HistoryController
// BatchCtrler is controller instance
BatchCtrler *BatchController
BatchCtrler *BatchController
initControllerOnce sync.Once
)

View File

@@ -1,40 +1,23 @@
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(),
}
}
@@ -42,120 +25,48 @@ 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.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
return
}
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
})
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.RenderFailure(ctx, types.ErrGetClaimablesFailure, err)
types.RenderJSON(ctx, types.ErrGetClaimablesFailure, err, nil)
return
}
if resultData, ok := result.(*types.ResultData); ok {
types.RenderSuccess(ctx, resultData)
} else {
log.Error("unexpected type from singleflight", "expected", "*types.ResultData", "got", reflect.TypeOf(result))
types.RenderFailure(ctx, types.ErrGetClaimablesFailure, errors.New("unexpected error"))
types.RenderJSON(ctx, types.Success, nil, &types.ResultData{Result: txs, Total: total})
}
// GetAllTxsByAddr defines the http get method behavior
func (c *HistoryController) GetAllTxsByAddr(ctx *gin.Context) {
var req types.QueryByAddressRequest
if err := ctx.ShouldBind(&req); err != nil {
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
return
}
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)
return
}
types.RenderJSON(ctx, types.Success, nil, &types.ResultData{Result: message, Total: total})
}
// 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.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
types.RenderJSON(ctx, types.ErrParameterInvalidNo, err, nil)
return
}
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"))
result, err := c.historyLogic.GetTxsByHashes(ctx, req.Txs)
if err != nil {
types.RenderJSON(ctx, types.ErrGetTxsByHashFailure, err, nil)
return
}
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)
types.RenderJSON(ctx, types.Success, nil, &types.ResultData{Result: result, Total: 0})
}

View File

@@ -1,40 +0,0 @@
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
}

View File

@@ -23,101 +23,66 @@ func NewHistoryLogic(db *gorm.DB) *HistoryLogic {
return logic
}
// updateL2TxClaimInfo updates UserClaimInfos for each transaction history.
func updateL2TxClaimInfo(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) {
// getCrossTxClaimInfo get UserClaimInfos by address
func getCrossTxClaimInfo(ctx context.Context, msgHash string, db *gorm.DB) *types.UserClaimInfo {
l2SentMsgOrm := orm.NewL2SentMsg(db)
rollupOrm := orm.NewRollupBatch(db)
var l2MsgHashes []string
for _, txHistory := range txHistories {
if !txHistory.IsL1 {
l2MsgHashes = append(l2MsgHashes, txHistory.MsgHash)
}
l2sentMsg, err := l2SentMsgOrm.GetL2SentMsgByHash(ctx, msgHash)
if err != nil || l2sentMsg == nil {
log.Debug("getCrossTxClaimInfo failed", "error", err)
return &types.UserClaimInfo{}
}
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)
batch, err := rollupOrm.GetRollupBatchByIndex(ctx, l2sentMsg.BatchIndex)
if err != nil {
log.Debug("GetRollupBatchesByIndexes failed", "error", err)
return
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),
}
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 updateCrossTxHashes(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) {
msgHashes := make([]string, len(txHistories))
for i, txHistory := range txHistories {
msgHashes[i] = txHistory.MsgHash
}
func updateCrossTxHash(ctx context.Context, msgHash string, txInfo *types.TxHistoryInfo, db *gorm.DB) {
relayed := orm.NewRelayedMsg(db)
relayedMsgs, err := relayed.GetRelayedMsgsByHashes(ctx, msgHashes)
if err != nil || len(relayedMsgs) == 0 {
log.Debug("GetRelayedMsgsByHashes failed", "msg hashes", msgHashes, "relayed msgs", relayedMsgs, "error", err)
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
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) ([]*types.TxHistoryInfo, uint64, error) {
func (h *HistoryLogic) GetClaimableTxsByAddress(ctx context.Context, address common.Address, offset int, limit int) ([]*types.TxHistoryInfo, uint64, error) {
var txHistories []*types.TxHistoryInfo
l2SentMsgOrm := orm.NewL2SentMsg(h.db)
l2CrossMsgOrm := orm.NewCrossMsg(h.db)
results, err := l2SentMsgOrm.GetClaimableL2SentMsgByAddress(ctx, address.Hex())
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)
if err != nil || len(results) == 0 {
return txHistories, 0, err
}
@@ -137,10 +102,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
@@ -152,36 +117,96 @@ func (h *HistoryLogic) GetClaimableTxsByAddress(ctx context.Context, address com
}
txHistories = append(txHistories, txInfo)
}
updateL2TxClaimInfo(ctx, txHistories, h.db)
return txHistories, uint64(len(results)), err
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
}
// 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)
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: ""},
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
}
txHistories = append(txHistories, txHistory)
}
updateCrossTxHashesAndL2TxClaimInfo(ctx, txHistories, h.db)
return txHistories, nil
}

View File

@@ -5,15 +5,13 @@ 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, reg prometheus.Registerer) {
func Route(router *gin.Engine, conf *config.Config) {
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
@@ -22,9 +20,9 @@ func Route(router *gin.Engine, conf *config.Config, reg prometheus.Registerer) {
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)
}

View File

@@ -10,8 +10,6 @@ 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
@@ -26,7 +24,9 @@ const (
// QueryByAddressRequest the request parameter of address api
type QueryByAddressRequest struct {
Address string `form:"address" binding:"required"`
Address string `form:"address" binding:"required"`
Page int `form:"page" binding:"required"`
PageSize int `form:"page_size" binding:"required"`
}
// QueryByHashRequest the request parameter of hash api
@@ -78,7 +78,6 @@ 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"`
@@ -104,28 +103,3 @@ 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)
}

View File

@@ -1,18 +0,0 @@
package observability
import (
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"bridge-history-api/observability/ginmetrics"
)
// Use register the gin metric
func Use(router *gin.Engine, metricsPrefix string, reg prometheus.Registerer) {
m := ginmetrics.GetMonitor(reg)
m.SetMetricPath("/metrics")
m.SetMetricPrefix(metricsPrefix + "_")
m.SetSlowTime(1)
m.SetDuration([]float64{0.025, .05, .1, .5, 1, 5, 10})
m.UseWithoutExposingEndpoint(router)
}

View File

@@ -1,35 +0,0 @@
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)
}

View File

@@ -1,53 +0,0 @@
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)
}
}()
}

View File

@@ -71,16 +71,6 @@ 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 {

View File

@@ -368,14 +368,3 @@ 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
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/ethereum/go-ethereum/log"
@@ -55,19 +54,6 @@ 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
@@ -86,61 +72,26 @@ func (l *L2SentMsg) GetLatestSentMsgHeightOnL2(ctx context.Context) (uint64, err
return result.Height, nil
}
// 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
// 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)
}
return results, nil
}
// 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)
// 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)
}
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
return count, nil
}
// GetLatestL2SentMsgBatchIndex get latest l2 sent msg batch index

View File

@@ -1,77 +0,0 @@
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)
}

View File

@@ -49,19 +49,6 @@ 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

View File

@@ -2,7 +2,6 @@ package utils
import (
"context"
"database/sql"
"fmt"
"time"
@@ -68,29 +67,18 @@ 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.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 sqlDB, nil
return db, nil
}
// CloseDB close the db handler. notice the db handler only can close when then program exit.

View File

@@ -14,6 +14,14 @@ 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

View File

@@ -24,6 +24,7 @@ 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/

View File

@@ -7,6 +7,7 @@ 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/

View File

@@ -7,6 +7,7 @@ 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/

View File

@@ -7,6 +7,7 @@ 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/

View File

@@ -0,0 +1,31 @@
# Download Go dependencies
FROM scrolltech/go-alpine-builder:1.19 as base
WORKDIR /src
COPY go.work* ./
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
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
# Pull prover-stats-api into a second stage deploy alpine container \
FROM alpine:latest
COPY --from=builder /bin/prover-stats-api /bin/
ENTRYPOINT ["prover-stats-api"]

View File

@@ -7,6 +7,7 @@ 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/

View File

@@ -2,7 +2,6 @@ package database
import (
"context"
"database/sql"
"fmt"
"time"
@@ -64,15 +63,17 @@ func InitDB(config *Config) (*gorm.DB, error) {
if err != nil {
return nil, err
}
sqlDB, pingErr := Ping(db)
if pingErr != nil {
return nil, pingErr
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
}
@@ -87,16 +88,3 @@ 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
}

View File

@@ -11,10 +11,6 @@ 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) {
@@ -37,26 +33,3 @@ 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))
}

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ edition = "2021"
crate-type = ["cdylib"]
[patch.crates-io]
ethers-core = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }
ethers-core = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v0.17.0" }
[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,8 +20,9 @@ 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.7", default-features = false, features = ["parallel_syn", "scroll", "shanghai"] }
base64 = "0.13.0"
env_logger = "0.9.0"

View File

@@ -1,8 +0,0 @@
.PHONY: help fmt clippy test test-ci test-all
fmt:
@cargo fmt --all -- --check
clippy:
@cargo check --all-features
@cargo clippy --release -- -D warnings

View File

@@ -1,18 +1,15 @@
use crate::{
types::{CheckChunkProofsResponse, ProofResult},
utils::{
c_char_to_str, c_char_to_vec, file_exists, panic_catch, string_to_c_char, vec_to_c_char,
OUTPUT_DIR,
},
utils::{c_char_to_str, c_char_to_vec, 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, BlockTrace, ChunkHash, ChunkProof,
BatchProof, ChunkHash, ChunkProof,
};
use std::{cell::OnceCell, env, ptr::null};
use std::{cell::OnceCell, env, panic, ptr::null};
use types::eth::BlockTrace;
static mut PROVER: OnceCell<Prover> = OnceCell::new();
static mut VERIFIER: OnceCell<Verifier> = OnceCell::new();
@@ -27,12 +24,6 @@ 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();
@@ -56,7 +47,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(|| PROVER.get_mut().unwrap().get_vk());
let vk_result = panic::catch_unwind(|| PROVER.get_mut().unwrap().get_vk());
vk_result
.ok()
@@ -67,7 +58,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(|| {
let check_result: Result<bool, String> = panic::catch_unwind(|| {
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:?}"))?;
@@ -103,7 +94,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(|| {
let proof_result: Result<Vec<u8>, String> = panic::catch_unwind(|| {
let chunk_hashes = c_char_to_vec(chunk_hashes);
let chunk_proofs = c_char_to_vec(chunk_proofs);
@@ -152,7 +143,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(|| VERIFIER.get().unwrap().verify_agg_evm_proof(proof));
let verified = panic::catch_unwind(|| VERIFIER.get().unwrap().verify_agg_evm_proof(proof));
verified.unwrap_or(false) as c_char
}

View File

@@ -1,18 +1,15 @@
use crate::{
types::ProofResult,
utils::{
c_char_to_str, c_char_to_vec, file_exists, panic_catch, string_to_c_char, vec_to_c_char,
OUTPUT_DIR,
},
utils::{c_char_to_str, c_char_to_vec, 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},
BlockTrace, ChunkProof,
ChunkProof,
};
use std::{cell::OnceCell, env, ptr::null};
use std::{cell::OnceCell, env, panic, ptr::null};
use types::eth::BlockTrace;
static mut PROVER: OnceCell<Prover> = OnceCell::new();
static mut VERIFIER: OnceCell<Verifier> = OnceCell::new();
@@ -27,13 +24,7 @@ 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);
// 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);
let prover = Prover::from_params_dir(params_dir);
PROVER.set(prover).unwrap();
}
@@ -56,7 +47,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(|| PROVER.get_mut().unwrap().get_vk());
let vk_result = panic::catch_unwind(|| PROVER.get_mut().unwrap().get_vk());
vk_result
.ok()
@@ -67,7 +58,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(|| {
let proof_result: Result<Vec<u8>, String> = panic::catch_unwind(|| {
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:?}"))?;
@@ -75,7 +66,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, None, OUTPUT_DIR.as_deref())
.gen_chunk_proof(block_traces, 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:?}"))
@@ -102,6 +93,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(|| VERIFIER.get().unwrap().verify_chunk_proof(proof));
let verified = panic::catch_unwind(|| VERIFIER.get().unwrap().verify_chunk_proof(proof));
verified.unwrap_or(false) as c_char
}

View File

@@ -3,8 +3,6 @@ use std::{
env,
ffi::{CStr, CString},
os::raw::c_char,
panic::{catch_unwind, AssertUnwindSafe},
path::PathBuf,
};
// Only used for debugging.
@@ -28,22 +26,3 @@ 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:?}")
}
})
}

View File

@@ -1,10 +1,10 @@
package observability
package metrics
import (
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"scroll-tech/common/observability/ginmetrics"
"scroll-tech/common/metrics/ginmetrics"
)
// Use register the gin metric

View File

@@ -1,4 +1,4 @@
package observability
package metrics
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, db *gorm.DB) {
func Server(c *cli.Context, reg *prometheus.Registry) {
if !c.Bool(utils.MetricsEnabled.Name) {
return
}
@@ -33,10 +33,6 @@ func Server(c *cli.Context, db *gorm.DB) {
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,

View File

@@ -1,57 +0,0 @@
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
}

View File

@@ -1,89 +0,0 @@
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
}

View File

@@ -1,155 +0,0 @@
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()))
}
}

View File

@@ -1,158 +0,0 @@
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,
)
}

View File

@@ -1,35 +0,0 @@
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)
}

View File

@@ -15,16 +15,9 @@ import (
// CalldataNonZeroByteGas is the gas consumption per non zero byte in calldata.
const CalldataNonZeroByteGas = 16
// GetKeccak256Gas calculates the gas cost for computing the keccak256 hash of a given size.
// GetKeccak256Gas calculates keccak256 hash gas.
func GetKeccak256Gas(size uint64) uint64 {
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
return 30 + 6*((size+31)/32) // 30 + 6 * ceil(size / 32)
}
// WrappedBlock contains the block's Header, Transactions and WithdrawTrieRoot hash.
@@ -138,12 +131,6 @@ 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
}

View File

@@ -46,7 +46,7 @@ func TestChunkEncode(t *testing.T) {
},
}
assert.Equal(t, uint64(0), chunk.NumL1Messages(0))
assert.Equal(t, uint64(6042), chunk.EstimateL1CommitGas())
assert.Equal(t, uint64(6006), 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(5329), chunk.EstimateL1CommitGas())
assert.Equal(t, uint64(5002), 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(10612), chunk.EstimateL1CommitGas())
assert.Equal(t, uint64(9958), chunk.EstimateL1CommitGas())
bytes, err = chunk.Encode(0)
hexString = hex.EncodeToString(bytes)
assert.NoError(t, err)

View File

@@ -103,7 +103,7 @@ const (
ProverTaskFailureTypeUndefined ProverTaskFailureType = iota
// ProverTaskFailureTypeTimeout prover task failure of timeout
ProverTaskFailureTypeTimeout
// ProverTaskFailureTypeSubmitStatusNotOk prover task failure of submit status not ok
// ProverTaskFailureTypeSubmitStatusNotOk prover task failure of validated failed by coordinator
ProverTaskFailureTypeSubmitStatusNotOk
// ProverTaskFailureTypeVerifiedFailed prover task failure of verified failed by coordinator
ProverTaskFailureTypeVerifiedFailed

View File

@@ -3,21 +3,12 @@ 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

View File

@@ -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,omitempty"`
StorageTrace []byte `json:"storage_trace"`
Protocol []byte `json:"protocol"`
Proof []byte `json:"proof"`
Instances []byte `json:"instances"`

View File

@@ -1,53 +0,0 @@
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)
}

View File

@@ -1,6 +1,7 @@
package version
import (
"strconv"
"strings"
)
@@ -19,3 +20,36 @@ 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
}

View File

@@ -5,7 +5,7 @@ import (
"runtime/debug"
)
var tag = "v4.3.35"
var tag = "v4.2.21"
var commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok {

View File

@@ -260,6 +260,23 @@ 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 |
@@ -354,6 +371,22 @@ 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
@@ -530,6 +563,23 @@ 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

View File

@@ -227,6 +227,23 @@ 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 |
@@ -299,6 +316,22 @@ 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
@@ -469,6 +502,23 @@ 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

View File

@@ -93,6 +93,28 @@ 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 |
@@ -161,28 +183,6 @@ 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,6 +239,23 @@ 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
@@ -436,6 +453,22 @@ 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
@@ -609,5 +642,22 @@ 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 |

View File

@@ -225,6 +225,23 @@ 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 |
@@ -275,6 +292,22 @@ 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
@@ -372,5 +405,22 @@ 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 |

View File

@@ -223,6 +223,23 @@ 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 |
@@ -273,6 +290,22 @@ 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
@@ -370,5 +403,22 @@ 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 |

View File

@@ -205,6 +205,23 @@ 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 |
@@ -299,6 +316,22 @@ 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
@@ -455,6 +488,23 @@ 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

View File

@@ -174,6 +174,23 @@ 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 |
@@ -246,6 +263,22 @@ 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
@@ -397,6 +430,23 @@ 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

View File

@@ -70,6 +70,28 @@ 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 |
@@ -99,28 +121,6 @@ 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,6 +155,23 @@ 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
@@ -273,6 +290,22 @@ 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
@@ -446,5 +479,22 @@ 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 |

View File

@@ -139,6 +139,23 @@ 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 |
@@ -206,6 +223,22 @@ 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
@@ -321,6 +354,23 @@ 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

View File

@@ -172,6 +172,23 @@ 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 |
@@ -222,6 +239,22 @@ 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
@@ -337,6 +370,23 @@ 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

View File

@@ -10,38 +10,6 @@ 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
@@ -145,7 +113,7 @@ Import layer 2 genesis block
### initialize
```solidity
function initialize(address _messageQueue, address _verifier, uint256 _maxNumTxInChunk) external nonpayable
function initialize(address _messageQueue, address _verifier, uint256 _maxNumL2TxInChunk) external nonpayable
```
@@ -158,7 +126,7 @@ function initialize(address _messageQueue, address _verifier, uint256 _maxNumTxI
|---|---|---|
| _messageQueue | address | undefined |
| _verifier | address | undefined |
| _maxNumTxInChunk | uint256 | undefined |
| _maxNumL2TxInChunk | uint256 | undefined |
### isBatchFinalized
@@ -260,10 +228,10 @@ The chain id of the corresponding layer 2 chain.
|---|---|---|
| _0 | uint64 | undefined |
### maxNumTxInChunk
### maxNumL2TxInChunk
```solidity
function maxNumTxInChunk() external view returns (uint256)
function maxNumL2TxInChunk() external view returns (uint256)
```
The maximum number of transactions allowed in each chunk.
@@ -311,55 +279,6 @@ 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
@@ -368,7 +287,7 @@ function renounceOwnership() external nonpayable
*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.*
*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.*
### revertBatch
@@ -379,7 +298,7 @@ function revertBatch(bytes _batchHeader, uint256 _count) external nonpayable
Revert a pending batch.
*If the owner want to revert a sequence of batches by sending multiple transactions, make sure to revert recent batches first.*
*one can only revert unfinalized batches.*
#### Parameters
@@ -388,22 +307,6 @@ 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
@@ -420,13 +323,13 @@ function transferOwnership(address newOwner) external nonpayable
|---|---|---|
| newOwner | address | undefined |
### updateMaxNumTxInChunk
### updateMaxNumL2TxInChunk
```solidity
function updateMaxNumTxInChunk(uint256 _maxNumTxInChunk) external nonpayable
function updateMaxNumL2TxInChunk(uint256 _maxNumL2TxInChunk) external nonpayable
```
Update the value of `maxNumTxInChunk`.
Update the value of `maxNumL2TxInChunk`.
@@ -434,7 +337,41 @@ Update the value of `maxNumTxInChunk`.
| Name | Type | Description |
|---|---|---|
| _maxNumTxInChunk | uint256 | The new value of `maxNumTxInChunk`. |
| _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. |
### updateVerifier
@@ -498,7 +435,7 @@ Return the message root of a committed batch.
### CommitBatch
```solidity
event CommitBatch(uint256 indexed batchIndex, bytes32 indexed batchHash)
event CommitBatch(bytes32 indexed batchHash)
```
Emitted when a new batch is committed.
@@ -509,13 +446,12 @@ Emitted when a new batch is committed.
| Name | Type | Description |
|---|---|---|
| batchIndex `indexed` | uint256 | undefined |
| batchHash `indexed` | bytes32 | undefined |
### FinalizeBatch
```solidity
event FinalizeBatch(uint256 indexed batchIndex, bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot)
event FinalizeBatch(bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot)
```
Emitted when a batch is finalized.
@@ -526,27 +462,10 @@ 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
@@ -564,26 +483,10 @@ 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(uint256 indexed batchIndex, bytes32 indexed batchHash)
event RevertBatch(bytes32 indexed batchHash)
```
revert a pending batch.
@@ -594,16 +497,15 @@ revert a pending batch.
| Name | Type | Description |
|---|---|---|
| batchIndex `indexed` | uint256 | undefined |
| batchHash `indexed` | bytes32 | undefined |
### Unpaused
### UpdateMaxNumL2TxInChunk
```solidity
event Unpaused(address account)
event UpdateMaxNumL2TxInChunk(uint256 oldMaxNumL2TxInChunk, uint256 newMaxNumL2TxInChunk)
```
Emitted when the value of `maxNumL2TxInChunk` is updated.
@@ -611,24 +513,8 @@ event Unpaused(address account)
| Name | Type | Description |
|---|---|---|
| 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`. |
| oldMaxNumL2TxInChunk | uint256 | The old value of `maxNumL2TxInChunk`. |
| newMaxNumL2TxInChunk | uint256 | The new value of `maxNumL2TxInChunk`. |
### UpdateProver
@@ -667,7 +553,7 @@ Emitted when owner updates the status of sequencer.
### UpdateVerifier
```solidity
event UpdateVerifier(address indexed oldVerifier, address indexed newVerifier)
event UpdateVerifier(address oldVerifier, address newVerifier)
```
Emitted when the address of rollup verifier is updated.
@@ -678,8 +564,8 @@ Emitted when the address of rollup verifier is updated.
| Name | Type | Description |
|---|---|---|
| oldVerifier `indexed` | address | The address of old rollup verifier. |
| newVerifier `indexed` | address | The address of new rollup verifier. |
| oldVerifier | address | The address of old rollup verifier. |
| newVerifier | address | The address of new rollup verifier. |

View File

@@ -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, 51000, 8, 16);
await oracle.initialize(21000, 0, 8, 16);
const Whitelist = await ethers.getContractFactory("Whitelist", deployer);
const whitelist = await Whitelist.deploy(deployer.address);

View File

@@ -42,7 +42,7 @@ describe("L1MessageQueue", async () => {
deployer
);
await oracle.initialize(21000, 50000, 8, 16);
await oracle.initialize(21000, 0, 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 512 messages
for (let i = 0; i < 256 * 2; i++) {
// append 100 messages
for (let i = 0; i < 100; i++) {
await queue.connect(messenger).appendCrossDomainMessage(constants.AddressZero, 1000000, "0x");
}
@@ -274,8 +274,7 @@ describe("L1MessageQueue", async () => {
.to.emit(queue, "DequeueTransaction")
.withArgs(0, 50, 0);
for (let i = 0; i < 50; i++) {
expect(await queue.isMessageSkipped(i)).to.eq(false);
expect(await queue.isMessageDropped(i)).to.eq(false);
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
}
expect(await queue.pendingQueueIndex()).to.eq(50);
@@ -285,8 +284,7 @@ describe("L1MessageQueue", async () => {
.withArgs(50, 10, 1023);
expect(await queue.pendingQueueIndex()).to.eq(60);
for (let i = 50; i < 60; i++) {
expect(await queue.isMessageSkipped(i)).to.eq(true);
expect(await queue.isMessageDropped(i)).to.eq(false);
expect(BigNumber.from(await queue.getCrossDomainMessage(i))).to.gt(constants.Zero);
}
// pop 20 messages, skip first 5
@@ -295,76 +293,12 @@ describe("L1MessageQueue", async () => {
.withArgs(60, 20, 31);
expect(await queue.pendingQueueIndex()).to.eq(80);
for (let i = 60; i < 65; i++) {
expect(await queue.isMessageSkipped(i)).to.eq(true);
expect(await queue.isMessageDropped(i)).to.eq(false);
expect(BigNumber.from(await queue.getCrossDomainMessage(i))).to.gt(constants.Zero);
}
for (let i = 65; i < 80; i++) {
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);
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
}
});
// @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 () => {
@@ -374,7 +308,7 @@ describe("L1MessageQueue", async () => {
);
});
it("should revert, when drop non-skipped message", async () => {
it("should revert, when drop executed message", async () => {
// append 10 messages
for (let i = 0; i < 10; i++) {
await queue.connect(messenger).appendCrossDomainMessage(constants.AddressZero, 1000000, "0x");
@@ -384,13 +318,14 @@ describe("L1MessageQueue", async () => {
.to.emit(queue, "DequeueTransaction")
.withArgs(0, 5, 0);
for (let i = 0; i < 5; i++) {
expect(await queue.isMessageSkipped(i)).to.eq(false);
expect(await queue.isMessageDropped(i)).to.eq(false);
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
}
expect(await queue.pendingQueueIndex()).to.eq(5);
for (let i = 0; i < 5; i++) {
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("drop non-skipped message");
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith(
"message already dropped or executed"
);
}
// drop pending message
@@ -410,12 +345,9 @@ describe("L1MessageQueue", async () => {
.withArgs(0, 10, 0x3ff);
for (let i = 0; i < 10; i++) {
expect(await queue.isMessageSkipped(i)).to.eq(true);
expect(await queue.isMessageDropped(i)).to.eq(false);
expect(BigNumber.from(await queue.getCrossDomainMessage(i))).to.gt(constants.Zero);
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.emit(queue, "DropTransaction").withArgs(i);
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);
expect(await queue.getCrossDomainMessage(i)).to.eq(constants.HashZero);
}
});
});

View File

@@ -55,8 +55,8 @@
"typescript": "^4.5.2"
},
"dependencies": {
"@openzeppelin/contracts": "^v4.9.3",
"@openzeppelin/contracts-upgradeable": "^v4.9.3"
"@openzeppelin/contracts": "^v4.9.2",
"@openzeppelin/contracts-upgradeable": "^v4.9.2"
},
"lint-staged": {
"*.{js,ts}": "npx eslint --cache --fix",

View File

@@ -17,6 +17,7 @@ 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";
@@ -26,7 +27,7 @@ import {ZkEvmVerifierV1} from "../../src/libraries/verifier/ZkEvmVerifierV1.sol"
contract DeployL1BridgeContracts is Script {
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
uint64 CHAIN_ID_L2 = uint64(vm.envUint("CHAIN_ID_L2"));
uint32 CHAIN_ID_L2 = uint32(vm.envUint("CHAIN_ID_L2"));
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
@@ -55,6 +56,7 @@ contract DeployL1BridgeContracts is Script {
deployL1CustomERC20Gateway();
deployL1ERC721Gateway();
deployL1ERC1155Gateway();
deployL1DAIGateway();
vm.stopBroadcast();
}
@@ -202,6 +204,18 @@ 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(

View File

@@ -1,66 +0,0 @@
// 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)))));
}
}

View File

@@ -15,6 +15,7 @@ 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";
@@ -59,6 +60,7 @@ contract DeployL2BridgeContracts is Script {
deployL2CustomERC20Gateway();
deployL2ERC721Gateway();
deployL2ERC1155Gateway();
deployL2DAIGateway();
vm.stopBroadcast();
}
@@ -96,7 +98,7 @@ contract DeployL2BridgeContracts is Script {
}
address owner = vm.addr(L2_DEPLOYER_PRIVATE_KEY);
L2TxFeeVault feeVault = new L2TxFeeVault(address(owner), L1_TX_FEE_RECIPIENT_ADDR, 10 ether);
L2TxFeeVault feeVault = new L2TxFeeVault(address(owner), L1_TX_FEE_RECIPIENT_ADDR);
logAddress("L2_TX_FEE_VAULT_ADDR", address(feeVault));
}
@@ -199,6 +201,18 @@ 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(

View File

@@ -1,66 +0,0 @@
// 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)))));
}
}

View File

@@ -11,6 +11,7 @@ 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";
@@ -28,6 +29,9 @@ 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");
@@ -40,6 +44,7 @@ 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");
@@ -51,6 +56,7 @@ 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");
@@ -149,12 +155,22 @@ contract InitializeL1BridgeContracts is Script {
L1_SCROLL_MESSENGER_PROXY_ADDR
);
// set WETH gateway in router
// 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
{
address[] memory _tokens = new address[](1);
address[] memory _tokens = new address[](2);
_tokens[0] = L1_WETH_ADDR;
address[] memory _gateways = new address[](1);
_tokens[1] = L1_DAI_ADDR;
address[] memory _gateways = new address[](2);
_gateways[0] = L1_WETH_GATEWAY_PROXY_ADDR;
_gateways[1] = L1_DAI_GATEWAY_PROXY_ADDR;
L1GatewayRouter(L1_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways);
}

View File

@@ -1,275 +0,0 @@
// 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);
}
}

View File

@@ -11,6 +11,7 @@ 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";
@@ -22,6 +23,9 @@ 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");
@@ -30,6 +34,7 @@ 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");
@@ -44,6 +49,7 @@ 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 {
@@ -108,12 +114,22 @@ contract InitializeL2BridgeContracts is Script {
L2_SCROLL_MESSENGER_PROXY_ADDR
);
// set WETH gateway in router
// 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
{
address[] memory _tokens = new address[](1);
address[] memory _tokens = new address[](2);
_tokens[0] = L2_WETH_ADDR;
address[] memory _gateways = new address[](1);
_tokens[1] = L2_DAI_ADDR;
address[] memory _gateways = new address[](2);
_gateways[0] = L2_WETH_GATEWAY_PROXY_ADDR;
_gateways[1] = L2_DAI_GATEWAY_PROXY_ADDR;
L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways);
}

View File

@@ -1,228 +0,0 @@
// 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);
}
}

View File

@@ -2,7 +2,6 @@
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";

View File

@@ -13,7 +13,6 @@ 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
@@ -42,8 +41,8 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
* Variables *
*************/
/// @notice Mapping from L1 message hash to the timestamp when the message is sent.
mapping(bytes32 => uint256) public messageSendTimestamp;
/// @notice Mapping from L1 message hash to sent status.
mapping(bytes32 => bool) public isL1MessageSent;
/// @notice Mapping from L2 message hash to a boolean value indicating if the message has been successfully executed.
mapping(bytes32 => bool) public isL2MessageExecuted;
@@ -115,7 +114,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
bytes memory _message,
uint256 _gasLimit
) external payable override whenNotPaused {
_sendMessage(_to, _value, _message, _gasLimit, _msgSender());
_sendMessage(_to, _value, _message, _gasLimit, msg.sender);
}
/// @inheritdoc IScrollMessenger
@@ -190,7 +189,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_from, _to, _value, _messageNonce, _message);
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
require(messageSendTimestamp[_xDomainCalldataHash] > 0, "Provided message has not been enqueued");
require(isL1MessageSent[_xDomainCalldataHash], "Provided message has not been enqueued");
// cannot replay dropped message
require(!isL1MessageDropped[_xDomainCalldataHash], "Message already dropped");
@@ -262,7 +261,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
// check message exists
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_from, _to, _value, _messageNonce, _message);
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
require(messageSendTimestamp[_xDomainCalldataHash] > 0, "Provided message has not been enqueued");
require(isL1MessageSent[_xDomainCalldataHash], "Provided message has not been enqueued");
// check message not dropped
require(!isL1MessageDropped[_xDomainCalldataHash], "Message already dropped");
@@ -316,12 +315,14 @@ 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(_msgSender(), _to, _value, _messageNonce, _message);
bytes memory _xDomainCalldata = _encodeXDomainCalldata(msg.sender, _to, _value, _messageNonce, _message);
// compute and deduct the messaging fee to fee vault.
uint256 _fee = IL1MessageQueue(_messageQueue).estimateCrossDomainMessageFee(_gasLimit);
@@ -338,10 +339,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(messageSendTimestamp[_xDomainCalldataHash] == 0, "Duplicated message");
messageSendTimestamp[_xDomainCalldataHash] = block.timestamp;
require(!isL1MessageSent[_xDomainCalldataHash], "Duplicated message");
isL1MessageSent[_xDomainCalldataHash] = true;
emit SentMessage(_msgSender(), _to, _value, _messageNonce, _gasLimit, _message);
emit SentMessage(msg.sender, _to, _value, _messageNonce, _gasLimit, _message);
// refund fee to `_refundAddress`
unchecked {

View File

@@ -1,134 +0,0 @@
// 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);
}
}
}

View File

@@ -66,7 +66,7 @@ contract L1ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC
uint256 _amount,
uint256 _gasLimit
) external payable override {
_depositERC1155(_token, _msgSender(), _tokenId, _amount, _gasLimit);
_depositERC1155(_token, msg.sender, _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, _msgSender(), _tokenIds, _amounts, _gasLimit);
_batchDepositERC1155(_token, msg.sender, _tokenIds, _amounts, _gasLimit);
}
/// @inheritdoc IL1ERC1155Gateway
@@ -198,21 +198,19 @@ 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(_sender, address(this), _tokenId, _amount, "");
IERC1155Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId, _amount, "");
// 2. Generate message passed to L2ERC1155Gateway.
bytes memory _message = abi.encodeCall(
IL2ERC1155Gateway.finalizeDepositERC1155,
(_token, _l2Token, _sender, _to, _tokenId, _amount)
(_token, _l2Token, msg.sender, _to, _tokenId, _amount)
);
// 3. Send message to L1ScrollMessenger.
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
emit DepositERC1155(_token, _l2Token, _sender, _to, _tokenId, _amount);
emit DepositERC1155(_token, _l2Token, msg.sender, _to, _tokenId, _amount);
}
/// @dev Internal function to batch deposit ERC1155 NFT to layer 2.
@@ -238,20 +236,18 @@ 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(_sender, address(this), _tokenIds, _amounts, "");
IERC1155Upgradeable(_token).safeBatchTransferFrom(msg.sender, address(this), _tokenIds, _amounts, "");
// 2. Generate message passed to L2ERC1155Gateway.
bytes memory _message = abi.encodeCall(
IL2ERC1155Gateway.finalizeBatchDepositERC1155,
(_token, _l2Token, _sender, _to, _tokenIds, _amounts)
(_token, _l2Token, msg.sender, _to, _tokenIds, _amounts)
);
// 3. Send message to L1ScrollMessenger.
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
emit BatchDepositERC1155(_token, _l2Token, _sender, _to, _tokenIds, _amounts);
emit BatchDepositERC1155(_token, _l2Token, msg.sender, _to, _tokenIds, _amounts);
}
}

View File

@@ -9,12 +9,11 @@ import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
import {IL1GatewayRouter} from "./IL1GatewayRouter.sol";
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
import {IScrollMessenger} from "../../libraries/IScrollMessenger.sol";
import {ScrollConstants} from "../../libraries/constants/ScrollConstants.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;
@@ -35,7 +34,7 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
uint256 _amount,
uint256 _gasLimit
) external payable override {
_deposit(_token, _msgSender(), _amount, new bytes(0), _gasLimit);
_deposit(_token, msg.sender, _amount, new bytes(0), _gasLimit);
}
/// @inheritdoc IL1ERC20Gateway
@@ -144,12 +143,11 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
bytes memory
)
{
address _sender = _msgSender();
address _from = _sender;
if (router == _sender) {
address _from = msg.sender;
if (router == msg.sender) {
// Extract real sender if this call is from L1GatewayRouter.
(_from, _data) = abi.decode(_data, (address, bytes));
_amount = IL1GatewayRouter(_sender).requestERC20(_from, _token, _amount);
_amount = IL1GatewayRouter(msg.sender).requestERC20(_from, _token, _amount);
} else {
// common practice to handle fee on transfer token.
uint256 _before = IERC20Upgradeable(_token).balanceOf(address(this));
@@ -161,6 +159,9 @@ 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);
}

View File

@@ -64,7 +64,7 @@ contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC72
uint256 _tokenId,
uint256 _gasLimit
) external payable override {
_depositERC721(_token, _msgSender(), _tokenId, _gasLimit);
_depositERC721(_token, msg.sender, _tokenId, _gasLimit);
}
/// @inheritdoc IL1ERC721Gateway
@@ -83,7 +83,7 @@ contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC72
uint256[] calldata _tokenIds,
uint256 _gasLimit
) external payable override {
_batchDepositERC721(_token, _msgSender(), _tokenIds, _gasLimit);
_batchDepositERC721(_token, msg.sender, _tokenIds, _gasLimit);
}
/// @inheritdoc IL1ERC721Gateway
@@ -190,21 +190,19 @@ 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(_sender, address(this), _tokenId);
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId);
// 2. Generate message passed to L2ERC721Gateway.
bytes memory _message = abi.encodeCall(
IL2ERC721Gateway.finalizeDepositERC721,
(_token, _l2Token, _sender, _to, _tokenId)
(_token, _l2Token, msg.sender, _to, _tokenId)
);
// 3. Send message to L1ScrollMessenger.
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
emit DepositERC721(_token, _l2Token, _sender, _to, _tokenId);
emit DepositERC721(_token, _l2Token, msg.sender, _to, _tokenId);
}
/// @dev Internal function to batch deposit ERC721 NFT to layer 2.
@@ -223,22 +221,20 @@ 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(_sender, address(this), _tokenIds[i]);
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenIds[i]);
}
// 2. Generate message passed to L2ERC721Gateway.
bytes memory _message = abi.encodeCall(
IL2ERC721Gateway.finalizeBatchDepositERC721,
(_token, _l2Token, _sender, _to, _tokenIds)
(_token, _l2Token, msg.sender, _to, _tokenIds)
);
// 3. Send message to L1ScrollMessenger.
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _sender);
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, msg.sender);
emit BatchDepositERC721(_token, _l2Token, _sender, _to, _tokenIds);
emit BatchDepositERC721(_token, _l2Token, msg.sender, _to, _tokenIds);
}
}

View File

@@ -44,7 +44,7 @@ contract L1ETHGateway is ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback
/// @inheritdoc IL1ETHGateway
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
_deposit(_msgSender(), _amount, new bytes(0), _gasLimit);
_deposit(msg.sender, _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 = _msgSender();
if (router == _from) {
address _from = msg.sender;
if (router == msg.sender) {
(_from, _data) = abi.decode(_data, (address, bytes));
}

View File

@@ -45,7 +45,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
}
modifier onlyInContext() {
require(_msgSender() == gatewayInContext, "Only in deposit context");
require(msg.sender == gatewayInContext, "Only in deposit context");
_;
}
@@ -110,10 +110,9 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
address _token,
uint256 _amount
) external onlyInContext returns (uint256) {
address _caller = _msgSender();
uint256 _balance = IERC20Upgradeable(_token).balanceOf(_caller);
IERC20Upgradeable(_token).safeTransferFrom(_sender, _caller, _amount);
_amount = IERC20Upgradeable(_token).balanceOf(_caller) - _balance;
uint256 _balance = IERC20Upgradeable(_token).balanceOf(msg.sender);
IERC20Upgradeable(_token).safeTransferFrom(_sender, msg.sender, _amount);
_amount = IERC20Upgradeable(_token).balanceOf(msg.sender) - _balance;
return _amount;
}
@@ -127,7 +126,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
uint256 _amount,
uint256 _gasLimit
) external payable override {
depositERC20AndCall(_token, _msgSender(), _amount, new bytes(0), _gasLimit);
depositERC20AndCall(_token, msg.sender, _amount, new bytes(0), _gasLimit);
}
/// @inheritdoc IL1ERC20Gateway
@@ -155,7 +154,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
gatewayInContext = _gateway;
// encode msg.sender with _data
bytes memory _routerData = abi.encode(_msgSender(), _data);
bytes memory _routerData = abi.encode(msg.sender, _data);
IL1ERC20Gateway(_gateway).depositERC20AndCall{value: msg.value}(_token, _to, _amount, _routerData, _gasLimit);
@@ -181,7 +180,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
/// @inheritdoc IL1ETHGateway
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
depositETHAndCall(_msgSender(), _amount, new bytes(0), _gasLimit);
depositETHAndCall(msg.sender, _amount, new bytes(0), _gasLimit);
}
/// @inheritdoc IL1ETHGateway
@@ -204,7 +203,7 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
require(_gateway != address(0), "eth gateway available");
// encode msg.sender with _data
bytes memory _routerData = abi.encode(_msgSender(), _data);
bytes memory _routerData = abi.encode(msg.sender, _data);
IL1ETHGateway(_gateway).depositETHAndCall{value: msg.value}(_to, _amount, _routerData, _gasLimit);
}

View File

@@ -54,7 +54,7 @@ contract L1WETHGateway is L1ERC20Gateway {
}
receive() external payable {
require(_msgSender() == WETH, "only WETH");
require(msg.sender == WETH, "only WETH");
}
/*************************

View File

@@ -2,6 +2,9 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IFiatToken} from "../../../interfaces/IFiatToken.sol";
import {IUSDCBurnableSourceBridge} from "../../../interfaces/IUSDCBurnableSourceBridge.sol";
import {IL2ERC20Gateway} from "../../../L2/gateways/IL2ERC20Gateway.sol";
@@ -84,7 +87,7 @@ contract L1USDCGateway is L1ERC20Gateway, IUSDCBurnableSourceBridge {
/// @inheritdoc IUSDCBurnableSourceBridge
function burnAllLockedUSDC() external override {
require(_msgSender() == circleCaller, "only circle caller");
require(msg.sender == circleCaller, "only circle caller");
// @note Only bridged USDC will be burned. We may refund the rest if possible.
uint256 _balance = totalBridgedUSDC;

View File

@@ -72,14 +72,6 @@ interface IL1MessageQueue {
bytes calldata data
) external view returns (bytes32);
/// @notice Return whether the message is skipped.
/// @param queueIndex The queue index of the message to check.
function isMessageSkipped(uint256 queueIndex) external view returns (bool);
/// @notice Return whether the message is dropped.
/// @param queueIndex The queue index of the message to check.
function isMessageDropped(uint256 queueIndex) external view returns (bool);
/*****************************
* Public Mutating Functions *
*****************************/

View File

@@ -3,7 +3,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {BitMapsUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/structs/BitMapsUpgradeable.sol";
import {IL2GasPriceOracle} from "./IL2GasPriceOracle.sol";
import {IL1MessageQueue} from "./IL1MessageQueue.sol";
@@ -18,8 +17,6 @@ import {AddressAliasHelper} from "../../libraries/common/AddressAliasHelper.sol"
/// @notice This contract will hold all L1 to L2 messages.
/// Each appended message is assigned with a unique and increasing `uint256` index.
contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
using BitMapsUpgradeable for BitMapsUpgradeable.BitMap;
/**********
* Events *
**********/
@@ -64,18 +61,12 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
/// @notice The max gas limit of L1 transactions.
uint256 public maxGasLimit;
/// @dev The bitmap for dropped messages, where `droppedMessageBitmap[i]` keeps the bits from `[i*256, (i+1)*256)`.
BitMapsUpgradeable.BitMap private droppedMessageBitmap;
/// @dev The bitmap for skipped messages, where `skippedMessageBitmap[i]` keeps the bits from `[i*256, (i+1)*256)`.
mapping(uint256 => uint256) private skippedMessageBitmap;
/**********************
* Function Modifiers *
**********************/
modifier onlyMessenger() {
require(_msgSender() == messenger, "Only callable by the L1ScrollMessenger");
require(msg.sender == messenger, "Only callable by the L1ScrollMessenger");
_;
}
@@ -265,19 +256,6 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
return hash;
}
/// @inheritdoc IL1MessageQueue
function isMessageSkipped(uint256 _queueIndex) external view returns (bool) {
if (_queueIndex >= pendingQueueIndex) return false;
return _isMessageSkipped(_queueIndex);
}
/// @inheritdoc IL1MessageQueue
function isMessageDropped(uint256 _queueIndex) external view returns (bool) {
// it should be a skipped message first.
return _isMessageSkipped(_queueIndex) && droppedMessageBitmap.get(_queueIndex);
}
/*****************************
* Public Mutating Functions *
*****************************/
@@ -292,7 +270,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
_validateGasLimit(_gasLimit, _data);
// do address alias to avoid replay attack in L2.
address _sender = AddressAliasHelper.applyL1ToL2Alias(_msgSender());
address _sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
_queueTransaction(_sender, _target, 0, _gasLimit, _data);
}
@@ -305,7 +283,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
uint256 _gasLimit,
bytes calldata _data
) external override {
require(_msgSender() == enforcedTxGateway, "Only callable by the EnforcedTxGateway");
require(msg.sender == enforcedTxGateway, "Only callable by the EnforcedTxGateway");
// We will check it in EnforcedTxGateway, just in case.
require(_sender.code.length == 0, "only EOA");
@@ -321,21 +299,16 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
uint256 _count,
uint256 _skippedBitmap
) external {
require(_msgSender() == scrollChain, "Only callable by the ScrollChain");
require(msg.sender == scrollChain, "Only callable by the ScrollChain");
require(_count <= 256, "pop too many messages");
require(pendingQueueIndex == _startIndex, "start index mismatch");
unchecked {
// clear extra bits in `_skippedBitmap`, and if _count = 256, it's designed to overflow.
uint256 mask = (1 << _count) - 1;
_skippedBitmap &= mask;
uint256 bucket = _startIndex >> 8;
uint256 offset = _startIndex & 0xff;
skippedMessageBitmap[bucket] |= _skippedBitmap << offset;
if (offset + _count > 256) {
skippedMessageBitmap[bucket + 1] = _skippedBitmap >> (256 - offset);
for (uint256 i = 0; i < _count; i++) {
if ((_skippedBitmap >> i) & 1 == 0) {
messageQueue[_startIndex + i] = bytes32(0);
}
}
pendingQueueIndex = _startIndex + _count;
@@ -347,10 +320,9 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
/// @inheritdoc IL1MessageQueue
function dropCrossDomainMessage(uint256 _index) external onlyMessenger {
require(_index < pendingQueueIndex, "cannot drop pending message");
require(messageQueue[_index] != bytes32(0), "message already dropped or executed");
require(_isMessageSkipped(_index), "drop non-skipped message");
require(!droppedMessageBitmap.get(_index), "message already dropped");
droppedMessageBitmap.set(_index);
messageQueue[_index] = bytes32(0);
emit DropTransaction(_index);
}
@@ -421,11 +393,4 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
uint256 intrinsicGas = calculateIntrinsicGasFee(_calldata);
require(_gasLimit >= intrinsicGas, "Insufficient gas limit, must be above intrinsic gas");
}
/// @dev Returns whether the bit at `index` is set.
function _isMessageSkipped(uint256 index) internal view returns (bool) {
uint256 bucket = index >> 8;
uint256 mask = 1 << (index & 0xff);
return skippedMessageBitmap[bucket] & mask != 0;
}
}

View File

@@ -8,8 +8,6 @@ import {IWhitelist} from "../../libraries/common/IWhitelist.sol";
import {IL2GasPriceOracle} from "./IL2GasPriceOracle.sol";
// solhint-disable reason-string
contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
/**********
* Events *
@@ -43,13 +41,9 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
IWhitelist public whitelist;
struct IntrinsicParams {
// The intrinsic gas for transaction.
uint64 txGas;
// The intrinsic gas for contract creation. It is reserved for future use.
uint64 txGasContractCreation;
// The intrinsic gas for each zero byte.
uint64 zeroGas;
// The intrinsic gas for each nonzero byte.
uint64 nonZeroGas;
}
@@ -72,7 +66,12 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
) external initializer {
OwnableUpgradeable.__Ownable_init();
_setIntrinsicParams(_txGas, _txGasContractCreation, _zeroGas, _nonZeroGas);
intrinsicParams = IntrinsicParams({
txGas: _txGas,
txGasContractCreation: _txGasContractCreation,
zeroGas: _zeroGas,
nonZeroGas: _nonZeroGas
});
}
/*************************
@@ -108,10 +107,33 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
* Public Mutating Functions *
*****************************/
/// @notice Allows whitelisted caller to modify the l2 base fee.
/// @notice Allows the owner to update parameters for intrinsic gas calculation.
/// @param _txGas The intrinsic gas for transaction.
/// @param _txGasContractCreation The intrinsic gas for contract creation.
/// @param _zeroGas The intrinsic gas for each zero byte.
/// @param _nonZeroGas The intrinsic gas for each nonzero byte.
function setIntrinsicParams(
uint64 _txGas,
uint64 _txGasContractCreation,
uint64 _zeroGas,
uint64 _nonZeroGas
) public {
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
intrinsicParams = IntrinsicParams({
txGas: _txGas,
txGasContractCreation: _txGasContractCreation,
zeroGas: _zeroGas,
nonZeroGas: _nonZeroGas
});
emit IntrinsicParamsUpdated(_txGas, _txGasContractCreation, _zeroGas, _nonZeroGas);
}
/// @notice Allows the owner to modify the l2 base fee.
/// @param _newL2BaseFee The new l2 base fee.
function setL2BaseFee(uint256 _newL2BaseFee) external {
require(whitelist.isSenderAllowed(_msgSender()), "Not whitelisted sender");
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
uint256 _oldL2BaseFee = l2BaseFee;
l2BaseFee = _newL2BaseFee;
@@ -132,48 +154,4 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
whitelist = IWhitelist(_newWhitelist);
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
}
/// @notice Allows the owner to update parameters for intrinsic gas calculation.
/// @param _txGas The intrinsic gas for transaction.
/// @param _txGasContractCreation The intrinsic gas for contract creation.
/// @param _zeroGas The intrinsic gas for each zero byte.
/// @param _nonZeroGas The intrinsic gas for each nonzero byte.
function setIntrinsicParams(
uint64 _txGas,
uint64 _txGasContractCreation,
uint64 _zeroGas,
uint64 _nonZeroGas
) external onlyOwner {
_setIntrinsicParams(_txGas, _txGasContractCreation, _zeroGas, _nonZeroGas);
}
/**********************
* Internal Functions *
**********************/
/// @dev Internal function to update parameters for intrinsic gas calculation.
/// @param _txGas The intrinsic gas for transaction.
/// @param _txGasContractCreation The intrinsic gas for contract creation.
/// @param _zeroGas The intrinsic gas for each zero byte.
/// @param _nonZeroGas The intrinsic gas for each nonzero byte.
function _setIntrinsicParams(
uint64 _txGas,
uint64 _txGasContractCreation,
uint64 _zeroGas,
uint64 _nonZeroGas
) internal {
require(_txGas > 0, "txGas is zero");
require(_zeroGas > 0, "zeroGas is zero");
require(_nonZeroGas > 0, "nonZeroGas is zero");
require(_txGasContractCreation > _txGas, "txGasContractCreation is less than txGas");
intrinsicParams = IntrinsicParams({
txGas: _txGas,
txGasContractCreation: _txGasContractCreation,
zeroGas: _zeroGas,
nonZeroGas: _nonZeroGas
});
emit IntrinsicParamsUpdated(_txGas, _txGasContractCreation, _zeroGas, _nonZeroGas);
}
}

View File

@@ -85,12 +85,12 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
modifier OnlySequencer() {
// @note In the decentralized mode, it should be only called by a list of validator.
require(isSequencer[_msgSender()], "caller not sequencer");
require(isSequencer[msg.sender], "caller not sequencer");
_;
}
modifier OnlyProver() {
require(isProver[_msgSender()], "caller not prover");
require(isProver[msg.sender], "caller not prover");
_;
}

Some files were not shown because too many files have changed in this diff Show More