Compare commits

...

22 Commits

Author SHA1 Message Date
Ho
7de388ef1a [Fix] Accept proof submission even it has been timeout (#1764) 2025-12-12 12:18:34 +09:00
Morty
27dd62eac3 feat(rollup-relayer): add blob fee tolerance (#1773) 2025-12-03 21:49:17 +08:00
Ho
22479a7952 [Feat] Galileo v2 (#1771)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2025-12-02 11:04:57 +01:00
Péter Garamvölgyi
690bc01c41 feat: force commit batches at hardfork boundary (#1768) 2025-11-30 20:36:53 +01:00
Péter Garamvölgyi
e75d6c16a9 feat: propose chunk at hardfork boundary (#1767) 2025-11-28 17:21:51 +01:00
Péter Garamvölgyi
752e4e1117 fix: Fix blob fee overflow on rollup-relayer and gas-oracle (#1772) 2025-11-28 15:44:37 +01:00
georgehao
2ecc42e2f5 Return when total < request page (#1766) 2025-11-25 23:36:40 +08:00
georgehao
de72e2dccb remove unused check (#1765) 2025-11-25 22:12:16 +08:00
georgehao
edb51236e2 bump version (#1763) 2025-11-25 21:00:57 +08:00
georgehao
15a23478d1 fix bridge history GetL2UnclaimedWithdrawalsByAddress (#1760)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2025-11-25 20:59:31 +08:00
Morty
9100a0bd4a fix: ci lint (#1762) 2025-11-25 17:45:05 +08:00
Morty
0ede0cd41f feat(blob-uploader): upload blob once proposed (#1759)
Co-authored-by: yiweichi <yiweichi@users.noreply.github.com>
2025-11-25 14:07:08 +08:00
Ho
9dceae1ca2 [Feat] Galileo forking (#1753)
Co-authored-by: Rohit Narurkar <rohit.narurkar@proton.me>
2025-11-24 17:37:04 +08:00
georgehao
235ba874c6 Update Galileo Dependency (#1752) 2025-11-17 18:18:48 +08:00
Zhang Zhuo
6bee33036f feat: the CLOAK privacy solution (#1737)
Co-authored-by: Ho <fan@scroll.io>
Co-authored-by: Rohit Narurkar <rohit.narurkar@proton.me>
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2025-11-14 15:00:37 +01:00
Ho
1985e54ab3 [Feat] For prover 4.6.1 (#1742) 2025-10-24 16:18:40 +09:00
Péter Garamvölgyi
bfc0fdd7ce feat: support Fusaka blob type (#1746)
Co-authored-by: jonastheis <jonastheis@users.noreply.github.com>
Co-authored-by: jonastheis <4181434+jonastheis@users.noreply.github.com>
2025-10-18 08:52:29 +02:00
Jonas Theis
426c57a5fa feat(l2 relayer): enhance batch submission strategy based on backlog size (#1745) 2025-10-17 09:06:53 +08:00
Péter Garamvölgyi
b7fdf48c30 ci: Do not push latest tag on Docker images (#1744) 2025-09-30 08:40:49 +02:00
johnsonjie
ad0c918944 update prover image cuda version (#1741) 2025-09-24 09:42:19 +08:00
Ho
1098876183 [Feat] Update zkvm to 0.6 (use openvm 1.4) (#1736) 2025-09-19 10:29:13 +09:00
Jonas Theis
9e520e7769 feat(tx sender): add multiple write clients for more reliable tx submission (#1740) 2025-09-19 08:56:01 +08:00
126 changed files with 4843 additions and 13143 deletions

View File

@@ -29,7 +29,7 @@ jobs:
steps: steps:
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: nightly-2025-02-14 toolchain: nightly-2025-08-18
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Install Go - name: Install Go

View File

@@ -33,7 +33,7 @@ jobs:
steps: steps:
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: nightly-2025-02-14 toolchain: nightly-2025-08-18
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Install Go - name: Install Go

View File

@@ -51,9 +51,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
rollup_relayer: rollup_relayer:
runs-on: runs-on:
@@ -97,9 +95,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
blob_uploader: blob_uploader:
runs-on: runs-on:
@@ -143,9 +139,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
rollup-db-cli: rollup-db-cli:
runs-on: runs-on:
@@ -189,9 +183,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
bridgehistoryapi-fetcher: bridgehistoryapi-fetcher:
runs-on: runs-on:
@@ -235,9 +227,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
bridgehistoryapi-api: bridgehistoryapi-api:
runs-on: runs-on:
@@ -281,9 +271,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
bridgehistoryapi-db-cli: bridgehistoryapi-db-cli:
runs-on: runs-on:
@@ -327,9 +315,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
coordinator-api: coordinator-api:
runs-on: runs-on:
@@ -372,9 +358,7 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
coordinator-cron: coordinator-cron:
runs-on: runs-on:
@@ -418,6 +402,4 @@ jobs:
push: true push: true
tags: | tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest

View File

@@ -22,11 +22,9 @@ on:
required: true required: true
type: choice type: choice
options: options:
- nightly-2023-12-03
- nightly-2022-12-10
- 1.86.0 - 1.86.0
- nightly-2025-02-14 - nightly-2025-08-18
default: "nightly-2023-12-03" default: "nightly-2025-08-18"
PYTHON_VERSION: PYTHON_VERSION:
description: "Python version" description: "Python version"
required: false required: false
@@ -41,7 +39,8 @@ on:
options: options:
- "11.7.1" - "11.7.1"
- "12.2.2" - "12.2.2"
default: "11.7.1" - "12.9.1"
default: "12.9.1"
CARGO_CHEF_TAG: CARGO_CHEF_TAG:
description: "Cargo chef version" description: "Cargo chef version"
required: true required: true

2820
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,15 +14,16 @@ edition = "2021"
homepage = "https://scroll.io" homepage = "https://scroll.io"
readme = "README.md" readme = "README.md"
repository = "https://github.com/scroll-tech/scroll" repository = "https://github.com/scroll-tech/scroll"
version = "4.5.8" version = "4.7.1"
[workspace.dependencies] [workspace.dependencies]
scroll-zkvm-prover = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "ad0efe7" } scroll-zkvm-prover = { git = "https://github.com/scroll-tech/zkvm-prover", tag = "v0.7.1" }
scroll-zkvm-verifier = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "ad0efe7" } scroll-zkvm-verifier = { git = "https://github.com/scroll-tech/zkvm-prover", tag = "v0.7.1" }
scroll-zkvm-types = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "ad0efe7" } scroll-zkvm-types = { git = "https://github.com/scroll-tech/zkvm-prover", tag = "v0.7.1" }
sbv-primitives = { git = "https://github.com/scroll-tech/stateless-block-verifier", branch = "chore/openvm-1.3", features = ["scroll"] } sbv-primitives = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2", features = ["scroll", "rkyv"] }
sbv-utils = { git = "https://github.com/scroll-tech/stateless-block-verifier", branch = "chore/openvm-1.3" } sbv-utils = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2" }
sbv-core = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2", features = ["scroll"] }
metrics = "0.23.0" metrics = "0.23.0"
metrics-util = "0.17" metrics-util = "0.17"
@@ -30,14 +31,14 @@ metrics-tracing-context = "0.16.0"
anyhow = "1.0" anyhow = "1.0"
alloy = { version = "1", default-features = false } alloy = { version = "1", default-features = false }
alloy-primitives = { version = "1.2", default-features = false, features = ["tiny-keccak"] } alloy-primitives = { version = "1.4.1", default-features = false, features = ["tiny-keccak"] }
# also use this to trigger "serde" feature for primitives # also use this to trigger "serde" feature for primitives
alloy-serde = { version = "1", default-features = false } alloy-serde = { version = "1", default-features = false }
serde = { version = "1", default-features = false, features = ["derive"] } serde = { version = "1", default-features = false, features = ["derive"] }
serde_json = { version = "1.0" } serde_json = { version = "1.0" }
serde_derive = "1.0" serde_derive = "1.0"
serde_with = "3.11.0" serde_with = "3"
itertools = "0.14" itertools = "0.14"
tiny-keccak = "2.0" tiny-keccak = "2.0"
tracing = "0.1" tracing = "0.1"
@@ -45,22 +46,20 @@ eyre = "0.6"
once_cell = "1.20" once_cell = "1.20"
base64 = "0.22" base64 = "0.22"
[patch.crates-io]
revm = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-bytecode = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-context = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-context-interface = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-database = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-database-interface = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-handler = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-inspector = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-interpreter = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-precompile = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-primitives = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
revm-state = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v78" }
ruint = { git = "https://github.com/scroll-tech/uint.git", branch = "v1.15.0" } [patch.crates-io]
alloy-primitives = { git = "https://github.com/scroll-tech/alloy-core", branch = "v1.2.0" } revm = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-bytecode = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-context = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-context-interface = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-database = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-database-interface = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-handler = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-inspector = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-interpreter = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-precompile = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-primitives = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
revm-state = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" }
[profile.maxperf] [profile.maxperf]
inherits = "release" inherits = "release"

View File

@@ -1,6 +1,6 @@
.PHONY: fmt dev_docker build_test_docker run_test_docker clean update .PHONY: fmt dev_docker build_test_docker run_test_docker clean update
L2GETH_TAG=scroll-v5.8.23 L2GETH_TAG=scroll-v5.9.17
help: ## Display this help message help: ## Display this help message
@grep -h \ @grep -h \

View File

@@ -10,15 +10,18 @@ require (
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5
github.com/pressly/goose/v3 v3.16.0 github.com/pressly/goose/v3 v3.16.0
github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_golang v1.19.0
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 github.com/scroll-tech/da-codec v0.10.0
github.com/scroll-tech/go-ethereum v1.10.14-0.20250729113104-bd8f141bb3e9 github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.25.7 github.com/urfave/cli/v2 v2.25.7
golang.org/x/sync v0.11.0 golang.org/x/sync v0.11.0
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde
) )
replace github.com/scroll-tech/go-ethereum => github.com/scroll-tech/go-ethereum v1.10.14-0.20250729113104-bd8f141bb3e9 // It's a hotfix for the header hash incompatibility issue, pls change this with caution // Hotfix for header hash incompatibility issue.
// PR: https://github.com/scroll-tech/go-ethereum/pull/1133/
// CAUTION: Requires careful handling. When upgrading go-ethereum, ensure this fix remains up-to-date in this branch.
replace github.com/scroll-tech/go-ethereum => github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092359-25d5bf6b817b
require ( require (
dario.cat/mergo v1.0.0 // indirect dario.cat/mergo v1.0.0 // indirect
@@ -30,10 +33,10 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/bavard v0.1.27 // indirect
github.com/consensys/gnark-crypto v0.13.0 // indirect github.com/consensys/gnark-crypto v0.16.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -41,7 +44,7 @@ require (
github.com/docker/docker v26.1.0+incompatible // indirect github.com/docker/docker v26.1.0+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-connections v0.5.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/fjl/memsize v0.0.2 // indirect github.com/fjl/memsize v0.0.2 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
@@ -98,7 +101,7 @@ require (
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/status-im/keycard-go v0.2.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect
github.com/supranational/blst v0.3.13 // indirect github.com/supranational/blst v0.3.15 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect github.com/tklauser/numcpus v0.9.0 // indirect
@@ -110,7 +113,7 @@ require (
go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.5.0 // indirect golang.org/x/arch v0.5.0 // indirect
golang.org/x/crypto v0.24.0 // indirect golang.org/x/crypto v0.32.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.30.0 // indirect golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect

View File

@@ -53,16 +53,16 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.27 h1:j6hKUrGAy/H+gpNrpLU3I26n1yc+VMGmd6ID5+gAhOs=
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/bavard v0.1.27/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
github.com/consensys/gnark-crypto v0.13.0 h1:VPULb/v6bbYELAPTDFINEVaMTTybV5GLxDdcjnS+4oc= github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw4KoTAawo=
github.com/consensys/gnark-crypto v0.13.0/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o= github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU=
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -88,8 +88,8 @@ github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T
github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E= github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E=
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
github.com/ethereum/c-kzg-4844 v1.0.3/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -214,8 +214,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -309,10 +309,10 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 h1:4utngmJHXSOS5FoSdZhEV1xMRirpArbXvyoCZY9nYj0= github.com/scroll-tech/da-codec v0.10.0 h1:IPHxyTyXTWPV0Q+DZ08cod2fWkhUvrfysmj/VBpB+WU=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= github.com/scroll-tech/da-codec v0.10.0/go.mod h1:MBlIP4wCXPcUDZ/Ci2B7n/2IbVU1WBo9OTFTZ5ffE0U=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250729113104-bd8f141bb3e9 h1:u371VK8eOU2Z/0SVf5KDI3eJc8msHSpJbav4do/8n38= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092359-25d5bf6b817b h1:pMQKnroJoS/FeL1aOWkz7/u1iBHUP8PWjZstNuzoUGE=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250729113104-bd8f141bb3e9/go.mod h1:pDCZ4iGvEGmdIe4aSAGBrb7XSrKEML6/L/wEMmNxOdk= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092359-25d5bf6b817b/go.mod h1:Aa/kD1XB+OV/7rRxMQrjcPCB4b0pKyLH0gsTrtuHi38=
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
@@ -341,10 +341,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o=
github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/supranational/blst v0.3.15/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
@@ -387,8 +387,8 @@ golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@@ -361,7 +361,6 @@ func getTxHistoryInfoFromBridgeBatchDepositMessage(message *orm.BridgeBatchDepos
func (h *HistoryLogic) getCachedTxsInfo(ctx context.Context, cacheKey string, pageNum, pageSize uint64) ([]*types.TxHistoryInfo, uint64, bool, error) { func (h *HistoryLogic) getCachedTxsInfo(ctx context.Context, cacheKey string, pageNum, pageSize uint64) ([]*types.TxHistoryInfo, uint64, bool, error) {
start := int64((pageNum - 1) * pageSize) start := int64((pageNum - 1) * pageSize)
end := start + int64(pageSize) - 1 end := start + int64(pageSize) - 1
total, err := h.redis.ZCard(ctx, cacheKey).Result() total, err := h.redis.ZCard(ctx, cacheKey).Result()
if err != nil { if err != nil {
log.Error("failed to get zcard result", "error", err) log.Error("failed to get zcard result", "error", err)
@@ -372,6 +371,10 @@ func (h *HistoryLogic) getCachedTxsInfo(ctx context.Context, cacheKey string, pa
return nil, 0, false, nil return nil, 0, false, nil
} }
if start >= total {
return nil, 0, false, nil
}
values, err := h.redis.ZRevRange(ctx, cacheKey, start, end).Result() values, err := h.redis.ZRevRange(ctx, cacheKey, start, end).Result()
if err != nil { if err != nil {
log.Error("failed to get zrange result", "error", err) log.Error("failed to get zrange result", "error", err)
@@ -450,5 +453,6 @@ func (h *HistoryLogic) processAndCacheTxHistoryInfo(ctx context.Context, cacheKe
log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", page, "page size", pageSize, "error", err) log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", page, "page size", pageSize, "error", err)
return nil, 0, err return nil, 0, err
} }
return pagedTxs, total, nil return pagedTxs, total, nil
} }

View File

@@ -157,7 +157,7 @@ func (c *CrossMessage) GetL2UnclaimedWithdrawalsByAddress(ctx context.Context, s
db = db.Where("tx_status in (?)", []types.TxStatusType{types.TxStatusTypeSent, types.TxStatusTypeFailedRelayed, types.TxStatusTypeRelayTxReverted}) db = db.Where("tx_status in (?)", []types.TxStatusType{types.TxStatusTypeSent, types.TxStatusTypeFailedRelayed, types.TxStatusTypeRelayTxReverted})
db = db.Where("sender = ?", sender) db = db.Where("sender = ?", sender)
db = db.Order("block_timestamp desc") db = db.Order("block_timestamp desc")
db = db.Limit(500) db = db.Limit(10000)
if err := db.Find(&messages).Error; err != nil { if err := db.Find(&messages).Error; err != nil {
return nil, fmt.Errorf("failed to get L2 claimable withdrawal messages by sender address, sender: %v, error: %w", sender, err) return nil, fmt.Errorf("failed to get L2 claimable withdrawal messages by sender address, sender: %v, error: %w", sender, err)
} }

View File

@@ -15,7 +15,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 github.com/modern-go/reflect2 v1.0.2
github.com/orcaman/concurrent-map v1.0.0 github.com/orcaman/concurrent-map v1.0.0
github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_golang v1.19.0
github.com/scroll-tech/go-ethereum v1.10.14-0.20250625112225-a67863c65587 github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/testcontainers/testcontainers-go v0.30.0 github.com/testcontainers/testcontainers-go v0.30.0
github.com/testcontainers/testcontainers-go/modules/compose v0.30.0 github.com/testcontainers/testcontainers-go/modules/compose v0.30.0
@@ -64,7 +64,7 @@ require (
github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect
github.com/distribution/reference v0.5.0 // indirect github.com/distribution/reference v0.5.0 // indirect
@@ -79,7 +79,7 @@ require (
github.com/docker/go-units v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/emicklei/go-restful/v3 v3.10.1 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fjl/memsize v0.0.2 // indirect github.com/fjl/memsize v0.0.2 // indirect
github.com/fsnotify/fsevents v0.1.1 // indirect github.com/fsnotify/fsevents v0.1.1 // indirect
@@ -184,7 +184,7 @@ require (
github.com/rjeczalik/notify v0.9.1 // indirect github.com/rjeczalik/notify v0.9.1 // indirect
github.com/rs/cors v1.7.0 // indirect github.com/rs/cors v1.7.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 // indirect github.com/scroll-tech/da-codec v0.10.0 // indirect
github.com/scroll-tech/zktrie v0.8.4 // indirect github.com/scroll-tech/zktrie v0.8.4 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
@@ -198,7 +198,7 @@ require (
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.4.0 // indirect github.com/spf13/viper v1.4.0 // indirect
github.com/status-im/keycard-go v0.2.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect
github.com/supranational/blst v0.3.13 // indirect github.com/supranational/blst v0.3.15 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/theupdateframework/notary v0.7.0 // indirect github.com/theupdateframework/notary v0.7.0 // indirect
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 // indirect github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 // indirect

View File

@@ -155,8 +155,8 @@ github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoY
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
@@ -214,8 +214,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
github.com/ethereum/c-kzg-4844 v1.0.3/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
@@ -636,10 +636,10 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 h1:4utngmJHXSOS5FoSdZhEV1xMRirpArbXvyoCZY9nYj0= github.com/scroll-tech/da-codec v0.10.0 h1:IPHxyTyXTWPV0Q+DZ08cod2fWkhUvrfysmj/VBpB+WU=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= github.com/scroll-tech/da-codec v0.10.0/go.mod h1:MBlIP4wCXPcUDZ/Ci2B7n/2IbVU1WBo9OTFTZ5ffE0U=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250625112225-a67863c65587 h1:wG1+gb+K4iLtxAHhiAreMdIjP5x9hB64duraN2+u1QU= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f h1:j6SjP98MoWFFX9TwB1/nFYEkayqHQsrtE66Ll2C+oT0=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250625112225-a67863c65587/go.mod h1:YyfB2AyAtphlbIuDQgaxc2b9mo0zE4EBA1+qtXvzlmg= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f/go.mod h1:Aa/kD1XB+OV/7rRxMQrjcPCB4b0pKyLH0gsTrtuHi38=
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE= github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
@@ -707,8 +707,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o=
github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/supranational/blst v0.3.15/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E= github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E=

View File

@@ -34,7 +34,7 @@ services:
# Sets up the genesis configuration for the go-ethereum client from a JSON file. # Sets up the genesis configuration for the go-ethereum client from a JSON file.
geth-genesis: geth-genesis:
image: "ethereum/client-go:v1.13.14" image: "ethereum/client-go:v1.14.0"
command: --datadir=/data/execution init /data/execution/genesis.json command: --datadir=/data/execution init /data/execution/genesis.json
volumes: volumes:
- data:/data - data:/data
@@ -80,7 +80,7 @@ services:
# Runs the go-ethereum execution client with the specified, unlocked account and necessary # Runs the go-ethereum execution client with the specified, unlocked account and necessary
# APIs to allow for proof-of-stake consensus via Prysm. # APIs to allow for proof-of-stake consensus via Prysm.
geth: geth:
image: "ethereum/client-go:v1.13.14" image: "ethereum/client-go:v1.14.0"
command: command:
- --http - --http
- --http.api=eth,net,web3 - --http.api=eth,net,web3

View File

@@ -1,4 +1,4 @@
FROM ethereum/client-go:v1.13.14 FROM ethereum/client-go:v1.14.0
COPY password /l1geth/ COPY password /l1geth/
COPY genesis.json /l1geth/ COPY genesis.json /l1geth/

View File

@@ -10,6 +10,7 @@ import (
"time" "time"
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/rpc"
"github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/compose" "github.com/testcontainers/testcontainers-go/modules/compose"
"github.com/testcontainers/testcontainers-go/modules/postgres" "github.com/testcontainers/testcontainers-go/modules/postgres"
@@ -166,13 +167,13 @@ func (t *TestcontainerApps) GetPoSL1EndPoint() (string, error) {
return contrainer.PortEndpoint(context.Background(), "8545/tcp", "http") return contrainer.PortEndpoint(context.Background(), "8545/tcp", "http")
} }
// GetPoSL1Client returns a ethclient by dialing running PoS L1 client // GetPoSL1Client returns a raw rpc client by dialing the L1 node
func (t *TestcontainerApps) GetPoSL1Client() (*ethclient.Client, error) { func (t *TestcontainerApps) GetPoSL1Client() (*rpc.Client, error) {
endpoint, err := t.GetPoSL1EndPoint() endpoint, err := t.GetPoSL1EndPoint()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return ethclient.Dial(endpoint) return rpc.Dial(endpoint)
} }
// GetDBEndPoint returns the endpoint of the running postgres container // GetDBEndPoint returns the endpoint of the running postgres container
@@ -220,11 +221,20 @@ func (t *TestcontainerApps) GetGormDBClient() (*gorm.DB, error) {
// GetL2GethClient returns a ethclient by dialing running L2Geth // GetL2GethClient returns a ethclient by dialing running L2Geth
func (t *TestcontainerApps) GetL2GethClient() (*ethclient.Client, error) { func (t *TestcontainerApps) GetL2GethClient() (*ethclient.Client, error) {
rpcCli, err := t.GetL2Client()
if err != nil {
return nil, err
}
return ethclient.NewClient(rpcCli), nil
}
// GetL2GethClient returns a rpc client by dialing running L2Geth
func (t *TestcontainerApps) GetL2Client() (*rpc.Client, error) {
endpoint, err := t.GetL2GethEndPoint() endpoint, err := t.GetL2GethEndPoint()
if err != nil { if err != nil {
return nil, err return nil, err
} }
client, err := ethclient.Dial(endpoint) client, err := rpc.Dial(endpoint)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -3,7 +3,6 @@ package testcontainers
import ( import (
"testing" "testing"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -14,7 +13,6 @@ func TestNewTestcontainerApps(t *testing.T) {
err error err error
endpoint string endpoint string
gormDBclient *gorm.DB gormDBclient *gorm.DB
ethclient *ethclient.Client
) )
testApps := NewTestcontainerApps() testApps := NewTestcontainerApps()
@@ -32,17 +30,17 @@ func TestNewTestcontainerApps(t *testing.T) {
endpoint, err = testApps.GetL2GethEndPoint() endpoint, err = testApps.GetL2GethEndPoint()
assert.NoError(t, err) assert.NoError(t, err)
assert.NotEmpty(t, endpoint) assert.NotEmpty(t, endpoint)
ethclient, err = testApps.GetL2GethClient() l2RawClient, err := testApps.GetL2Client()
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, ethclient) assert.NotNil(t, l2RawClient)
assert.NoError(t, testApps.StartPoSL1Container()) assert.NoError(t, testApps.StartPoSL1Container())
endpoint, err = testApps.GetPoSL1EndPoint() endpoint, err = testApps.GetPoSL1EndPoint()
assert.NoError(t, err) assert.NoError(t, err)
assert.NotEmpty(t, endpoint) assert.NotEmpty(t, endpoint)
ethclient, err = testApps.GetPoSL1Client() l1RawClient, err := testApps.GetPoSL1Client()
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, ethclient) assert.NotNil(t, l1RawClient)
assert.NoError(t, testApps.StartWeb3SignerContainer(1)) assert.NoError(t, testApps.StartWeb3SignerContainer(1))
endpoint, err = testApps.GetWeb3SignerEndpoint() endpoint, err = testApps.GetWeb3SignerEndpoint()

View File

@@ -39,10 +39,12 @@ const (
// ChunkTaskDetail is a type containing ChunkTask detail for chunk task. // ChunkTaskDetail is a type containing ChunkTask detail for chunk task.
type ChunkTaskDetail struct { type ChunkTaskDetail struct {
Version uint8 `json:"version"`
// use one of the string of "euclidv1" / "euclidv2" // use one of the string of "euclidv1" / "euclidv2"
ForkName string `json:"fork_name"` ForkName string `json:"fork_name"`
BlockHashes []common.Hash `json:"block_hashes"` BlockHashes []common.Hash `json:"block_hashes"`
PrevMsgQueueHash common.Hash `json:"prev_msg_queue_hash"` PrevMsgQueueHash common.Hash `json:"prev_msg_queue_hash"`
PostMsgQueueHash common.Hash `json:"post_msg_queue_hash"`
} }
// it is a hex encoded big with fixed length on 48 bytes // it is a hex encoded big with fixed length on 48 bytes
@@ -90,40 +92,59 @@ func (e *Byte48) UnmarshalJSON(input []byte) error {
// BatchTaskDetail is a type containing BatchTask detail. // BatchTaskDetail is a type containing BatchTask detail.
type BatchTaskDetail struct { type BatchTaskDetail struct {
Version uint8 `json:"version"`
// use one of the string of "euclidv1" / "euclidv2" // use one of the string of "euclidv1" / "euclidv2"
ForkName string `json:"fork_name"` ForkName string `json:"fork_name"`
ChunkInfos []*ChunkInfo `json:"chunk_infos"` ChunkProofs []*OpenVMChunkProof `json:"chunk_proofs"`
ChunkProofs []*OpenVMChunkProof `json:"chunk_proofs"` BatchHeader interface{} `json:"batch_header"`
BatchHeader interface{} `json:"batch_header"` BlobBytes []byte `json:"blob_bytes"`
BlobBytes []byte `json:"blob_bytes"` KzgProof *Byte48 `json:"kzg_proof,omitempty"`
KzgProof Byte48 `json:"kzg_proof,omitempty"` KzgCommitment *Byte48 `json:"kzg_commitment,omitempty"`
KzgCommitment Byte48 `json:"kzg_commitment,omitempty"` // ChallengeDigest should be a common.Hash type if it is not nil
ChallengeDigest common.Hash `json:"challenge_digest,omitempty"` ChallengeDigest interface{} `json:"challenge_digest,omitempty"`
} }
// BundleTaskDetail consists of all the information required to describe the task to generate a proof for a bundle of batches. // BundleTaskDetail consists of all the information required to describe the task to generate a proof for a bundle of batches.
type BundleTaskDetail struct { type BundleTaskDetail struct {
Version uint8 `json:"version"`
// use one of the string of "euclidv1" / "euclidv2" // use one of the string of "euclidv1" / "euclidv2"
ForkName string `json:"fork_name"` ForkName string `json:"fork_name"`
BatchProofs []*OpenVMBatchProof `json:"batch_proofs"` BatchProofs []*OpenVMBatchProof `json:"batch_proofs"`
BundleInfo *OpenVMBundleInfo `json:"bundle_info,omitempty"` BundleInfo *OpenVMBundleInfo `json:"bundle_info,omitempty"`
} }
type RawBytes []byte
func (r RawBytes) MarshalJSON() ([]byte, error) {
if r == nil {
return []byte("null"), nil
}
// Marshal the []byte as a JSON array of numbers
rn := make([]uint16, len(r))
for i := range r {
rn[i] = uint16(r[i])
}
return json.Marshal(rn)
}
// ChunkInfo is for calculating pi_hash for chunk // ChunkInfo is for calculating pi_hash for chunk
type ChunkInfo struct { type ChunkInfo struct {
ChainID uint64 `json:"chain_id"` ChainID uint64 `json:"chain_id"`
PrevStateRoot common.Hash `json:"prev_state_root"` PrevStateRoot common.Hash `json:"prev_state_root"`
PostStateRoot common.Hash `json:"post_state_root"` PostStateRoot common.Hash `json:"post_state_root"`
WithdrawRoot common.Hash `json:"withdraw_root"` WithdrawRoot common.Hash `json:"withdraw_root"`
DataHash common.Hash `json:"data_hash"` DataHash common.Hash `json:"data_hash"`
IsPadding bool `json:"is_padding"` IsPadding bool `json:"is_padding"`
TxBytes []byte `json:"tx_bytes"` // TxBytes []byte `json:"tx_bytes"`
TxBytesHash common.Hash `json:"tx_data_digest"` TxBytesHash common.Hash `json:"tx_data_digest"`
PrevMsgQueueHash common.Hash `json:"prev_msg_queue_hash"` PrevMsgQueueHash common.Hash `json:"prev_msg_queue_hash"`
PostMsgQueueHash common.Hash `json:"post_msg_queue_hash"` PostMsgQueueHash common.Hash `json:"post_msg_queue_hash"`
TxDataLength uint64 `json:"tx_data_length"` TxDataLength uint64 `json:"tx_data_length"`
InitialBlockNumber uint64 `json:"initial_block_number"` InitialBlockNumber uint64 `json:"initial_block_number"`
BlockCtxs []BlockContextV2 `json:"block_ctxs"` BlockCtxs []BlockContextV2 `json:"block_ctxs"`
PrevBlockhash common.Hash `json:"prev_blockhash"`
PostBlockhash common.Hash `json:"post_blockhash"`
EncryptionKey RawBytes `json:"encryption_key"`
} }
// BlockContextV2 is the block context for euclid v2 // BlockContextV2 is the block context for euclid v2
@@ -186,6 +207,7 @@ type OpenVMBatchInfo struct {
ChainID uint64 `json:"chain_id"` ChainID uint64 `json:"chain_id"`
PrevMsgQueueHash common.Hash `json:"prev_msg_queue_hash"` PrevMsgQueueHash common.Hash `json:"prev_msg_queue_hash"`
PostMsgQueueHash common.Hash `json:"post_msg_queue_hash"` PostMsgQueueHash common.Hash `json:"post_msg_queue_hash"`
EncryptionKey RawBytes `json:"encryption_key"`
} }
// BatchProof includes the proof info that are required for batch verification and rollup. // BatchProof includes the proof info that are required for batch verification and rollup.
@@ -246,6 +268,7 @@ type OpenVMBundleInfo struct {
PrevBatchHash common.Hash `json:"prev_batch_hash"` PrevBatchHash common.Hash `json:"prev_batch_hash"`
BatchHash common.Hash `json:"batch_hash"` BatchHash common.Hash `json:"batch_hash"`
MsgQueueHash common.Hash `json:"msg_queue_hash"` MsgQueueHash common.Hash `json:"msg_queue_hash"`
EncryptionKey RawBytes `json:"encryption_key"`
} }
// OpenVMBundleProof includes the proof info that are required for verification of a bundle of batch proofs. // OpenVMBundleProof includes the proof info that are required for verification of a bundle of batch proofs.

View File

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

View File

@@ -35,10 +35,16 @@ coordinator_tool:
go build -ldflags "-X scroll-tech/common/version.ZkVersion=${ZK_VERSION}" -o $(PWD)/build/bin/coordinator_tool ./cmd/tool go build -ldflags "-X scroll-tech/common/version.ZkVersion=${ZK_VERSION}" -o $(PWD)/build/bin/coordinator_tool ./cmd/tool
localsetup: coordinator_api ## Local setup: build coordinator_api, copy config, and setup releases localsetup: coordinator_api ## Local setup: build coordinator_api, copy config, and setup releases
mkdir -p build/bin/conf
@echo "Copying configuration files..." @echo "Copying configuration files..."
cp -r $(PWD)/conf $(PWD)/build/bin/ @if [ -f "$(PWD)/conf/config.template.json" ]; then \
SRC="$(PWD)/conf/config.template.json"; \
else \
SRC="$(CURDIR)/conf/config.json"; \
fi; \
cp -fL "$$SRC" "$(CURDIR)/build/bin/conf/config.template.json"
@echo "Setting up releases..." @echo "Setting up releases..."
cd $(PWD)/build && bash setup_releases.sh cd $(CURDIR)/build && bash setup_releases.sh
#coordinator_api_skip_libzkp: #coordinator_api_skip_libzkp:

View File

@@ -6,8 +6,11 @@ if [ -z "${SCROLL_ZKVM_VERSION}" ]; then
exit 1 exit 1
fi fi
# default fork name from env or "galileo"
SCROLL_FORK_NAME="${SCROLL_FORK_NAME:-galileov2}"
# set ASSET_DIR by reading from config.json # set ASSET_DIR by reading from config.json
CONFIG_FILE="bin/conf/config.json" CONFIG_FILE="bin/conf/config.template.json"
if [ ! -f "$CONFIG_FILE" ]; then if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file $CONFIG_FILE not found" echo "Config file $CONFIG_FILE not found"
exit 1 exit 1
@@ -29,6 +32,12 @@ for ((i=0; i<$VERIFIER_COUNT; i++)); do
ASSETS_PATH=$(jq -r ".prover_manager.verifier.verifiers[$i].assets_path" "$CONFIG_FILE") ASSETS_PATH=$(jq -r ".prover_manager.verifier.verifiers[$i].assets_path" "$CONFIG_FILE")
FORK_NAME=$(jq -r ".prover_manager.verifier.verifiers[$i].fork_name" "$CONFIG_FILE") FORK_NAME=$(jq -r ".prover_manager.verifier.verifiers[$i].fork_name" "$CONFIG_FILE")
# skip if this verifier's fork doesn't match the target fork
if [ "$FORK_NAME" != "$SCROLL_FORK_NAME" ]; then
echo "Expect $SCROLL_FORK_NAME, skip current fork ($FORK_NAME)"
continue
fi
if [ "$ASSETS_PATH" = "null" ]; then if [ "$ASSETS_PATH" = "null" ]; then
echo "Warning: Could not find assets_path for verifier $i, skipping..." echo "Warning: Could not find assets_path for verifier $i, skipping..."
continue continue
@@ -53,6 +62,7 @@ for ((i=0; i<$VERIFIER_COUNT; i++)); do
# assets for verifier-only mode # assets for verifier-only mode
echo "Downloading assets for $FORK_NAME to $ASSET_DIR..." echo "Downloading assets for $FORK_NAME to $ASSET_DIR..."
wget https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/$SCROLL_ZKVM_VERSION/verifier/verifier.bin -O ${ASSET_DIR}/verifier.bin wget https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/$SCROLL_ZKVM_VERSION/verifier/verifier.bin -O ${ASSET_DIR}/verifier.bin
wget https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/$SCROLL_ZKVM_VERSION/verifier/root_verifier_vk -O ${ASSET_DIR}/root_verifier_vk
wget https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/$SCROLL_ZKVM_VERSION/verifier/openVmVk.json -O ${ASSET_DIR}/openVmVk.json wget https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/$SCROLL_ZKVM_VERSION/verifier/openVmVk.json -O ${ASSET_DIR}/openVmVk.json
echo "Completed downloading assets for $FORK_NAME" echo "Completed downloading assets for $FORK_NAME"

View File

@@ -91,11 +91,13 @@ func (c *CoordinatorApp) MockConfig(store bool) error {
ProversPerSession: 1, ProversPerSession: 1,
Verifier: &coordinatorConfig.VerifierConfig{ Verifier: &coordinatorConfig.VerifierConfig{
MinProverVersion: "v4.4.89", MinProverVersion: "v4.4.89",
Verifiers: []coordinatorConfig.AssetConfig{{ Verifiers: []coordinatorConfig.AssetConfig{
AssetsPath: "", {
ForkName: "feynman", AssetsPath: "",
ForkName: "galileo",
},
}, },
}}, },
BatchCollectionTimeSec: 60, BatchCollectionTimeSec: 60,
ChunkCollectionTimeSec: 60, ChunkCollectionTimeSec: 60,
SessionAttempts: 10, SessionAttempts: 10,

View File

@@ -36,7 +36,7 @@ func verify(cCtx *cli.Context) error {
return fmt.Errorf("error reading file: %w", err) return fmt.Errorf("error reading file: %w", err)
} }
vf, err := verifier.NewVerifier(cfg.ProverManager.Verifier) vf, err := verifier.NewVerifier(cfg.ProverManager.Verifier, cfg.L2.ValidiumMode)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -10,12 +10,17 @@
"min_prover_version": "v4.4.45", "min_prover_version": "v4.4.45",
"verifiers": [ "verifiers": [
{ {
"assets_path": "assets", "features": "legacy_witness:openvm_13",
"fork_name": "euclidV2" "assets_path": "assets_feynman",
"fork_name": "feynman"
}, },
{ {
"assets_path": "assets", "assets_path": "assets",
"fork_name": "feynman" "fork_name": "galileo"
},
{
"assets_path": "assets_v2",
"fork_name": "galileoV2"
} }
] ]
} }

View File

@@ -9,8 +9,8 @@ require (
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_golang v1.19.0
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 github.com/scroll-tech/da-codec v0.10.0
github.com/scroll-tech/go-ethereum v1.10.14-0.20250626110859-cc9a1dd82de7 github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f
github.com/shopspring/decimal v1.3.1 github.com/shopspring/decimal v1.3.1
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.25.7 github.com/urfave/cli/v2 v2.25.7
@@ -54,11 +54,11 @@ require (
github.com/consensys/bavard v0.1.29 // indirect github.com/consensys/bavard v0.1.29 // indirect
github.com/consensys/gnark-crypto v0.16.0 // indirect github.com/consensys/gnark-crypto v0.16.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/fjl/memsize v0.0.2 // indirect github.com/fjl/memsize v0.0.2 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
@@ -92,7 +92,7 @@ require (
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect
github.com/supranational/blst v0.3.13 // indirect github.com/supranational/blst v0.3.15 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect github.com/tklauser/numcpus v0.9.0 // indirect

View File

@@ -47,8 +47,8 @@ github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw
github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU= github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -59,8 +59,8 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vs
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
github.com/ethereum/c-kzg-4844 v1.0.3/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -253,10 +253,10 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 h1:4utngmJHXSOS5FoSdZhEV1xMRirpArbXvyoCZY9nYj0= github.com/scroll-tech/da-codec v0.10.0 h1:IPHxyTyXTWPV0Q+DZ08cod2fWkhUvrfysmj/VBpB+WU=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= github.com/scroll-tech/da-codec v0.10.0/go.mod h1:MBlIP4wCXPcUDZ/Ci2B7n/2IbVU1WBo9OTFTZ5ffE0U=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250626110859-cc9a1dd82de7 h1:1rN1qocsQlOyk1VCpIEF1J5pfQbLAi1pnMZSLQS37jQ= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f h1:j6SjP98MoWFFX9TwB1/nFYEkayqHQsrtE66Ll2C+oT0=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250626110859-cc9a1dd82de7/go.mod h1:pDCZ4iGvEGmdIe4aSAGBrb7XSrKEML6/L/wEMmNxOdk= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f/go.mod h1:Aa/kD1XB+OV/7rRxMQrjcPCB4b0pKyLH0gsTrtuHi38=
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
@@ -282,8 +282,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o=
github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/supranational/blst v0.3.15/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=

View File

@@ -36,8 +36,9 @@ type L2Endpoint struct {
// L2 loads l2geth configuration items. // L2 loads l2geth configuration items.
type L2 struct { type L2 struct {
// l2geth chain_id. // l2geth chain_id.
ChainID uint64 `json:"chain_id"` ChainID uint64 `json:"chain_id"`
Endpoint *L2Endpoint `json:"l2geth"` Endpoint *L2Endpoint `json:"l2geth"`
ValidiumMode bool `json:"validium_mode"`
} }
// Auth provides the auth coordinator // Auth provides the auth coordinator
@@ -47,20 +48,28 @@ type Auth struct {
LoginExpireDurationSec int `json:"login_expire_duration_sec"` LoginExpireDurationSec int `json:"login_expire_duration_sec"`
} }
// The sequencer controlled data
type Sequencer struct {
DecryptionKey string `json:"decryption_key"`
}
// Config load configuration items. // Config load configuration items.
type Config struct { type Config struct {
ProverManager *ProverManager `json:"prover_manager"` ProverManager *ProverManager `json:"prover_manager"`
DB *database.Config `json:"db"` DB *database.Config `json:"db"`
L2 *L2 `json:"l2"` L2 *L2 `json:"l2"`
Auth *Auth `json:"auth"` Auth *Auth `json:"auth"`
Sequencer *Sequencer `json:"sequencer"`
} }
// AssetConfig contain assets configurated for each fork, the defaul vkfile name is "OpenVmVk.json". // AssetConfig contain assets configurated for each fork, the defaul vkfile name is "OpenVmVk.json".
type AssetConfig struct { type AssetConfig struct {
AssetsPath string `json:"assets_path"` AssetsPath string `json:"assets_path"`
Version uint8 `json:"version,omitempty"`
ForkName string `json:"fork_name"` ForkName string `json:"fork_name"`
Vkfile string `json:"vk_file,omitempty"` Vkfile string `json:"vk_file,omitempty"`
MinProverVersion string `json:"min_prover_version,omitempty"` MinProverVersion string `json:"min_prover_version,omitempty"`
Features string `json:"features,omitempty"`
} }
// VerifierConfig load zk verifier config. // VerifierConfig load zk verifier config.

View File

@@ -23,7 +23,7 @@ func TestConfig(t *testing.T) {
"min_prover_version": "v4.4.45", "min_prover_version": "v4.4.45",
"verifiers": [{ "verifiers": [{
"assets_path": "assets", "assets_path": "assets",
"fork_name": "feynman" "fork_name": "galileo"
}] }]
}, },
"max_verifier_workers": 4 "max_verifier_workers": 4
@@ -35,13 +35,17 @@ func TestConfig(t *testing.T) {
"maxIdleNum": 20 "maxIdleNum": 20
}, },
"l2": { "l2": {
"chain_id": 111 "chain_id": 111,
"validium_mode": false
}, },
"auth": { "auth": {
"secret": "prover secret key", "secret": "prover secret key",
"challenge_expire_duration_sec": 3600, "challenge_expire_duration_sec": 3600,
"login_expire_duration_sec": 3600 "login_expire_duration_sec": 3600
} },
"sequencer": {
"decryption_key": "sequencer decryption key"
}
}` }`
t.Run("Success Case", func(t *testing.T) { t.Run("Success Case", func(t *testing.T) {

View File

@@ -24,7 +24,9 @@ var (
// InitController inits Controller with database // InitController inits Controller with database
func InitController(cfg *config.Config, chainCfg *params.ChainConfig, db *gorm.DB, reg prometheus.Registerer) { func InitController(cfg *config.Config, chainCfg *params.ChainConfig, db *gorm.DB, reg prometheus.Registerer) {
vf, err := verifier.NewVerifier(cfg.ProverManager.Verifier) validiumMode := cfg.L2.ValidiumMode
vf, err := verifier.NewVerifier(cfg.ProverManager.Verifier, validiumMode)
if err != nil { if err != nil {
panic("proof receiver new verifier failure") panic("proof receiver new verifier failure")
} }

View File

@@ -93,8 +93,8 @@ func fromMessageTaskType(taskType int) int {
} }
// Generate a universal task // Generate a universal task
func GenerateUniversalTask(taskType int, taskJSON, forkName string, expectedVk []byte) (bool, string, string, []byte) { func GenerateUniversalTask(taskType int, taskJSON, forkName string, expectedVk []byte, decryptionKey []byte) (bool, string, string, []byte) {
return generateUniversalTask(fromMessageTaskType(taskType), taskJSON, strings.ToLower(forkName), expectedVk) return generateUniversalTask(fromMessageTaskType(taskType), taskJSON, strings.ToLower(forkName), expectedVk, decryptionKey)
} }
// Generate wrapped proof // Generate wrapped proof
@@ -140,3 +140,20 @@ func DumpVk(forkName, filePath string) error {
return nil return nil
} }
// UnivTaskCompatibilityFix calls the universal task compatibility fix function
func UniversalTaskCompatibilityFix(taskJSON string) (string, error) {
cTaskJSON := goToCString(taskJSON)
defer freeCString(cTaskJSON)
resultPtr := C.univ_task_compatibility_fix(cTaskJSON)
if resultPtr == nil {
return "", fmt.Errorf("univ_task_compatibility_fix failed")
}
// Convert result to Go string and free C memory
result := C.GoString(resultPtr)
C.release_string(resultPtr)
return result, nil
}

View File

@@ -40,7 +40,9 @@ HandlingResult gen_universal_task(
char* task, char* task,
char* fork_name, char* fork_name,
const unsigned char* expected_vk, const unsigned char* expected_vk,
size_t expected_vk_len size_t expected_vk_len,
const unsigned char* decryption_key,
size_t decryption_key_len
); );
// Release memory allocated for a HandlingResult returned by gen_universal_task // Release memory allocated for a HandlingResult returned by gen_universal_task
@@ -54,4 +56,7 @@ char* gen_wrapped_proof(char* proof_json, char* metadata, char* vk, size_t vk_le
// Release memory allocated for a string returned by gen_wrapped_proof // Release memory allocated for a string returned by gen_wrapped_proof
void release_string(char* string_ptr); void release_string(char* string_ptr);
// Universal task compatibility fix function
char* univ_task_compatibility_fix(char* task_json);
#endif /* LIBZKP_H */ #endif /* LIBZKP_H */

View File

@@ -14,7 +14,7 @@ import (
func InitL2geth(configJSON string) { func InitL2geth(configJSON string) {
} }
func generateUniversalTask(taskType int, taskJSON, forkName string, expectedVk []byte) (bool, string, string, []byte) { func generateUniversalTask(taskType int, taskJSON, forkName string, expectedVk []byte, decryptionKey []byte) (bool, string, string, []byte) {
fmt.Printf("call mocked generate universal task %d, taskJson %s\n", taskType, taskJSON) fmt.Printf("call mocked generate universal task %d, taskJson %s\n", taskType, taskJSON)
var metadata interface{} var metadata interface{}

View File

@@ -17,7 +17,7 @@ func InitL2geth(configJSON string) {
C.init_l2geth(cConfig) C.init_l2geth(cConfig)
} }
func generateUniversalTask(taskType int, taskJSON, forkName string, expectedVk []byte) (bool, string, string, []byte) { func generateUniversalTask(taskType int, taskJSON, forkName string, expectedVk []byte, decryptionKey []byte) (bool, string, string, []byte) {
cTask := goToCString(taskJSON) cTask := goToCString(taskJSON)
cForkName := goToCString(forkName) cForkName := goToCString(forkName)
defer freeCString(cTask) defer freeCString(cTask)
@@ -29,7 +29,13 @@ func generateUniversalTask(taskType int, taskJSON, forkName string, expectedVk [
cVk = (*C.uchar)(unsafe.Pointer(&expectedVk[0])) cVk = (*C.uchar)(unsafe.Pointer(&expectedVk[0]))
} }
result := C.gen_universal_task(C.int(taskType), cTask, cForkName, cVk, C.size_t(len(expectedVk))) // Create a C array from Go slice
var cDk *C.uchar
if len(decryptionKey) > 0 {
cDk = (*C.uchar)(unsafe.Pointer(&decryptionKey[0]))
}
result := C.gen_universal_task(C.int(taskType), cTask, cForkName, cVk, C.size_t(len(expectedVk)), cDk, C.size_t(len(decryptionKey)))
defer C.release_task_result(result) defer C.release_task_result(result)
// Check if the operation was successful // Check if the operation was successful

View File

@@ -213,6 +213,14 @@ func (bp *BatchProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato
return nil, ErrCoordinatorInternalFailure return nil, ErrCoordinatorInternalFailure
} }
proverTask.Metadata = metadata proverTask.Metadata = metadata
if isCompatibilityFixingVersion(taskCtx.ProverVersion) {
log.Info("Apply compatibility fixing for prover", "version", taskCtx.ProverVersion)
if err := fixCompatibility(taskMsg); err != nil {
log.Error("apply compatibility failure", "err", err)
return nil, ErrCoordinatorInternalFailure
}
}
} }
// Store session info. // Store session info.
@@ -249,36 +257,21 @@ func (bp *BatchProverTask) formatProverTask(ctx context.Context, task *orm.Prove
} }
var chunkProofs []*message.OpenVMChunkProof var chunkProofs []*message.OpenVMChunkProof
var chunkInfos []*message.ChunkInfo // var chunkInfos []*message.ChunkInfo
for _, chunk := range chunks { for _, chunk := range chunks {
var proof message.OpenVMChunkProof var proof message.OpenVMChunkProof
if encodeErr := json.Unmarshal(chunk.Proof, &proof); encodeErr != nil { if encodeErr := json.Unmarshal(chunk.Proof, &proof); encodeErr != nil {
return nil, fmt.Errorf("Chunk.GetProofsByBatchHash unmarshal proof error: %w, batch hash: %v, chunk hash: %v", encodeErr, task.TaskID, chunk.Hash) return nil, fmt.Errorf("Chunk.GetProofsByBatchHash unmarshal proof error: %w, batch hash: %v, chunk hash: %v", encodeErr, task.TaskID, chunk.Hash)
} }
chunkProofs = append(chunkProofs, &proof) chunkProofs = append(chunkProofs, &proof)
chunkInfo := message.ChunkInfo{
ChainID: bp.cfg.L2.ChainID,
PrevStateRoot: common.HexToHash(chunk.ParentChunkStateRoot),
PostStateRoot: common.HexToHash(chunk.StateRoot),
WithdrawRoot: common.HexToHash(chunk.WithdrawRoot),
DataHash: common.HexToHash(chunk.Hash),
PrevMsgQueueHash: common.HexToHash(chunk.PrevL1MessageQueueHash),
PostMsgQueueHash: common.HexToHash(chunk.PostL1MessageQueueHash),
IsPadding: false,
InitialBlockNumber: proof.MetaData.ChunkInfo.InitialBlockNumber,
BlockCtxs: proof.MetaData.ChunkInfo.BlockCtxs,
TxDataLength: proof.MetaData.ChunkInfo.TxDataLength,
}
chunkInfos = append(chunkInfos, &chunkInfo)
} }
taskDetail, err := bp.getBatchTaskDetail(batch, chunkInfos, chunkProofs, hardForkName) taskDetail, err := bp.getBatchTaskDetail(batch, chunkProofs, hardForkName)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get batch task detail, taskID:%s err:%w", task.TaskID, err) return nil, fmt.Errorf("failed to get batch task detail, taskID:%s err:%w", task.TaskID, err)
} }
chunkProofsBytes, err := json.Marshal(taskDetail) taskBytesWithchunkProofs, err := json.Marshal(taskDetail)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to marshal chunk proofs, taskID:%s err:%w", task.TaskID, err) return nil, fmt.Errorf("failed to marshal chunk proofs, taskID:%s err:%w", task.TaskID, err)
} }
@@ -286,7 +279,7 @@ func (bp *BatchProverTask) formatProverTask(ctx context.Context, task *orm.Prove
taskMsg := &coordinatorType.GetTaskSchema{ taskMsg := &coordinatorType.GetTaskSchema{
TaskID: task.TaskID, TaskID: task.TaskID,
TaskType: int(message.ProofTypeBatch), TaskType: int(message.ProofTypeBatch),
TaskData: string(chunkProofsBytes), TaskData: string(taskBytesWithchunkProofs),
HardForkName: hardForkName, HardForkName: hardForkName,
} }
@@ -301,38 +294,59 @@ func (bp *BatchProverTask) recoverActiveAttempts(ctx *gin.Context, batchTask *or
} }
} }
func (bp *BatchProverTask) getBatchTaskDetail(dbBatch *orm.Batch, chunkInfos []*message.ChunkInfo, chunkProofs []*message.OpenVMChunkProof, hardForkName string) (*message.BatchTaskDetail, error) { func (bp *BatchProverTask) getBatchTaskDetail(dbBatch *orm.Batch, chunkProofs []*message.OpenVMChunkProof, hardForkName string) (*message.BatchTaskDetail, error) {
// Get the version byte.
version, err := bp.version(hardForkName)
if err != nil {
return nil, fmt.Errorf("failed to decode version byte: %w", err)
}
taskDetail := &message.BatchTaskDetail{ taskDetail := &message.BatchTaskDetail{
ChunkInfos: chunkInfos, Version: version,
ChunkProofs: chunkProofs, ChunkProofs: chunkProofs,
ForkName: hardForkName, ForkName: hardForkName,
} }
dbBatchCodecVersion := encoding.CodecVersion(dbBatch.CodecVersion)
switch dbBatchCodecVersion {
case encoding.CodecV3, encoding.CodecV4, encoding.CodecV6, encoding.CodecV7, encoding.CodecV8:
default:
return taskDetail, nil
}
codec, err := encoding.CodecFromVersion(encoding.CodecVersion(dbBatch.CodecVersion))
if err != nil {
return nil, fmt.Errorf("failed to get codec from version %d, err: %w", dbBatch.CodecVersion, err)
}
batchHeader, decodeErr := codec.NewDABatchFromBytes(dbBatch.BatchHeader)
if decodeErr != nil {
return nil, fmt.Errorf("failed to decode batch header version %d: %w", dbBatch.CodecVersion, decodeErr)
}
taskDetail.BatchHeader = batchHeader
taskDetail.BlobBytes = dbBatch.BlobBytes taskDetail.BlobBytes = dbBatch.BlobBytes
taskDetail.ChallengeDigest = common.HexToHash(dbBatch.ChallengeDigest) if !bp.validiumMode() {
// Memory layout of `BlobDataProof`: used in Codec.BlobDataProofForPointEvaluation() dbBatchCodecVersion := encoding.CodecVersion(dbBatch.CodecVersion)
// | z | y | kzg_commitment | kzg_proof | switch dbBatchCodecVersion {
// |---------|---------|----------------|-----------| case 0:
// | bytes32 | bytes32 | bytes48 | bytes48 | log.Warn("the codec version is 0, if it is not under integration test we have encountered an error here")
taskDetail.KzgProof = message.Byte48{Big: hexutil.Big(*new(big.Int).SetBytes(dbBatch.BlobDataProof[112:160]))} return taskDetail, nil
taskDetail.KzgCommitment = message.Byte48{Big: hexutil.Big(*new(big.Int).SetBytes(dbBatch.BlobDataProof[64:112]))} case encoding.CodecV3, encoding.CodecV4, encoding.CodecV6, encoding.CodecV7, encoding.CodecV8, encoding.CodecV9, encoding.CodecV10:
default:
return nil, fmt.Errorf("Unsupported codec version <%d>", dbBatchCodecVersion)
}
codec, err := encoding.CodecFromVersion(encoding.CodecVersion(dbBatch.CodecVersion))
if err != nil {
return nil, fmt.Errorf("failed to get codec from version %d, err: %w", dbBatch.CodecVersion, err)
}
batchHeader, decodeErr := codec.NewDABatchFromBytes(dbBatch.BatchHeader)
if decodeErr != nil {
return nil, fmt.Errorf("failed to decode batch header version %d: %w", dbBatch.CodecVersion, decodeErr)
}
taskDetail.BatchHeader = batchHeader
taskDetail.ChallengeDigest = common.HexToHash(dbBatch.ChallengeDigest)
// Memory layout of `BlobDataProof`: used in Codec.BlobDataProofForPointEvaluation()
// | z | y | kzg_commitment | kzg_proof |
// |---------|---------|----------------|-----------|
// | bytes32 | bytes32 | bytes48 | bytes48 |
taskDetail.KzgProof = &message.Byte48{Big: hexutil.Big(*new(big.Int).SetBytes(dbBatch.BlobDataProof[112:160]))}
taskDetail.KzgCommitment = &message.Byte48{Big: hexutil.Big(*new(big.Int).SetBytes(dbBatch.BlobDataProof[64:112]))}
} else {
log.Info("Apply validium mode for batch proving task")
codec := cutils.FromVersion(version)
batchHeader, decodeErr := codec.DABatchForTaskFromBytes(dbBatch.BatchHeader)
if decodeErr != nil {
return nil, fmt.Errorf("failed to decode batch header version %d: %w", dbBatch.CodecVersion, decodeErr)
}
batchHeader.SetHash(common.HexToHash(dbBatch.Hash))
taskDetail.BatchHeader = batchHeader
}
return taskDetail, nil return taskDetail, nil
} }

View File

@@ -211,6 +211,14 @@ func (bp *BundleProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinat
// bundle proof require snark // bundle proof require snark
taskMsg.UseSnark = true taskMsg.UseSnark = true
proverTask.Metadata = metadata proverTask.Metadata = metadata
if isCompatibilityFixingVersion(taskCtx.ProverVersion) {
log.Info("Apply compatibility fixing for prover", "version", taskCtx.ProverVersion)
if err := fixCompatibility(taskMsg); err != nil {
log.Error("apply compatibility failure", "err", err)
return nil, ErrCoordinatorInternalFailure
}
}
} }
// Store session info. // Store session info.
@@ -265,7 +273,14 @@ func (bp *BundleProverTask) formatProverTask(ctx context.Context, task *orm.Prov
batchProofs = append(batchProofs, &proof) batchProofs = append(batchProofs, &proof)
} }
// Get the version byte.
version, err := bp.version(hardForkName)
if err != nil {
return nil, fmt.Errorf("failed to decode version byte: %w", err)
}
taskDetail := message.BundleTaskDetail{ taskDetail := message.BundleTaskDetail{
Version: version,
BatchProofs: batchProofs, BatchProofs: batchProofs,
ForkName: hardForkName, ForkName: hardForkName,
} }

View File

@@ -237,14 +237,21 @@ func (cp *ChunkProverTask) formatProverTask(ctx context.Context, task *orm.Prove
return nil, fmt.Errorf("failed to fetch block hashes of a chunk, chunk hash:%s err:%v", task.TaskID, dbErr) return nil, fmt.Errorf("failed to fetch block hashes of a chunk, chunk hash:%s err:%v", task.TaskID, dbErr)
} }
// Get the version byte.
version, err := cp.version(hardForkName)
if err != nil {
return nil, fmt.Errorf("failed to decode version byte: %w", err)
}
var taskDetailBytes []byte var taskDetailBytes []byte
taskDetail := message.ChunkTaskDetail{ taskDetail := message.ChunkTaskDetail{
Version: version,
BlockHashes: blockHashes, BlockHashes: blockHashes,
PrevMsgQueueHash: common.HexToHash(chunk.PrevL1MessageQueueHash), PrevMsgQueueHash: common.HexToHash(chunk.PrevL1MessageQueueHash),
PostMsgQueueHash: common.HexToHash(chunk.PostL1MessageQueueHash),
ForkName: hardForkName, ForkName: hardForkName,
} }
var err error
taskDetailBytes, err = json.Marshal(taskDetail) taskDetailBytes, err = json.Marshal(taskDetail)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to marshal block hashes hash:%s, err:%w", task.TaskID, err) return nil, fmt.Errorf("failed to marshal block hashes hash:%s, err:%w", task.TaskID, err)

View File

@@ -1,6 +1,7 @@
package provertask package provertask
import ( import (
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
@@ -14,11 +15,13 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"scroll-tech/common/types/message" "scroll-tech/common/types/message"
"scroll-tech/common/version"
"scroll-tech/coordinator/internal/config" "scroll-tech/coordinator/internal/config"
"scroll-tech/coordinator/internal/logic/libzkp" "scroll-tech/coordinator/internal/logic/libzkp"
"scroll-tech/coordinator/internal/orm" "scroll-tech/coordinator/internal/orm"
coordinatorType "scroll-tech/coordinator/internal/types" coordinatorType "scroll-tech/coordinator/internal/types"
"scroll-tech/coordinator/internal/utils"
) )
var ( var (
@@ -65,6 +68,17 @@ type proverTaskContext struct {
hasAssignedTask *orm.ProverTask hasAssignedTask *orm.ProverTask
} }
func (b *BaseProverTask) version(hardForkName string) (uint8, error) {
return utils.Version(hardForkName, b.validiumMode())
}
// validiumMode induce different behavior in task generation:
// + skip the point_evaluation part in batch task
// + encode batch header with codec in utils instead of da-codec
func (b *BaseProverTask) validiumMode() bool {
return b.cfg.L2.ValidiumMode
}
// hardForkName get the chunk/batch/bundle hard fork name // hardForkName get the chunk/batch/bundle hard fork name
func (b *BaseProverTask) hardForkName(ctx *gin.Context, taskCtx *proverTaskContext) (string, error) { func (b *BaseProverTask) hardForkName(ctx *gin.Context, taskCtx *proverTaskContext) (string, error) {
switch { switch {
@@ -192,7 +206,16 @@ func (b *BaseProverTask) applyUniversal(schema *coordinatorType.GetTaskSchema) (
return nil, nil, fmt.Errorf("no expectedVk found from hardfork %s", schema.HardForkName) return nil, nil, fmt.Errorf("no expectedVk found from hardfork %s", schema.HardForkName)
} }
ok, uTaskData, metadata, _ := libzkp.GenerateUniversalTask(schema.TaskType, schema.TaskData, schema.HardForkName, expectedVk) var decryptionKey []byte
if b.cfg.L2.ValidiumMode {
var err error
decryptionKey, err = hex.DecodeString(b.cfg.Sequencer.DecryptionKey)
if err != nil {
return nil, nil, fmt.Errorf("sequencer decryption key hex-decoding failed")
}
}
ok, uTaskData, metadata, _ := libzkp.GenerateUniversalTask(schema.TaskType, schema.TaskData, schema.HardForkName, expectedVk, decryptionKey)
if !ok { if !ok {
return nil, nil, fmt.Errorf("can not generate universal task, see coordinator log for the reason") return nil, nil, fmt.Errorf("can not generate universal task, see coordinator log for the reason")
} }
@@ -201,6 +224,23 @@ func (b *BaseProverTask) applyUniversal(schema *coordinatorType.GetTaskSchema) (
return schema, []byte(metadata), nil return schema, []byte(metadata), nil
} }
const CompatibilityVersion = "4.5.43"
func isCompatibilityFixingVersion(ver string) bool {
return !version.CheckScrollRepoVersion(ver, CompatibilityVersion)
}
func fixCompatibility(schema *coordinatorType.GetTaskSchema) error {
fixedTask, err := libzkp.UniversalTaskCompatibilityFix(schema.TaskData)
if err != nil {
return err
}
schema.TaskData = fixedTask
return nil
}
func newGetTaskCounterVec(factory promauto.Factory, taskType string) *prometheus.CounterVec { func newGetTaskCounterVec(factory promauto.Factory, taskType string) *prometheus.CounterVec {
getTaskCounterInitOnce.Do(func() { getTaskCounterInitOnce.Do(func() {
getTaskCounterVec = factory.NewCounterVec(prometheus.CounterOpts{ getTaskCounterVec = factory.NewCounterVec(prometheus.CounterOpts{

View File

@@ -155,7 +155,7 @@ func NewSubmitProofReceiverLogic(cfg *config.ProverManager, chainCfg *params.Cha
// HandleZkProof handle a ZkProof submitted from a prover. // HandleZkProof handle a ZkProof submitted from a prover.
// For now only proving/verifying error will lead to setting status as skipped. // For now only proving/verifying error will lead to setting status as skipped.
// db/unmarshal errors will not because they are errors on the business logic side. // db/unmarshal errors will not because they are errors on the business logic side.
func (m *ProofReceiverLogic) HandleZkProof(ctx *gin.Context, proofParameter coordinatorType.SubmitProofParameter) error { func (m *ProofReceiverLogic) HandleZkProof(ctx *gin.Context, proofParameter coordinatorType.SubmitProofParameter) (rerr error) {
m.proofReceivedTotal.Inc() m.proofReceivedTotal.Inc()
pk := ctx.GetString(coordinatorType.PublicKey) pk := ctx.GetString(coordinatorType.PublicKey)
if len(pk) == 0 { if len(pk) == 0 {
@@ -172,6 +172,18 @@ func (m *ProofReceiverLogic) HandleZkProof(ctx *gin.Context, proofParameter coor
return ErrValidatorFailureProverTaskEmpty return ErrValidatorFailureProverTaskEmpty
} }
defer func() {
if rerr != nil && types.ProverProveStatus(proverTask.ProvingStatus) == types.ProverAssigned {
// trigger a last-chance closing of current task if some routine had missed it
log.Warn("last chance proof recover triggerred",
"proofID", proofParameter.TaskID,
"err", rerr,
)
m.proofRecover(ctx.Copy(), proverTask, types.ProverTaskFailureTypeUndefined, proofParameter)
}
}()
proofTime := time.Since(proverTask.CreatedAt) proofTime := time.Since(proverTask.CreatedAt)
proofTimeSec := uint64(proofTime.Seconds()) proofTimeSec := uint64(proofTime.Seconds())
@@ -311,6 +323,20 @@ func (m *ProofReceiverLogic) validator(ctx context.Context, proverTask *orm.Prov
} }
}() }()
// Internally we overide the timeout failure:
// if prover task FailureType is SessionInfoFailureTimeout, the submit proof is timeout, but we still accept it
if types.ProverProveStatus(proverTask.ProvingStatus) == types.ProverProofInvalid &&
types.ProverTaskFailureType(proverTask.FailureType) == types.ProverTaskFailureTypeTimeout {
m.validateFailureProverTaskTimeout.Inc()
proverTask.ProvingStatus = int16(types.ProverAssigned)
proofTime := time.Since(proverTask.CreatedAt)
proofTimeSec := uint64(proofTime.Seconds())
log.Warn("proof submit proof have timeout", "hash", proofParameter.TaskID, "taskType", proverTask.TaskType,
"proverName", proverTask.ProverName, "proverPublicKey", pk, "proofTime", proofTimeSec)
}
// Ensure this prover is eligible to participate in the prover task. // Ensure this prover is eligible to participate in the prover task.
if types.ProverProveStatus(proverTask.ProvingStatus) == types.ProverProofValid || if types.ProverProveStatus(proverTask.ProvingStatus) == types.ProverProofValid ||
types.ProverProveStatus(proverTask.ProvingStatus) == types.ProverProofInvalid { types.ProverProveStatus(proverTask.ProvingStatus) == types.ProverProofInvalid {
@@ -328,9 +354,6 @@ func (m *ProofReceiverLogic) validator(ctx context.Context, proverTask *orm.Prov
return ErrValidatorFailureProverTaskCannotSubmitTwice return ErrValidatorFailureProverTaskCannotSubmitTwice
} }
proofTime := time.Since(proverTask.CreatedAt)
proofTimeSec := uint64(proofTime.Seconds())
if proofParameter.Status != int(coordinatorType.StatusOk) { if proofParameter.Status != int(coordinatorType.StatusOk) {
// Temporarily replace "panic" with "pa-nic" to prevent triggering the alert based on logs. // Temporarily replace "panic" with "pa-nic" to prevent triggering the alert based on logs.
failureMsg := strings.Replace(proofParameter.FailureMsg, "panic", "pa-nic", -1) failureMsg := strings.Replace(proofParameter.FailureMsg, "panic", "pa-nic", -1)
@@ -346,14 +369,6 @@ func (m *ProofReceiverLogic) validator(ctx context.Context, proverTask *orm.Prov
return ErrValidatorFailureProofMsgStatusNotOk return ErrValidatorFailureProofMsgStatusNotOk
} }
// if prover task FailureType is SessionInfoFailureTimeout, the submit proof is timeout, need skip it
if types.ProverTaskFailureType(proverTask.FailureType) == types.ProverTaskFailureTypeTimeout {
m.validateFailureProverTaskTimeout.Inc()
log.Info("proof submit proof have timeout, skip this submit proof", "hash", proofParameter.TaskID, "taskType", proverTask.TaskType,
"proverName", proverTask.ProverName, "proverPublicKey", pk, "proofTime", proofTimeSec)
return ErrValidatorFailureProofTimeout
}
// store the proof to prover task // store the proof to prover task
if updateTaskProofErr := m.updateProverTaskProof(ctx, proverTask, proofParameter); updateTaskProofErr != nil { if updateTaskProofErr := m.updateProverTaskProof(ctx, proverTask, proofParameter); updateTaskProofErr != nil {
log.Warn("update prover task proof failure", "hash", proofParameter.TaskID, "proverPublicKey", pk, log.Warn("update prover task proof failure", "hash", proofParameter.TaskID, "proverPublicKey", pk,
@@ -368,6 +383,7 @@ func (m *ProofReceiverLogic) validator(ctx context.Context, proverTask *orm.Prov
"taskType", proverTask.TaskType, "proverName", proverTask.ProverName, "proverPublicKey", pk) "taskType", proverTask.TaskType, "proverName", proverTask.ProverName, "proverPublicKey", pk)
return ErrValidatorFailureTaskHaveVerifiedSuccess return ErrValidatorFailureTaskHaveVerifiedSuccess
} }
return nil return nil
} }
@@ -384,7 +400,7 @@ func (m *ProofReceiverLogic) closeProofTask(ctx context.Context, proverTask *orm
log.Info("proof close task update proof status", "hash", proverTask.TaskID, "proverPublicKey", proverTask.ProverPublicKey, log.Info("proof close task update proof status", "hash", proverTask.TaskID, "proverPublicKey", proverTask.ProverPublicKey,
"taskType", message.ProofType(proverTask.TaskType).String(), "status", types.ProvingTaskVerified.String()) "taskType", message.ProofType(proverTask.TaskType).String(), "status", types.ProvingTaskVerified.String())
if err := m.updateProofStatus(ctx, proverTask, proofParameter, types.ProverProofValid, types.ProverTaskFailureTypeUndefined, proofTimeSec); err != nil { if err := m.updateProofStatus(ctx, proverTask, proofParameter, types.ProverProofValid, types.ProverTaskFailureType(proverTask.FailureType), proofTimeSec); err != nil {
log.Error("failed to updated proof status ProvingTaskVerified", "hash", proverTask.TaskID, "proverPublicKey", proverTask.ProverPublicKey, "error", err) log.Error("failed to updated proof status ProvingTaskVerified", "hash", proverTask.TaskID, "proverPublicKey", proverTask.ProverPublicKey, "error", err)
return err return err
} }
@@ -445,6 +461,9 @@ func (m *ProofReceiverLogic) updateProofStatus(ctx context.Context, proverTask *
if err != nil { if err != nil {
return err return err
} }
// sync status and failture type into proverTask
proverTask.ProvingStatus = int16(status)
proverTask.FailureType = int16(failureType)
if status == types.ProverProofValid && message.ProofType(proofParameter.TaskType) == message.ProofTypeChunk { if status == types.ProverProofValid && message.ProofType(proofParameter.TaskType) == message.ProofTypeChunk {
if checkReadyErr := m.checkAreAllChunkProofsReady(ctx, proverTask.TaskID); checkReadyErr != nil { if checkReadyErr := m.checkAreAllChunkProofsReady(ctx, proverTask.TaskID); checkReadyErr != nil {

View File

@@ -9,7 +9,7 @@ import (
) )
// NewVerifier Sets up a mock verifier. // NewVerifier Sets up a mock verifier.
func NewVerifier(cfg *config.VerifierConfig) (*Verifier, error) { func NewVerifier(cfg *config.VerifierConfig, _ bool) (*Verifier, error) {
return &Verifier{ return &Verifier{
cfg: cfg, cfg: cfg,
OpenVMVkMap: map[string]struct{}{"mock_vk": {}}, OpenVMVkMap: map[string]struct{}{"mock_vk": {}},

View File

@@ -19,20 +19,36 @@ import (
"scroll-tech/coordinator/internal/config" "scroll-tech/coordinator/internal/config"
"scroll-tech/coordinator/internal/logic/libzkp" "scroll-tech/coordinator/internal/logic/libzkp"
"scroll-tech/coordinator/internal/utils"
) )
// This struct maps to `CircuitConfig` in libzkp/src/verifier.rs // This struct maps to `CircuitConfig` in libzkp/src/verifier.rs
// Define a brand new struct here is to eliminate side effects in case fields // Define a brand new struct here is to eliminate side effects in case fields
// in `*config.CircuitConfig` being changed // in `*config.CircuitConfig` being changed
type rustCircuitConfig struct { type rustCircuitConfig struct {
Version uint `json:"version"`
ForkName string `json:"fork_name"` ForkName string `json:"fork_name"`
AssetsPath string `json:"assets_path"` AssetsPath string `json:"assets_path"`
Features string `json:"features,omitempty"`
} }
var validiumMode bool
func newRustCircuitConfig(cfg config.AssetConfig) *rustCircuitConfig { func newRustCircuitConfig(cfg config.AssetConfig) *rustCircuitConfig {
ver := cfg.Version
if ver == 0 {
var err error
ver, err = utils.Version(cfg.ForkName, validiumMode)
if err != nil {
panic(err)
}
}
return &rustCircuitConfig{ return &rustCircuitConfig{
ForkName: cfg.ForkName, Version: uint(ver),
AssetsPath: cfg.AssetsPath, AssetsPath: cfg.AssetsPath,
ForkName: cfg.ForkName,
Features: cfg.Features,
} }
} }
@@ -60,7 +76,8 @@ type rustVkDump struct {
} }
// NewVerifier Sets up a rust ffi to call verify. // NewVerifier Sets up a rust ffi to call verify.
func NewVerifier(cfg *config.VerifierConfig) (*Verifier, error) { func NewVerifier(cfg *config.VerifierConfig, useValidiumMode bool) (*Verifier, error) {
validiumMode = useValidiumMode
verifierConfig := newRustVerifierConfig(cfg) verifierConfig := newRustVerifierConfig(cfg)
configBytes, err := json.Marshal(verifierConfig) configBytes, err := json.Marshal(verifierConfig)
if err != nil { if err != nil {

View File

@@ -0,0 +1,91 @@
package utils
import (
"encoding/binary"
"fmt"
"github.com/scroll-tech/go-ethereum/common"
)
type CodecVersion uint8
const (
daBatchValidiumEncodedLength = 137
)
type DABatch interface {
SetHash(common.Hash)
}
type daBatchValidiumV1 struct {
Version CodecVersion `json:"version"`
BatchIndex uint64 `json:"batch_index"`
ParentBatchHash common.Hash `json:"parent_batch_hash"`
PostStateRoot common.Hash `json:"post_state_root"`
WithDrawRoot common.Hash `json:"withdraw_root"`
Commitment common.Hash `json:"commitment"`
}
type daBatchValidium struct {
V1 *daBatchValidiumV1 `json:"V1,omitempty"`
BatchHash common.Hash `json:"batch_hash"`
}
func (da *daBatchValidium) SetHash(h common.Hash) {
da.BatchHash = h
}
func FromVersion(v uint8) CodecVersion {
return CodecVersion(v & STFVersionMask)
}
func (c CodecVersion) DABatchForTaskFromBytes(b []byte) (DABatch, error) {
switch c {
case 1:
if v1, err := decodeDABatchV1(b); err == nil {
return &daBatchValidium{
V1: v1,
}, nil
} else {
return nil, err
}
default:
return nil, fmt.Errorf("unknown codec type %d", c)
}
}
func decodeDABatchV1(data []byte) (*daBatchValidiumV1, error) {
if len(data) != daBatchValidiumEncodedLength {
return nil, fmt.Errorf("invalid data length for DABatchV7, expected %d bytes but got %d", daBatchValidiumEncodedLength, len(data))
}
const (
versionSize = 1
indexSize = 8
hashSize = 32
)
// Offsets (same as encodeBatchHeaderValidium)
versionOffset := 0
indexOffset := versionOffset + versionSize
parentHashOffset := indexOffset + indexSize
stateRootOffset := parentHashOffset + hashSize
withdrawRootOffset := stateRootOffset + hashSize
commitmentOffset := withdrawRootOffset + hashSize
version := CodecVersion(data[versionOffset])
batchIndex := binary.BigEndian.Uint64(data[indexOffset : indexOffset+indexSize])
parentBatchHash := common.BytesToHash(data[parentHashOffset : parentHashOffset+hashSize])
postStateRoot := common.BytesToHash(data[stateRootOffset : stateRootOffset+hashSize])
withdrawRoot := common.BytesToHash(data[withdrawRootOffset : withdrawRootOffset+hashSize])
commitment := common.BytesToHash(data[commitmentOffset : commitmentOffset+hashSize])
return &daBatchValidiumV1{
Version: version,
BatchIndex: batchIndex,
ParentBatchHash: parentBatchHash,
PostStateRoot: postStateRoot,
WithDrawRoot: withdrawRoot,
Commitment: commitment,
}, nil
}

View File

@@ -0,0 +1,42 @@
package utils
import (
"errors"
"strings"
)
const (
DomainOffset = 6
STFVersionMask = (1 << DomainOffset) - 1
)
// version get the version for the chain instance
//
// TODO: This is not foolproof and does not cover all scenarios.
func Version(hardForkName string, ValidiumMode bool) (uint8, error) {
var domain, stfVersion uint8
if ValidiumMode {
domain = 1
stfVersion = 1
} else {
domain = 0
switch canonicalName := strings.ToLower(hardForkName); canonicalName {
case "euclidv1":
stfVersion = 6
case "euclidv2":
stfVersion = 7
case "feynman":
stfVersion = 8
case "galileo":
stfVersion = 9
case "galileov2":
stfVersion = 10
default:
return 0, errors.New("unknown fork name " + canonicalName)
}
}
return (domain << DomainOffset) + stfVersion, nil
}

View File

@@ -132,7 +132,7 @@ func setupCoordinator(t *testing.T, proversPerSession uint8, coordinatorURL stri
func setEnv(t *testing.T) { func setEnv(t *testing.T) {
var err error var err error
version.Version = "v4.4.89" version.Version = "v4.5.45"
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat())) glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat()))
glogger.Verbosity(log.LvlInfo) glogger.Verbosity(log.LvlInfo)

View File

@@ -1,45 +0,0 @@
[patch."https://github.com/openvm-org/openvm.git"]
openvm-build = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-circuit = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-continuations = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-instructions ={ git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-native-circuit = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-native-compiler = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-native-recursion = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-native-transpiler = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-rv32im-transpiler = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
openvm-sdk = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false, features = ["parallel", "bench-metrics", "evm-prove"] }
openvm-transpiler = { git = "ssh://git@github.com/scroll-tech/openvm-gpu.git", branch = "patch-v1.3.0-pipe", default-features = false }
[patch."https://github.com/openvm-org/stark-backend.git"]
openvm-stark-backend = { git = "ssh://git@github.com/scroll-tech/openvm-stark-gpu.git", branch = "main", features = ["gpu"] }
openvm-stark-sdk = { git = "ssh://git@github.com/scroll-tech/openvm-stark-gpu.git", branch = "main", features = ["gpu"] }
[patch."https://github.com/Plonky3/Plonky3.git"]
p3-air = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-field = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-commit = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-matrix = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-baby-bear = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", features = [
"nightly-features",
], tag = "v0.2.1" }
p3-koala-bear = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-util = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-challenger = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-dft = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-fri = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-goldilocks = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-keccak = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-keccak-air = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-blake3 = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-mds = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-merkle-tree = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-monty-31 = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-poseidon = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-poseidon2 = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-poseidon2-air = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-symmetric = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-uni-stark = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }
p3-maybe-rayon = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" } # the "parallel" feature is NOT on by default to allow single-threaded benchmarking
p3-bn254-fr = { git = "ssh://git@github.com/scroll-tech/plonky3-gpu.git", tag = "v0.2.1" }

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +0,0 @@
.PHONY: build update clean
ZKVM_COMMIT ?= freebuild
PLONKY3_GPU_VERSION=$(shell ./print_plonky3gpu_version.sh | sed -n '2p')
$(info PLONKY3_GPU_VERSION is ${PLONKY3_GPU_VERSION})
GIT_REV ?= $(shell git rev-parse --short HEAD)
GO_TAG ?= $(shell grep "var tag = " ../../common/version/version.go | cut -d "\"" -f2)
ZK_VERSION=${ZKVM_COMMIT}-${PLONKY3_GPU_VERSION}
$(info ZK_GPU_VERSION is ${ZK_VERSION})
clean:
cargo clean -Z unstable-options --release -p prover --lockfile-path ./Cargo.lock
# build gpu prover, never touch lock file
build:
GO_TAG=${GO_TAG} GIT_REV=${GIT_REV} ZK_VERSION=${ZK_VERSION} cargo build -Z unstable-options --release -p prover --lockfile-path ./Cargo.lock
version:
echo ${GO_TAG}-${GIT_REV}-${ZK_VERSION}
# update Cargo.lock while override config has been updated
#update:
# GO_TAG=${GO_TAG} GIT_REV=${GIT_REV} ZK_VERSION=${ZK_VERSION} cargo build -Z unstable-options --release -p prover --lockfile-path ./Cargo.lock

View File

@@ -1,10 +0,0 @@
#!/bin/bash
higher_plonky3_item=`grep "plonky3-gpu" ./Cargo.lock | sort | uniq | awk -F "[#=]" '{print $3" "$4}' | sort -k 1 | tail -n 1`
higher_version=`echo $higher_plonky3_item | awk '{print $1}'`
higher_commit=`echo $higher_plonky3_item | cut -d ' ' -f2 | cut -c-7`
echo "$higher_version"
echo "$higher_commit"

View File

@@ -13,6 +13,7 @@ libzkp = { path = "../libzkp" }
alloy = { workspace = true, features = ["provider-http", "transport-http", "reqwest", "reqwest-rustls-tls", "json-rpc"] } alloy = { workspace = true, features = ["provider-http", "transport-http", "reqwest", "reqwest-rustls-tls", "json-rpc"] }
sbv-primitives = { workspace = true, features = ["scroll"] } sbv-primitives = { workspace = true, features = ["scroll"] }
sbv-utils = { workspace = true, features = ["scroll"] } sbv-utils = { workspace = true, features = ["scroll"] }
sbv-core = { workspace = true, features = ["scroll"] }
eyre.workspace = true eyre.workspace = true

View File

@@ -11,7 +11,7 @@ pub fn init(config: &str) -> eyre::Result<()> {
Ok(()) Ok(())
} }
pub fn get_client() -> rpc_client::RpcClient<'static> { pub fn get_client() -> impl libzkp::tasks::ChunkInterpreter {
GLOBAL_L2GETH_CLI GLOBAL_L2GETH_CLI
.get() .get()
.expect("must has been inited") .expect("must has been inited")

View File

@@ -1,11 +1,11 @@
use alloy::{ use alloy::{
providers::{Provider, ProviderBuilder, RootProvider}, providers::{Provider, ProviderBuilder},
rpc::client::ClientBuilder, rpc::client::ClientBuilder,
transports::layers::RetryBackoffLayer, transports::layers::RetryBackoffLayer,
}; };
use eyre::Result; use eyre::Result;
use libzkp::tasks::ChunkInterpreter; use libzkp::tasks::ChunkInterpreter;
use sbv_primitives::types::Network; use sbv_primitives::types::{consensus::TxL1Message, Network};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
fn default_max_retry() -> u32 { fn default_max_retry() -> u32 {
@@ -49,13 +49,13 @@ pub struct RpcConfig {
/// so it can be run in block mode (i.e. inside dynamic library without a global entry) /// so it can be run in block mode (i.e. inside dynamic library without a global entry)
pub struct RpcClientCore { pub struct RpcClientCore {
/// rpc prover /// rpc prover
provider: RootProvider<Network>, client: alloy::rpc::client::RpcClient,
rt: tokio::runtime::Runtime, rt: tokio::runtime::Runtime,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct RpcClient<'a> { pub struct RpcClient<'a, T: Provider<Network>> {
provider: &'a RootProvider<Network>, provider: T,
handle: &'a tokio::runtime::Handle, handle: &'a tokio::runtime::Handle,
} }
@@ -75,80 +75,78 @@ impl RpcClientCore {
let retry_layer = RetryBackoffLayer::new(config.max_retry, config.backoff, config.cups); let retry_layer = RetryBackoffLayer::new(config.max_retry, config.backoff, config.cups);
let client = ClientBuilder::default().layer(retry_layer).http(rpc); let client = ClientBuilder::default().layer(retry_layer).http(rpc);
Ok(Self { Ok(Self { client, rt })
provider: ProviderBuilder::<_, _, Network>::default().connect_client(client),
rt,
})
} }
pub fn get_client(&self) -> RpcClient { pub fn get_client(&self) -> RpcClient<'_, impl Provider<Network>> {
RpcClient { RpcClient {
provider: &self.provider, provider: ProviderBuilder::<_, _, Network>::default()
.connect_client(self.client.clone()),
handle: self.rt.handle(), handle: self.rt.handle(),
} }
} }
} }
impl ChunkInterpreter for RpcClient<'_> { impl<T: Provider<Network>> ChunkInterpreter for RpcClient<'_, T> {
fn try_fetch_block_witness( fn try_fetch_block_witness(
&self, &self,
block_hash: sbv_primitives::B256, block_hash: sbv_primitives::B256,
prev_witness: Option<&sbv_primitives::types::BlockWitness>, prev_witness: Option<&sbv_core::BlockWitness>,
) -> Result<sbv_primitives::types::BlockWitness> { ) -> Result<sbv_core::BlockWitness> {
async fn fetch_witness_async( async fn fetch_witness_async(
provider: &RootProvider<Network>, provider: impl Provider<Network>,
block_hash: sbv_primitives::B256, block_hash: sbv_primitives::B256,
prev_witness: Option<&sbv_primitives::types::BlockWitness>, prev_witness: Option<&sbv_core::BlockWitness>,
) -> Result<sbv_primitives::types::BlockWitness> { ) -> Result<sbv_core::BlockWitness> {
use sbv_utils::{rpc::ProviderExt, witness::WitnessBuilder}; use sbv_utils::rpc::ProviderExt;
let chain_id = provider.get_chain_id().await?; let (chain_id, block_num, prev_state_root) = if let Some(w) = prev_witness {
(w.chain_id, w.header.number + 1, w.header.state_root)
} else {
let chain_id = provider.get_chain_id().await?;
let block = provider
.get_block_by_hash(block_hash)
.full()
.await?
.ok_or_else(|| eyre::eyre!("Block {block_hash} not found"))?;
let block = provider let parent_block = provider
.get_block_by_hash(block_hash) .get_block_by_hash(block.header.parent_hash)
.full() .await?
.await? .ok_or_else(|| {
.ok_or_else(|| eyre::eyre!("Block {block_hash} not found"))?; eyre::eyre!(
"parent block for block {} should exist",
block.header.number
)
})?;
let number = block.header.number; (
let parent_hash = block.header.parent_hash; chain_id,
if number == 0 { block.header.number,
eyre::bail!("no number in header or use block 0"); parent_block.header.state_root,
} )
let mut witness_builder = WitnessBuilder::new()
.block(block)
.chain_id(chain_id)
.execution_witness(provider.debug_execution_witness(number.into()).await?);
let prev_state_root = match prev_witness {
Some(witness) => {
if witness.header.number != number - 1 {
eyre::bail!(
"the ref witness is not the previous block, expected {} get {}",
number - 1,
witness.header.number,
);
}
witness.header.state_root
}
None => {
let parent_block = provider
.get_block_by_hash(parent_hash)
.await?
.expect("parent block should exist");
parent_block.header.state_root
}
}; };
witness_builder = witness_builder.prev_state_root(prev_state_root);
Ok(witness_builder.build()?) let req = provider
.dump_block_witness(block_num)
.with_chain_id(chain_id)
.with_prev_state_root(prev_state_root);
let witness = req
.send()
.await
.transpose()
.ok_or_else(|| eyre::eyre!("Block witness {block_num} not available"))??;
Ok(witness)
} }
tracing::debug!("fetch witness for {block_hash}"); tracing::debug!("fetch witness for {block_hash}");
self.handle self.handle.block_on(fetch_witness_async(
.block_on(fetch_witness_async(self.provider, block_hash, prev_witness)) &self.provider,
block_hash,
prev_witness,
))
} }
fn try_fetch_storage_node( fn try_fetch_storage_node(
@@ -156,7 +154,7 @@ impl ChunkInterpreter for RpcClient<'_> {
node_hash: sbv_primitives::B256, node_hash: sbv_primitives::B256,
) -> Result<sbv_primitives::Bytes> { ) -> Result<sbv_primitives::Bytes> {
async fn fetch_storage_node_async( async fn fetch_storage_node_async(
provider: &RootProvider<Network>, provider: impl Provider<Network>,
node_hash: sbv_primitives::B256, node_hash: sbv_primitives::B256,
) -> Result<sbv_primitives::Bytes> { ) -> Result<sbv_primitives::Bytes> {
let ret = provider let ret = provider
@@ -168,7 +166,41 @@ impl ChunkInterpreter for RpcClient<'_> {
tracing::debug!("fetch storage node for {node_hash}"); tracing::debug!("fetch storage node for {node_hash}");
self.handle self.handle
.block_on(fetch_storage_node_async(self.provider, node_hash)) .block_on(fetch_storage_node_async(&self.provider, node_hash))
}
fn try_fetch_l1_msgs(&self, block_number: u64) -> Result<Vec<TxL1Message>> {
async fn fetch_l1_msgs(
provider: impl Provider<Network>,
block_number: u64,
) -> Result<Vec<TxL1Message>> {
let block_number_hex = format!("0x{:x}", block_number);
#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum NullOrVec {
Null, // matches JSON `null`
Vec(Vec<TxL1Message>), // matches JSON array
}
Ok(
match provider
.client()
.request::<_, NullOrVec>(
"scroll_getL1MessagesInBlock",
(block_number_hex, "synced"),
)
.await?
{
NullOrVec::Null => Vec::new(),
NullOrVec::Vec(r) => r,
},
)
}
tracing::debug!("fetch L1 msgs for {block_number}");
self.handle
.block_on(fetch_l1_msgs(&self.provider, block_number))
} }
} }
@@ -194,10 +226,10 @@ mod tests {
let client_core = RpcClientCore::create(&config).expect("Failed to create RPC client"); let client_core = RpcClientCore::create(&config).expect("Failed to create RPC client");
let client = client_core.get_client(); let client = client_core.get_client();
// latest - 1 block in 2025.6.15 // latest - 1 block in 2025.9.11
let block_hash = B256::from( let block_hash = B256::from(
hex::const_decode_to_array( hex::const_decode_to_array(
b"0x9535a6970bc4db9031749331a214e35ed8c8a3f585f6f456d590a0bc780a1368", b"0x093fb6bf2e556a659b35428ac447cd9f0635382fc40ffad417b5910824f9e932",
) )
.unwrap(), .unwrap(),
); );
@@ -207,10 +239,10 @@ mod tests {
.try_fetch_block_witness(block_hash, None) .try_fetch_block_witness(block_hash, None)
.expect("should success"); .expect("should success");
// latest block in 2025.6.15 // block selected in 2025.9.11
let block_hash = B256::from( let block_hash = B256::from(
hex::const_decode_to_array( hex::const_decode_to_array(
b"0xd47088cdb6afc68aa082e633bb7da9340d29c73841668afacfb9c1e66e557af0", b"0x77cc84dd7a4dedf6fe5fb9b443aeb5a4fb0623ad088a365d3232b7b23fc848e5",
) )
.unwrap(), .unwrap(),
); );
@@ -223,23 +255,13 @@ mod tests {
#[test] #[test]
#[ignore = "Requires L2GETH_ENDPOINT environment variable"] #[ignore = "Requires L2GETH_ENDPOINT environment variable"]
fn test_try_fetch_storage_node() { fn test_try_fetch_l1_messages() {
let config = create_config_from_env(); let config = create_config_from_env();
let client_core = RpcClientCore::create(&config).expect("Failed to create RPC client"); let client_core = RpcClientCore::create(&config).expect("Failed to create RPC client");
let client = client_core.get_client(); let client = client_core.get_client();
// the root node (state root) of the block in unittest above let msgs = client.try_fetch_l1_msgs(32).expect("should success");
let node_hash = B256::from(
hex::const_decode_to_array(
b"0xb9e67403a2eb35afbb0475fe942918cf9a330a1d7532704c24554506be62b27c",
)
.unwrap(),
);
// This is expected to fail since we're using a dummy hash, but it tests the code path println!("{}", serde_json::to_string_pretty(&msgs).unwrap());
let node = client
.try_fetch_storage_node(node_hash)
.expect("should success");
println!("{}", serde_json::to_string_pretty(&node).unwrap());
} }
} }

View File

@@ -5,11 +5,12 @@ edition.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
scroll-zkvm-types.workspace = true scroll-zkvm-types = { workspace = true, features = ["scroll"] }
scroll-zkvm-verifier.workspace = true scroll-zkvm-verifier.workspace = true
alloy-primitives.workspace = true #depress the effect of "native-keccak" alloy-primitives.workspace = true #depress the effect of "native-keccak"
sbv-primitives = {workspace = true, features = ["scroll-compress-ratio", "scroll"]} sbv-primitives = {workspace = true, features = ["scroll-compress-info", "scroll"]}
sbv-core = { workspace = true, features = ["scroll"] }
base64.workspace = true base64.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true
@@ -18,6 +19,7 @@ tracing.workspace = true
eyre.workspace = true eyre.workspace = true
git-version = "0.3.5" git-version = "0.3.5"
bincode = { version = "2", features = ["serde"] }
serde_stacker = "0.1" serde_stacker = "0.1"
regex = "1.11" regex = "1.11"
c-kzg = { version = "2.0", features = ["serde"] } c-kzg = { version = "2.0", features = ["serde"] }

View File

@@ -1,28 +1,112 @@
pub mod proofs; pub mod proofs;
pub mod tasks; pub mod tasks;
pub use tasks::ProvingTaskExt;
pub mod verifier; pub mod verifier;
use verifier::HardForkName;
pub use verifier::{TaskType, VerifierConfig}; pub use verifier::{TaskType, VerifierConfig};
mod utils; mod utils;
use sbv_primitives::B256; use sbv_primitives::B256;
use scroll_zkvm_types::utils::vec_as_base64; use scroll_zkvm_types::{utils::vec_as_base64, version::Version};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::value::RawValue; use serde_json::value::RawValue;
use std::path::Path; use std::{collections::HashMap, path::Path, sync::OnceLock};
use tasks::chunk_interpreter::{ChunkInterpreter, TryFromWithInterpreter}; use tasks::chunk_interpreter::{ChunkInterpreter, TryFromWithInterpreter};
pub(crate) fn witness_use_legacy_mode(fork_name: &str) -> eyre::Result<bool> {
ADDITIONAL_FEATURES
.get()
.and_then(|features| features.get(fork_name))
.map(|cfg| cfg.legacy_witness_encoding)
.ok_or_else(|| {
eyre::eyre!(
"can not find features setting for unrecognized fork {}",
fork_name
)
})
}
#[derive(Debug, Default, Clone)]
struct FeatureOptions {
legacy_witness_encoding: bool,
for_openvm_13_prover: bool,
}
static ADDITIONAL_FEATURES: OnceLock<HashMap<HardForkName, FeatureOptions>> = OnceLock::new();
impl FeatureOptions {
pub fn new(feats: &str) -> Self {
let mut ret: Self = Default::default();
for feat_s in feats.split(':') {
match feat_s.trim().to_lowercase().as_str() {
"legacy_witness" => {
tracing::info!("set witness encoding for legacy mode");
ret.legacy_witness_encoding = true;
}
"openvm_13" => {
tracing::info!("set prover should use openvm 13");
ret.for_openvm_13_prover = true;
}
s => tracing::warn!("unrecognized dynamic feature: {s}"),
}
}
ret
}
}
/// Turn the coordinator's chunk task into a json string for formal chunk proving /// Turn the coordinator's chunk task into a json string for formal chunk proving
/// task (with full witnesses) /// task (with full witnesses)
pub fn checkout_chunk_task( pub fn checkout_chunk_task(
task_json: &str, task_json: &str,
decryption_key: Option<&[u8]>,
interpreter: impl ChunkInterpreter, interpreter: impl ChunkInterpreter,
) -> eyre::Result<String> { ) -> eyre::Result<String> {
let chunk_task = serde_json::from_str::<tasks::ChunkTask>(task_json)?; let chunk_task = serde_json::from_str::<tasks::ChunkTask>(task_json)?;
let ret = serde_json::to_string(&tasks::ChunkProvingTask::try_from_with_interpret( Ok(serde_json::to_string(
chunk_task, &tasks::ChunkProvingTask::try_from_with_interpret(chunk_task, decryption_key, interpreter)?,
interpreter, )?)
)?)?; }
Ok(ret)
/// Convert the universal task json into compatible form for old prover
pub fn univ_task_compatibility_fix(task_json: &str) -> eyre::Result<String> {
use scroll_zkvm_types::proof::VmInternalStarkProof;
let task: tasks::ProvingTask = serde_json::from_str(task_json)?;
let aggregated_proofs: Vec<VmInternalStarkProof> = task
.aggregated_proofs
.into_iter()
.map(|proof| VmInternalStarkProof {
proofs: proof.proofs,
public_values: proof.public_values,
})
.collect();
#[derive(Serialize)]
struct CompatibleProvingTask {
/// seralized witness which should be written into stdin first
pub serialized_witness: Vec<Vec<u8>>,
/// aggregated proof carried by babybear fields, should be written into stdin
/// followed `serialized_witness`
pub aggregated_proofs: Vec<VmInternalStarkProof>,
/// Fork name specify
pub fork_name: String,
/// The vk of app which is expcted to prove this task
pub vk: Vec<u8>,
/// An identifier assigned by coordinator, it should be kept identify for the
/// same task (for example, using chunk, batch and bundle hashes)
pub identifier: String,
}
let compatible_u_task = CompatibleProvingTask {
serialized_witness: task.serialized_witness,
aggregated_proofs,
fork_name: task.fork_name,
vk: task.vk,
identifier: task.identifier,
};
Ok(serde_json::to_string(&compatible_u_task)?)
} }
/// Generate required staff for proving tasks /// Generate required staff for proving tasks
@@ -32,7 +116,6 @@ pub fn gen_universal_task(
task_json: &str, task_json: &str,
fork_name_str: &str, fork_name_str: &str,
expected_vk: &[u8], expected_vk: &[u8],
interpreter: Option<impl ChunkInterpreter>,
) -> eyre::Result<(B256, String, String)> { ) -> eyre::Result<(B256, String, String)> {
use proofs::*; use proofs::*;
use tasks::*; use tasks::*;
@@ -51,36 +134,56 @@ pub fn gen_universal_task(
let mut task = serde_json::from_str::<ChunkProvingTask>(task_json)?; let mut task = serde_json::from_str::<ChunkProvingTask>(task_json)?;
// normailze fork name field in task // normailze fork name field in task
task.fork_name = task.fork_name.to_lowercase(); task.fork_name = task.fork_name.to_lowercase();
let version = Version::from(task.version);
// always respect the fork_name_str (which has been normalized) being passed // always respect the fork_name_str (which has been normalized) being passed
// if the fork_name wrapped in task is not match, consider it a malformed task // if the fork_name wrapped in task is not match, consider it a malformed task
if fork_name_str != task.fork_name.as_str() { if fork_name_str != task.fork_name.as_str() {
eyre::bail!("fork name in chunk task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name); eyre::bail!("fork name in chunk task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name);
} }
let (pi_hash, metadata, u_task) = utils::panic_catch(move || { if fork_name_str != version.fork.as_str() {
gen_universal_chunk_task(task, fork_name_str.into(), interpreter) eyre::bail!(
}) "given task version, expected fork={fork_name_str}, got={version_fork}",
.map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??; version_fork = version.fork.as_str()
);
}
let (pi_hash, metadata, u_task) =
utils::panic_catch(move || gen_universal_chunk_task(task))
.map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??;
(pi_hash, AnyMetaData::Chunk(metadata), u_task) (pi_hash, AnyMetaData::Chunk(metadata), u_task)
} }
x if x == TaskType::Batch as i32 => { x if x == TaskType::Batch as i32 => {
let mut task = serde_json::from_str::<BatchProvingTask>(task_json)?; let mut task = serde_json::from_str::<BatchProvingTask>(task_json)?;
task.fork_name = task.fork_name.to_lowercase(); task.fork_name = task.fork_name.to_lowercase();
let version = Version::from(task.version);
if fork_name_str != task.fork_name.as_str() { if fork_name_str != task.fork_name.as_str() {
eyre::bail!("fork name in batch task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name); eyre::bail!("fork name in batch task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name);
} }
if fork_name_str != version.fork.as_str() {
eyre::bail!(
"given task version, expected fork={fork_name_str}, got={version_fork}",
version_fork = version.fork.as_str()
);
}
let (pi_hash, metadata, u_task) = let (pi_hash, metadata, u_task) =
utils::panic_catch(move || gen_universal_batch_task(task, fork_name_str.into())) utils::panic_catch(move || gen_universal_batch_task(task))
.map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??; .map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??;
(pi_hash, AnyMetaData::Batch(metadata), u_task) (pi_hash, AnyMetaData::Batch(metadata), u_task)
} }
x if x == TaskType::Bundle as i32 => { x if x == TaskType::Bundle as i32 => {
let mut task = serde_json::from_str::<BundleProvingTask>(task_json)?; let mut task = serde_json::from_str::<BundleProvingTask>(task_json)?;
task.fork_name = task.fork_name.to_lowercase(); task.fork_name = task.fork_name.to_lowercase();
let version = Version::from(task.version);
if fork_name_str != task.fork_name.as_str() { if fork_name_str != task.fork_name.as_str() {
eyre::bail!("fork name in bundle task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name); eyre::bail!("fork name in bundle task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name);
} }
if fork_name_str != version.fork.as_str() {
eyre::bail!(
"given task version, expected fork={fork_name_str}, got={version_fork}",
version_fork = version.fork.as_str()
);
}
let (pi_hash, metadata, u_task) = let (pi_hash, metadata, u_task) =
utils::panic_catch(move || gen_universal_bundle_task(task, fork_name_str.into())) utils::panic_catch(move || gen_universal_bundle_task(task))
.map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??; .map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??;
(pi_hash, AnyMetaData::Bundle(metadata), u_task) (pi_hash, AnyMetaData::Bundle(metadata), u_task)
} }
@@ -88,11 +191,26 @@ pub fn gen_universal_task(
}; };
u_task.vk = Vec::from(expected_vk); u_task.vk = Vec::from(expected_vk);
let fork_name = u_task.fork_name.clone();
let mut u_task_ext = ProvingTaskExt::new(u_task);
// set additional settings from global features
if let Some(cfg) = ADDITIONAL_FEATURES
.get()
.and_then(|features| features.get(&fork_name))
{
u_task_ext.use_openvm_13 = cfg.for_openvm_13_prover;
} else {
tracing::warn!(
"can not found features setting for unrecognized fork {}",
fork_name
);
}
Ok(( Ok((
pi_hash, pi_hash,
serde_json::to_string(&metadata)?, serde_json::to_string(&metadata)?,
serde_json::to_string(&u_task)?, serde_json::to_string(&u_task_ext)?,
)) ))
} }
@@ -123,7 +241,26 @@ pub fn gen_wrapped_proof(proof_json: &str, metadata: &str, vk: &[u8]) -> eyre::R
/// init verifier /// init verifier
pub fn verifier_init(config: &str) -> eyre::Result<()> { pub fn verifier_init(config: &str) -> eyre::Result<()> {
let cfg: VerifierConfig = serde_json::from_str(config)?; let cfg: VerifierConfig = serde_json::from_str(config)?;
ADDITIONAL_FEATURES
.set(HashMap::from_iter(cfg.circuits.iter().map(|config| {
tracing::info!(
"start setting features [{:?}] for fork {}",
config.features,
config.fork_name
);
(
config.fork_name.to_lowercase(),
config
.features
.as_ref()
.map(|features| FeatureOptions::new(features.as_str()))
.unwrap_or_default(),
)
})))
.map_err(|c| eyre::eyre!("Fail to init additional features: {c:?}"))?;
verifier::init(cfg); verifier::init(cfg);
Ok(()) Ok(())
} }

View File

@@ -8,9 +8,10 @@ use scroll_zkvm_types::{
bundle::BundleInfo, bundle::BundleInfo,
chunk::ChunkInfo, chunk::ChunkInfo,
proof::{EvmProof, OpenVmEvmProof, ProofEnum, StarkProof}, proof::{EvmProof, OpenVmEvmProof, ProofEnum, StarkProof},
public_inputs::{ForkName, MultiVersionPublicInputs}, public_inputs::MultiVersionPublicInputs,
types_agg::{AggregationInput, ProgramCommitment}, types_agg::AggregationInput,
utils::vec_as_base64, utils::{serialize_vk, vec_as_base64},
version,
}; };
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
@@ -139,8 +140,6 @@ impl ProofMetadata for ChunkProofMetadata {
pub struct BatchProofMetadata { pub struct BatchProofMetadata {
/// The batch information describing the list of chunks. /// The batch information describing the list of chunks.
pub batch_info: BatchInfo, pub batch_info: BatchInfo,
/// The [`scroll_zkvm_types::batch::BatchHeader`]'s digest.
pub batch_hash: B256,
} }
impl ProofMetadata for BatchProofMetadata { impl ProofMetadata for BatchProofMetadata {
@@ -172,7 +171,7 @@ impl<Metadata> From<&WrappedProof<Metadata>> for AggregationInput {
fn from(value: &WrappedProof<Metadata>) -> Self { fn from(value: &WrappedProof<Metadata>) -> Self {
Self { Self {
public_values: value.proof.public_values(), public_values: value.proof.public_values(),
commitment: ProgramCommitment::deserialize(&value.vk), commitment: serialize_vk::deserialize(&value.vk),
} }
} }
} }
@@ -181,13 +180,13 @@ impl<Metadata: ProofMetadata> WrappedProof<Metadata> {
/// Sanity checks on the wrapped proof: /// Sanity checks on the wrapped proof:
/// ///
/// - pi_hash computed in host does in fact match pi_hash computed in guest /// - pi_hash computed in host does in fact match pi_hash computed in guest
pub fn pi_hash_check(&self, fork_name: ForkName) -> bool { pub fn pi_hash_check(&self, ver: version::Version) -> bool {
let proof_pi = self.proof.public_values(); let proof_pi = self.proof.public_values();
let expected_pi = self let expected_pi = self
.metadata .metadata
.pi_hash_info() .pi_hash_info()
.pi_hash_by_fork(fork_name) .pi_hash_by_version(ver)
.0 .0
.as_ref() .as_ref()
.iter() .iter()
@@ -216,7 +215,7 @@ impl<Metadata: ProofMetadata> PersistableProof for WrappedProof<Metadata> {
mod tests { mod tests {
use base64::{prelude::BASE64_STANDARD, Engine}; use base64::{prelude::BASE64_STANDARD, Engine};
use sbv_primitives::B256; use sbv_primitives::B256;
use scroll_zkvm_types::{bundle::BundleInfo, proof::EvmProof, public_inputs::ForkName}; use scroll_zkvm_types::{bundle::BundleInfo, proof::EvmProof};
use super::*; use super::*;
@@ -252,8 +251,9 @@ mod tests {
batch_hash: B256::repeat_byte(4), batch_hash: B256::repeat_byte(4),
withdraw_root: B256::repeat_byte(5), withdraw_root: B256::repeat_byte(5),
msg_queue_hash: B256::repeat_byte(6), msg_queue_hash: B256::repeat_byte(6),
encryption_key: None,
}; };
let bundle_pi_hash = bundle_info.pi_hash(ForkName::EuclidV1); let bundle_pi_hash = bundle_info.pi_hash_euclidv1();
BundleProofMetadata { BundleProofMetadata {
bundle_info, bundle_info,
bundle_pi_hash, bundle_pi_hash,

View File

@@ -10,46 +10,62 @@ pub use chunk_interpreter::ChunkInterpreter;
pub use scroll_zkvm_types::task::ProvingTask; pub use scroll_zkvm_types::task::ProvingTask;
use crate::{ use crate::{
proofs::{self, BatchProofMetadata, BundleProofMetadata, ChunkProofMetadata}, proofs::{BatchProofMetadata, BundleProofMetadata, ChunkProofMetadata},
utils::panic_catch, utils::panic_catch,
}; };
use sbv_primitives::B256; use sbv_primitives::B256;
use scroll_zkvm_types::public_inputs::{ForkName, MultiVersionPublicInputs}; use scroll_zkvm_types::public_inputs::{MultiVersionPublicInputs, Version};
fn check_aggregation_proofs<Metadata>( fn encode_task_to_witness<T: serde::Serialize>(task: &T) -> eyre::Result<Vec<u8>> {
proofs: &[proofs::WrappedProof<Metadata>], let config = bincode::config::standard();
fork_name: ForkName, Ok(bincode::serde::encode_to_vec(task, config)?)
) -> eyre::Result<()> }
where
Metadata: proofs::ProofMetadata, fn check_aggregation_proofs<Metadata: MultiVersionPublicInputs>(
{ metadata: &[Metadata],
version: Version,
) -> eyre::Result<()> {
panic_catch(|| { panic_catch(|| {
for w in proofs.windows(2) { for w in metadata.windows(2) {
w[1].metadata w[1].validate(&w[0], version);
.pi_hash_info()
.validate(w[0].metadata.pi_hash_info(), fork_name);
} }
}) })
.map_err(|e| eyre::eyre!("Chunk data validation failed: {}", e))?; .map_err(|e| eyre::eyre!("Metadata validation failed: {}", e))?;
Ok(()) Ok(())
} }
#[derive(serde::Deserialize, serde::Serialize)]
pub struct ProvingTaskExt {
#[serde(flatten)]
task: ProvingTask,
#[serde(default)]
pub use_openvm_13: bool,
}
impl From<ProvingTaskExt> for ProvingTask {
fn from(wrap_t: ProvingTaskExt) -> Self {
wrap_t.task
}
}
impl ProvingTaskExt {
pub fn new(task: ProvingTask) -> Self {
Self {
task,
use_openvm_13: false,
}
}
}
/// Generate required staff for chunk proving /// Generate required staff for chunk proving
pub fn gen_universal_chunk_task( pub fn gen_universal_chunk_task(
mut task: ChunkProvingTask, task: ChunkProvingTask,
fork_name: ForkName,
interpreter: Option<impl ChunkInterpreter>,
) -> eyre::Result<(B256, ChunkProofMetadata, ProvingTask)> { ) -> eyre::Result<(B256, ChunkProofMetadata, ProvingTask)> {
if let Some(interpreter) = interpreter {
task.prepare_task_via_interpret(interpreter)?;
}
let chunk_total_gas = task.stats().total_gas_used; let chunk_total_gas = task.stats().total_gas_used;
let chunk_info = task.precheck_and_build_metadata()?; let (proving_task, chunk_info, chunk_pi_hash) = task.into_proving_task_with_precheck()?;
let proving_task = task.try_into()?;
let expected_pi_hash = chunk_info.pi_hash_by_fork(fork_name);
Ok(( Ok((
expected_pi_hash, chunk_pi_hash,
ChunkProofMetadata { ChunkProofMetadata {
chunk_info, chunk_info,
chunk_total_gas, chunk_total_gas,
@@ -61,18 +77,11 @@ pub fn gen_universal_chunk_task(
/// Generate required staff for batch proving /// Generate required staff for batch proving
pub fn gen_universal_batch_task( pub fn gen_universal_batch_task(
task: BatchProvingTask, task: BatchProvingTask,
fork_name: ForkName,
) -> eyre::Result<(B256, BatchProofMetadata, ProvingTask)> { ) -> eyre::Result<(B256, BatchProofMetadata, ProvingTask)> {
let batch_info = task.precheck_and_build_metadata()?; let (proving_task, batch_info, batch_pi_hash) = task.into_proving_task_with_precheck()?;
let proving_task = task.try_into()?;
let expected_pi_hash = batch_info.pi_hash_by_fork(fork_name);
Ok(( Ok((
expected_pi_hash, batch_pi_hash,
BatchProofMetadata { BatchProofMetadata { batch_info },
batch_info,
batch_hash: expected_pi_hash,
},
proving_task, proving_task,
)) ))
} }
@@ -80,17 +89,13 @@ pub fn gen_universal_batch_task(
/// Generate required staff for bundle proving /// Generate required staff for bundle proving
pub fn gen_universal_bundle_task( pub fn gen_universal_bundle_task(
task: BundleProvingTask, task: BundleProvingTask,
fork_name: ForkName,
) -> eyre::Result<(B256, BundleProofMetadata, ProvingTask)> { ) -> eyre::Result<(B256, BundleProofMetadata, ProvingTask)> {
let bundle_info = task.precheck_and_build_metadata()?; let (proving_task, bundle_info, bundle_pi_hash) = task.into_proving_task_with_precheck()?;
let proving_task = task.try_into()?;
let expected_pi_hash = bundle_info.pi_hash_by_fork(fork_name);
Ok(( Ok((
expected_pi_hash, bundle_pi_hash,
BundleProofMetadata { BundleProofMetadata {
bundle_info, bundle_info,
bundle_pi_hash: expected_pi_hash, bundle_pi_hash,
}, },
proving_task, proving_task,
)) ))

View File

@@ -1,58 +1,92 @@
use crate::proofs::ChunkProof;
use c_kzg::Bytes48; use c_kzg::Bytes48;
use eyre::Result; use eyre::Result;
use sbv_primitives::{B256, U256}; use sbv_primitives::{B256, U256};
use scroll_zkvm_types::{ use scroll_zkvm_types::{
batch::{ batch::{
BatchHeader, BatchHeaderV6, BatchHeaderV7, BatchHeaderV8, BatchInfo, BatchWitness, build_point_eval_witness, BatchHeader, BatchHeaderV6, BatchHeaderV7, BatchHeaderValidium,
Envelope, EnvelopeV6, EnvelopeV7, EnvelopeV8, PointEvalWitness, ReferenceHeader, BatchInfo, BatchWitness, Envelope, EnvelopeV6, EnvelopeV7, LegacyBatchWitness,
ToArchievedWitness, N_BLOB_BYTES, ReferenceHeader, N_BLOB_BYTES,
}, },
public_inputs::ForkName, chunk::ChunkInfo,
public_inputs::{ForkName, MultiVersionPublicInputs, Version},
task::ProvingTask, task::ProvingTask,
utils::{to_rkyv_bytes, RancorError}, utils::{to_rkyv_bytes, RancorError},
version::{Codec, Domain, STFVersion},
}; };
use crate::proofs::ChunkProof;
mod utils; mod utils;
use utils::{base64, point_eval}; use utils::{base64, point_eval};
/// Define variable batch header type, since BatchHeaderV6 can not #[derive(Clone, serde::Deserialize, serde::Serialize)]
/// be decoded as V7 we can always has correct deserialization pub struct BatchHeaderValidiumWithHash {
/// Notice: V6 header MUST be put above V7 since untagged enum #[serde(flatten)]
/// try to decode each defination in order header: BatchHeaderValidium,
batch_hash: B256,
}
/// Parse header types passed from golang side and adapt to the
/// definition in zkvm-prover's types
/// We distinguish the header type in golang side according to the STF
/// version, i.e. v6, v7-v10 (current), and validium
/// And adapt it to the corresponding batch header type used in zkvm-prover's witness
/// definition, i.e. v6, v7 (current), and validium
#[derive(Clone, serde::Deserialize, serde::Serialize)] #[derive(Clone, serde::Deserialize, serde::Serialize)]
#[serde(untagged)] #[serde(untagged)]
#[allow(non_camel_case_types)]
pub enum BatchHeaderV { pub enum BatchHeaderV {
/// Header for validium mode.
Validium(BatchHeaderValidiumWithHash),
/// Header for scroll's STF version v6.
V6(BatchHeaderV6), V6(BatchHeaderV6),
V7_8(BatchHeaderV7), /// Header for scroll's STF versions v7 - v10.
///
/// Since the codec essentially is unchanged for the above STF versions, we do not define new
/// variants, instead re-using the [`BatchHeaderV7`] variant.
V7_to_V10(BatchHeaderV7),
}
impl core::fmt::Display for BatchHeaderV {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
BatchHeaderV::V6(_) => write!(f, "V6"),
BatchHeaderV::V7_to_V10(_) => write!(f, "V7 - V10"),
BatchHeaderV::Validium(_) => write!(f, "Validium"),
}
}
} }
impl BatchHeaderV { impl BatchHeaderV {
pub fn batch_hash(&self) -> B256 { pub fn batch_hash(&self) -> B256 {
match self { match self {
BatchHeaderV::V6(h) => h.batch_hash(), BatchHeaderV::V6(h) => h.batch_hash(),
BatchHeaderV::V7_8(h) => h.batch_hash(), BatchHeaderV::V7_to_V10(h) => h.batch_hash(),
BatchHeaderV::Validium(h) => h.header.batch_hash(),
} }
} }
pub fn must_v6_header(&self) -> &BatchHeaderV6 { pub fn to_zkvm_batch_header_v6(&self) -> &BatchHeaderV6 {
match self { match self {
BatchHeaderV::V6(h) => h, BatchHeaderV::V6(h) => h,
_ => panic!("try to pick other header type"), _ => unreachable!("A header of {} is considered to be v6", self),
} }
} }
pub fn must_v7_header(&self) -> &BatchHeaderV7 { pub fn to_zkvm_batch_header_v7_to_v10(&self) -> &BatchHeaderV7 {
match self { match self {
BatchHeaderV::V7_8(h) => h, BatchHeaderV::V7_to_V10(h) => h,
_ => panic!("try to pick other header type"), _ => unreachable!(
"A header of {} is considered to be in [v7, v8, v9, v10]",
self
),
} }
} }
pub fn must_v8_header(&self) -> &BatchHeaderV8 { pub fn to_zkvm_batch_header_validium(&self) -> &BatchHeaderValidium {
match self { match self {
BatchHeaderV::V7_8(h) => h, BatchHeaderV::Validium(h) => &h.header,
_ => panic!("try to pick other header type"), _ => unreachable!("A header of {} is considered to be validium", self),
} }
} }
} }
@@ -61,6 +95,8 @@ impl BatchHeaderV {
/// is compatible with both pre-euclidv2 and euclidv2 /// is compatible with both pre-euclidv2 and euclidv2
#[derive(Clone, serde::Deserialize, serde::Serialize)] #[derive(Clone, serde::Deserialize, serde::Serialize)]
pub struct BatchProvingTask { pub struct BatchProvingTask {
/// The version of the chunks in the batch, as per [`Version`].
pub version: u8,
/// Chunk proofs for the contiguous list of chunks within the batch. /// Chunk proofs for the contiguous list of chunks within the batch.
pub chunk_proofs: Vec<ChunkProof>, pub chunk_proofs: Vec<ChunkProof>,
/// The [`BatchHeaderV6/V7`], as computed on-chain for this batch. /// The [`BatchHeaderV6/V7`], as computed on-chain for this batch.
@@ -79,128 +115,253 @@ pub struct BatchProvingTask {
pub fork_name: String, pub fork_name: String,
} }
impl TryFrom<BatchProvingTask> for ProvingTask { impl BatchProvingTask {
type Error = eyre::Error; pub fn into_proving_task_with_precheck(self) -> Result<(ProvingTask, BatchInfo, B256)> {
let (witness, metadata, batch_pi_hash) = self.precheck()?;
let serialized_witness = if crate::witness_use_legacy_mode(&self.fork_name)? {
let legacy_witness = LegacyBatchWitness::from(witness);
to_rkyv_bytes::<RancorError>(&legacy_witness)?.into_vec()
} else {
super::encode_task_to_witness(&witness)?
};
fn try_from(value: BatchProvingTask) -> Result<Self> { let proving_task = ProvingTask {
let witness = value.build_guest_input(); identifier: self.batch_header.batch_hash().to_string(),
fork_name: self.fork_name,
Ok(ProvingTask { aggregated_proofs: self
identifier: value.batch_header.batch_hash().to_string(),
fork_name: value.fork_name,
aggregated_proofs: value
.chunk_proofs .chunk_proofs
.into_iter() .into_iter()
.map(|w_proof| w_proof.proof.into_stark_proof().expect("expect root proof")) .map(|w_proof| w_proof.proof.into_stark_proof().expect("expect root proof"))
.collect(), .collect(),
serialized_witness: vec![to_rkyv_bytes::<RancorError>(&witness)?.into_vec()], serialized_witness: vec![serialized_witness],
vk: Vec::new(), vk: Vec::new(),
}) };
Ok((proving_task, metadata, batch_pi_hash))
} }
}
impl BatchProvingTask { fn build_guest_input(&self, version: Version) -> BatchWitness {
fn build_guest_input(&self) -> BatchWitness { tracing::info!(
let fork_name = self.fork_name.to_lowercase().as_str().into(); "Handling batch task for input, version byte {}, Version data: {:?}",
self.version,
version
);
// sanity check for if result of header type parsing match to version
match &self.batch_header {
BatchHeaderV::Validium(_) => assert!(
version.is_validium(),
"version {:?} is not match with parsed header, get validium header but version is not validium", version,
),
BatchHeaderV::V6(_) => assert_eq!(version.fork, ForkName::EuclidV1,
"hardfork mismatch for da-codec@v6 header: found={:?}, expected={:?}",
version.fork,
ForkName::EuclidV1,
),
BatchHeaderV::V7_to_V10(_) => assert!(
matches!(version.fork, ForkName::EuclidV2 | ForkName::Feynman | ForkName::Galileo | ForkName::GalileoV2),
"hardfork mismatch for da-codec@v7/8/9/10 header: found={}, expected={:?}",
version.fork,
[ForkName::EuclidV2, ForkName::Feynman, ForkName::Galileo, ForkName::GalileoV2],
),
}
// sanity check: calculate point eval needed and compare with task input let point_eval_witness = if !version.is_validium() {
let (kzg_commitment, kzg_proof, challenge_digest) = { // sanity check: calculate point eval needed and compare with task input
let blob = point_eval::to_blob(&self.blob_bytes); let (kzg_commitment, kzg_proof, challenge_digest) = {
let commitment = point_eval::blob_to_kzg_commitment(&blob); let blob = point_eval::to_blob(&self.blob_bytes);
let versioned_hash = point_eval::get_versioned_hash(&commitment); let commitment = point_eval::blob_to_kzg_commitment(&blob);
let challenge_digest = match &self.batch_header { let versioned_hash = point_eval::get_versioned_hash(&commitment);
BatchHeaderV::V6(_) => {
assert_eq!(
fork_name,
ForkName::EuclidV1,
"hardfork mismatch for da-codec@v6 header: found={fork_name:?}, expected={:?}",
ForkName::EuclidV1,
);
EnvelopeV6::from_slice(self.blob_bytes.as_slice())
.challenge_digest(versioned_hash)
}
BatchHeaderV::V7_8(_) => {
let padded_blob_bytes = {
let mut padded_blob_bytes = self.blob_bytes.to_vec();
padded_blob_bytes.resize(N_BLOB_BYTES, 0);
padded_blob_bytes
};
match fork_name { let padded_blob_bytes = {
ForkName::EuclidV2 => { let mut padded_blob_bytes = self.blob_bytes.to_vec();
<EnvelopeV7 as Envelope>::from_slice(padded_blob_bytes.as_slice()) padded_blob_bytes.resize(N_BLOB_BYTES, 0);
.challenge_digest(versioned_hash) padded_blob_bytes
} };
ForkName::Feynman => { let challenge_digest = match version.codec {
<EnvelopeV8 as Envelope>::from_slice(padded_blob_bytes.as_slice()) Codec::V6 => {
.challenge_digest(versioned_hash) // notice v6 do not use padded blob bytes
} <EnvelopeV6 as Envelope>::from_slice(self.blob_bytes.as_slice())
f => unreachable!( .challenge_digest(versioned_hash)
"hardfork mismatch for da-codec@v7 header: found={}, expected={:?}",
f,
[ForkName::EuclidV2, ForkName::Feynman],
),
} }
} Codec::V7 => <EnvelopeV7 as Envelope>::from_slice(padded_blob_bytes.as_slice())
.challenge_digest(versioned_hash),
};
let (proof, _) = point_eval::get_kzg_proof(&blob, challenge_digest);
(commitment.to_bytes(), proof.to_bytes(), challenge_digest)
}; };
let (proof, _) = point_eval::get_kzg_proof(&blob, challenge_digest); if let Some(k) = self.kzg_commitment {
assert_eq!(k, kzg_commitment);
}
(commitment.to_bytes(), proof.to_bytes(), challenge_digest) if let Some(c) = self.challenge_digest {
assert_eq!(c, U256::from_be_bytes(challenge_digest.0));
}
if let Some(p) = self.kzg_proof {
assert_eq!(p, kzg_proof);
}
Some(build_point_eval_witness(
kzg_commitment.into_inner(),
kzg_proof.into_inner(),
))
} else {
assert!(self.kzg_proof.is_none(), "domain=validium has no blob-da");
assert!(
self.kzg_commitment.is_none(),
"domain=validium has no blob-da"
);
assert!(
self.challenge_digest.is_none(),
"domain=validium has no blob-da"
);
match &self.batch_header {
BatchHeaderV::Validium(h) => assert_eq!(
h.header.batch_hash(),
h.batch_hash,
"calculated batch hash match which from coordinator"
),
_ => panic!("unexpected header type"),
}
None
}; };
if let Some(k) = self.kzg_commitment { let reference_header = match (version.domain, version.stf_version) {
assert_eq!(k, kzg_commitment); (Domain::Scroll, STFVersion::V6) => {
} ReferenceHeader::V6(*self.batch_header.to_zkvm_batch_header_v6())
}
if let Some(c) = self.challenge_digest { // The da-codec for STF versions v7, v8, v9, v10 is identical. In zkvm-prover we do not
assert_eq!(c, U256::from_be_bytes(challenge_digest.0)); // create additional variants to indicate the identical behaviour of codec. Instead we
} // add a separate variant for the STF version.
//
if let Some(p) = self.kzg_proof { // We handle the different STF versions here however build the same batch header since
assert_eq!(p, kzg_proof); // that type does not change. The batch header's version byte constructed in the
} // coordinator actually defines the STF version (v7, v8 or v9, v10) and we can derive
// the hard-fork (e.g. feynman or galileo) and the codec from the version
let point_eval_witness = PointEvalWitness { // byte.
kzg_commitment: kzg_commitment.into_inner(), //
kzg_proof: kzg_proof.into_inner(), // Refer [`scroll_zkvm_types::public_inputs::Version`].
(
Domain::Scroll,
STFVersion::V7 | STFVersion::V8 | STFVersion::V9 | STFVersion::V10,
) => ReferenceHeader::V7_V8_V9(*self.batch_header.to_zkvm_batch_header_v7_to_v10()),
(Domain::Validium, STFVersion::V1) => {
ReferenceHeader::Validium(*self.batch_header.to_zkvm_batch_header_validium())
}
(domain, stf_version) => {
unreachable!("unsupported domain={domain:?},stf-version={stf_version:?}")
}
}; };
let reference_header = match fork_name { // patch: ensure block_hash field is ZERO for scroll domain
ForkName::EuclidV1 => ReferenceHeader::V6(*self.batch_header.must_v6_header()), let chunk_infos = self
ForkName::EuclidV2 => ReferenceHeader::V7(*self.batch_header.must_v7_header()), .chunk_proofs
ForkName::Feynman => ReferenceHeader::V8(*self.batch_header.must_v8_header()), .iter()
}; .map(|p| {
if version.domain == Domain::Scroll {
ChunkInfo {
prev_blockhash: B256::ZERO,
post_blockhash: B256::ZERO,
..p.metadata.chunk_info.clone()
}
} else {
p.metadata.chunk_info.clone()
}
})
.collect();
BatchWitness { BatchWitness {
fork_name, version: version.as_version_byte(),
fork_name: version.fork,
chunk_proofs: self.chunk_proofs.iter().map(|proof| proof.into()).collect(), chunk_proofs: self.chunk_proofs.iter().map(|proof| proof.into()).collect(),
chunk_infos: self chunk_infos,
.chunk_proofs
.iter()
.map(|p| p.metadata.chunk_info.clone())
.collect(),
blob_bytes: self.blob_bytes.clone(), blob_bytes: self.blob_bytes.clone(),
reference_header, reference_header,
point_eval_witness, point_eval_witness,
} }
} }
pub fn precheck_and_build_metadata(&self) -> Result<BatchInfo> { pub fn precheck(&self) -> Result<(BatchWitness, BatchInfo, B256)> {
let fork_name = ForkName::from(self.fork_name.as_str());
// for every aggregation task, there are two steps needed to build the metadata: // for every aggregation task, there are two steps needed to build the metadata:
// 1. generate data for metadata from the witness // 1. generate data for metadata from the witness
// 2. validate every adjacent proof pair // 2. validate every adjacent proof pair
let witness = self.build_guest_input(); let version = Version::from(self.version);
let archieved = ToArchievedWitness::create(&witness) let witness = self.build_guest_input(version);
.map_err(|e| eyre::eyre!("archieve batch witness fail: {e}"))?; let metadata = BatchInfo::from(&witness);
let archieved_witness = archieved super::check_aggregation_proofs(
.access() witness.chunk_infos.as_slice(),
.map_err(|e| eyre::eyre!("access archieved batch witness fail: {e}"))?; Version::from(self.version),
let metadata: BatchInfo = archieved_witness.into(); )?;
let pi_hash = metadata.pi_hash_by_version(version);
super::check_aggregation_proofs(self.chunk_proofs.as_slice(), fork_name)?; Ok((witness, metadata, pi_hash))
}
Ok(metadata) }
#[test]
fn test_deserde_batch_header_v_validium() {
use std::str::FromStr;
// Top-level JSON: flattened enum tag "V1" + batch_hash
let json = r#"{
"V1": {
"version": 1,
"batch_index": 42,
"parent_batch_hash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"post_state_root": "0x2222222222222222222222222222222222222222222222222222222222222222",
"withdraw_root": "0x3333333333333333333333333333333333333333333333333333333333333333",
"commitment": "0x4444444444444444444444444444444444444444444444444444444444444444"
},
"batch_hash": "0x5555555555555555555555555555555555555555555555555555555555555555"
}"#;
let parsed: BatchHeaderV = serde_json::from_str(json).expect("deserialize BatchHeaderV");
match parsed {
BatchHeaderV::Validium(v) => {
// Check the batch_hash field
let expected_batch_hash = B256::from_str(
"0x5555555555555555555555555555555555555555555555555555555555555555",
)
.unwrap();
assert_eq!(v.batch_hash, expected_batch_hash);
// Check the inner header variant and fields
match v.header {
BatchHeaderValidium::V1(h) => {
assert_eq!(h.version, 1);
assert_eq!(h.batch_index, 42);
let p = B256::from_str(
"0x1111111111111111111111111111111111111111111111111111111111111111",
)
.unwrap();
let s = B256::from_str(
"0x2222222222222222222222222222222222222222222222222222222222222222",
)
.unwrap();
let w = B256::from_str(
"0x3333333333333333333333333333333333333333333333333333333333333333",
)
.unwrap();
let c = B256::from_str(
"0x4444444444444444444444444444444444444444444444444444444444444444",
)
.unwrap();
assert_eq!(h.parent_batch_hash, p);
assert_eq!(h.post_state_root, s);
assert_eq!(h.withdraw_root, w);
assert_eq!(h.commitment, c);
// Sanity: computed batch hash equals the provided one (if method available)
// assert_eq!(v.header.batch_hash(), expected_batch_hash);
}
}
}
_ => panic!("expected validium header variant"),
} }
} }

View File

@@ -1,16 +1,22 @@
use crate::proofs::BatchProof;
use eyre::Result; use eyre::Result;
use sbv_primitives::B256;
use scroll_zkvm_types::{ use scroll_zkvm_types::{
bundle::{BundleInfo, BundleWitness, ToArchievedWitness}, bundle::{BundleInfo, BundleWitness, LegacyBundleWitness},
public_inputs::ForkName, public_inputs::{MultiVersionPublicInputs, Version},
task::ProvingTask, task::ProvingTask,
utils::{to_rkyv_bytes, RancorError},
}; };
use crate::proofs::BatchProof;
/// Message indicating a sanity check failure. /// Message indicating a sanity check failure.
const BUNDLE_SANITY_MSG: &str = "bundle must have at least one batch"; const BUNDLE_SANITY_MSG: &str = "bundle must have at least one batch";
#[derive(Clone, serde::Deserialize, serde::Serialize)] #[derive(Clone, serde::Deserialize, serde::Serialize)]
pub struct BundleProvingTask { pub struct BundleProvingTask {
/// The version of batches in the bundle.
pub version: u8,
/// The STARK proofs of each batch in the bundle.
pub batch_proofs: Vec<BatchProof>, pub batch_proofs: Vec<BatchProof>,
/// for sanity check /// for sanity check
pub bundle_info: Option<BundleInfo>, pub bundle_info: Option<BundleInfo>,
@@ -19,6 +25,30 @@ pub struct BundleProvingTask {
} }
impl BundleProvingTask { impl BundleProvingTask {
pub fn into_proving_task_with_precheck(self) -> Result<(ProvingTask, BundleInfo, B256)> {
let (witness, bundle_info, bundle_pi_hash) = self.precheck()?;
let serialized_witness = if crate::witness_use_legacy_mode(&self.fork_name)? {
let legacy = LegacyBundleWitness::from(witness);
to_rkyv_bytes::<RancorError>(&legacy)?.into_vec()
} else {
super::encode_task_to_witness(&witness)?
};
let proving_task = ProvingTask {
identifier: self.identifier(),
fork_name: self.fork_name,
aggregated_proofs: self
.batch_proofs
.into_iter()
.map(|w_proof| w_proof.proof.into_stark_proof().expect("expect root proof"))
.collect(),
serialized_witness: vec![serialized_witness],
vk: Vec::new(),
};
Ok((proving_task, bundle_info, bundle_pi_hash))
}
fn identifier(&self) -> String { fn identifier(&self) -> String {
assert!(!self.batch_proofs.is_empty(), "{BUNDLE_SANITY_MSG}",); assert!(!self.batch_proofs.is_empty(), "{BUNDLE_SANITY_MSG}",);
@@ -27,64 +57,45 @@ impl BundleProvingTask {
.first() .first()
.expect(BUNDLE_SANITY_MSG) .expect(BUNDLE_SANITY_MSG)
.metadata .metadata
.batch_info
.batch_hash, .batch_hash,
self.batch_proofs self.batch_proofs
.last() .last()
.expect(BUNDLE_SANITY_MSG) .expect(BUNDLE_SANITY_MSG)
.metadata .metadata
.batch_info
.batch_hash, .batch_hash,
); );
format!("{first}-{last}") format!("{first}-{last}")
} }
fn build_guest_input(&self) -> BundleWitness { fn build_guest_input(&self, version: Version) -> BundleWitness {
BundleWitness { BundleWitness {
version: version.as_version_byte(),
batch_proofs: self.batch_proofs.iter().map(|proof| proof.into()).collect(), batch_proofs: self.batch_proofs.iter().map(|proof| proof.into()).collect(),
batch_infos: self batch_infos: self
.batch_proofs .batch_proofs
.iter() .iter()
.map(|wrapped_proof| wrapped_proof.metadata.batch_info.clone()) .map(|wrapped_proof| wrapped_proof.metadata.batch_info.clone())
.collect(), .collect(),
fork_name: self.fork_name.to_lowercase().as_str().into(), fork_name: version.fork,
} }
} }
pub fn precheck_and_build_metadata(&self) -> Result<BundleInfo> { fn precheck(&self) -> Result<(BundleWitness, BundleInfo, B256)> {
let fork_name = ForkName::from(self.fork_name.as_str());
// for every aggregation task, there are two steps needed to build the metadata: // for every aggregation task, there are two steps needed to build the metadata:
// 1. generate data for metadata from the witness // 1. generate data for metadata from the witness
// 2. validate every adjacent proof pair // 2. validate every adjacent proof pair
let witness = self.build_guest_input(); let version = Version::from(self.version);
let archieved = ToArchievedWitness::create(&witness) let witness = self.build_guest_input(version);
.map_err(|e| eyre::eyre!("archieve bundle witness fail: {e}"))?; let metadata = BundleInfo::from(&witness);
let archieved_witness = archieved super::check_aggregation_proofs(
.access() witness.batch_infos.as_slice(),
.map_err(|e| eyre::eyre!("access archieved bundle witness fail: {e}"))?; Version::from(self.version),
let metadata: BundleInfo = archieved_witness.into(); )?;
let pi_hash = metadata.pi_hash_by_version(version);
super::check_aggregation_proofs(self.batch_proofs.as_slice(), fork_name)?; Ok((witness, metadata, pi_hash))
Ok(metadata)
}
}
impl TryFrom<BundleProvingTask> for ProvingTask {
type Error = eyre::Error;
fn try_from(value: BundleProvingTask) -> Result<Self> {
let witness = value.build_guest_input();
Ok(ProvingTask {
identifier: value.identifier(),
fork_name: value.fork_name,
aggregated_proofs: value
.batch_proofs
.into_iter()
.map(|w_proof| w_proof.proof.into_stark_proof().expect("expect root proof"))
.collect(),
serialized_witness: vec![witness.rkyv_serialize(None)?.to_vec()],
vk: Vec::new(),
})
} }
} }

View File

@@ -1,18 +1,26 @@
use super::chunk_interpreter::*;
use eyre::Result; use eyre::Result;
use sbv_primitives::{types::BlockWitness, B256}; use sbv_core::BlockWitness;
use sbv_primitives::{types::consensus::BlockHeader, B256};
use scroll_zkvm_types::{ use scroll_zkvm_types::{
chunk::{execute, ChunkInfo, ChunkWitness, ToArchievedWitness}, chunk::{execute, ChunkInfo, ChunkWitness, LegacyChunkWitness, ValidiumInputs},
public_inputs::{MultiVersionPublicInputs, Version},
task::ProvingTask, task::ProvingTask,
utils::{to_rkyv_bytes, RancorError},
}; };
use super::chunk_interpreter::*;
/// The type aligned with coordinator's defination /// The type aligned with coordinator's defination
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ChunkTask { pub struct ChunkTask {
/// The version for the chunk, as per [`Version`].
pub version: u8,
/// block hashes for a series of block /// block hashes for a series of block
pub block_hashes: Vec<B256>, pub block_hashes: Vec<B256>,
/// The on-chain L1 msg queue hash before applying L1 msg txs from the chunk. /// The on-chain L1 msg queue hash before applying L1 msg txs from the chunk.
pub prev_msg_queue_hash: B256, pub prev_msg_queue_hash: B256,
/// The on-chain L1 msg queue hash after applying L1 msg txs from the chunk (for validate)
pub post_msg_queue_hash: B256,
/// Fork name specify /// Fork name specify
pub fork_name: String, pub fork_name: String,
} }
@@ -20,6 +28,7 @@ pub struct ChunkTask {
impl TryFromWithInterpreter<ChunkTask> for ChunkProvingTask { impl TryFromWithInterpreter<ChunkTask> for ChunkProvingTask {
fn try_from_with_interpret( fn try_from_with_interpret(
value: ChunkTask, value: ChunkTask,
decryption_key: Option<&[u8]>,
interpreter: impl ChunkInterpreter, interpreter: impl ChunkInterpreter,
) -> Result<Self> { ) -> Result<Self> {
let mut block_witnesses = Vec::new(); let mut block_witnesses = Vec::new();
@@ -29,10 +38,28 @@ impl TryFromWithInterpreter<ChunkTask> for ChunkProvingTask {
block_witnesses.push(witness); block_witnesses.push(witness);
} }
let validium_txs = if Version::from(value.version).is_validium() {
let mut validium_txs = Vec::new();
for block_number in block_witnesses.iter().map(|w| w.header.number()) {
validium_txs.push(interpreter.try_fetch_l1_msgs(block_number)?);
}
validium_txs
} else {
vec![]
};
let validium_inputs = decryption_key.map(|secret_key| ValidiumInputs {
validium_txs,
secret_key: secret_key.into(),
});
Ok(Self { Ok(Self {
version: value.version,
block_witnesses, block_witnesses,
prev_msg_queue_hash: value.prev_msg_queue_hash, prev_msg_queue_hash: value.prev_msg_queue_hash,
post_msg_queue_hash: value.post_msg_queue_hash,
fork_name: value.fork_name, fork_name: value.fork_name,
validium_inputs,
}) })
} }
} }
@@ -46,12 +73,18 @@ const CHUNK_SANITY_MSG: &str = "chunk must have at least one block";
/// - {first_block_number}-{last_block_number} /// - {first_block_number}-{last_block_number}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct ChunkProvingTask { pub struct ChunkProvingTask {
/// The version for the chunk, as per [Version][scroll_zkvm_types::version::Version].
pub version: u8,
/// Witnesses for every block in the chunk. /// Witnesses for every block in the chunk.
pub block_witnesses: Vec<BlockWitness>, pub block_witnesses: Vec<BlockWitness>,
/// The on-chain L1 msg queue hash before applying L1 msg txs from the chunk. /// The on-chain L1 msg queue hash before applying L1 msg txs from the chunk.
pub prev_msg_queue_hash: B256, pub prev_msg_queue_hash: B256,
/// The on-chain L1 msg queue hash after applying L1 msg txs from the chunk (for validate)
pub post_msg_queue_hash: B256,
/// Fork name specify /// Fork name specify
pub fork_name: String, pub fork_name: String,
/// Optional inputs in case of domain=validium.
pub validium_inputs: Option<ValidiumInputs>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -61,29 +94,13 @@ pub struct ChunkDetails {
pub total_gas_used: u64, pub total_gas_used: u64,
} }
impl TryFrom<ChunkProvingTask> for ProvingTask {
type Error = eyre::Error;
fn try_from(value: ChunkProvingTask) -> Result<Self> {
let witness = value.build_guest_input();
Ok(ProvingTask {
identifier: value.identifier(),
fork_name: value.fork_name,
aggregated_proofs: Vec::new(),
serialized_witness: vec![witness.rkyv_serialize(None)?.to_vec()],
vk: Vec::new(),
})
}
}
impl ChunkProvingTask { impl ChunkProvingTask {
pub fn stats(&self) -> ChunkDetails { pub fn stats(&self) -> ChunkDetails {
let num_blocks = self.block_witnesses.len(); let num_blocks = self.block_witnesses.len();
let num_txs = self let num_txs = self
.block_witnesses .block_witnesses
.iter() .iter()
.map(|b| b.transaction.len()) .map(|b| b.transactions.len())
.sum::<usize>(); .sum::<usize>();
let total_gas_used = self let total_gas_used = self
.block_witnesses .block_witnesses
@@ -98,6 +115,26 @@ impl ChunkProvingTask {
} }
} }
pub fn into_proving_task_with_precheck(self) -> Result<(ProvingTask, ChunkInfo, B256)> {
let (witness, chunk_info, chunk_pi_hash) = self.precheck()?;
let serialized_witness = if crate::witness_use_legacy_mode(&self.fork_name)? {
let legacy_witness = LegacyChunkWitness::from(witness);
to_rkyv_bytes::<RancorError>(&legacy_witness)?.into_vec()
} else {
super::encode_task_to_witness(&witness)?
};
let proving_task = ProvingTask {
identifier: self.identifier(),
fork_name: self.fork_name,
aggregated_proofs: Vec::new(),
serialized_witness: vec![serialized_witness],
vk: Vec::new(),
};
Ok((proving_task, chunk_info, chunk_pi_hash))
}
fn identifier(&self) -> String { fn identifier(&self) -> String {
assert!(!self.block_witnesses.is_empty(), "{CHUNK_SANITY_MSG}",); assert!(!self.block_witnesses.is_empty(), "{CHUNK_SANITY_MSG}",);
@@ -117,32 +154,42 @@ impl ChunkProvingTask {
format!("{first}-{last}") format!("{first}-{last}")
} }
fn build_guest_input(&self) -> ChunkWitness { fn build_guest_input(&self, version: Version) -> ChunkWitness {
ChunkWitness::new( if version.is_validium() {
&self.block_witnesses, assert!(self.validium_inputs.is_some());
self.prev_msg_queue_hash, ChunkWitness::new(
self.fork_name.to_lowercase().as_str().into(), version.as_version_byte(),
) &self.block_witnesses,
self.prev_msg_queue_hash,
version.fork,
self.validium_inputs.clone(),
)
} else {
ChunkWitness::new_scroll(
version.as_version_byte(),
&self.block_witnesses,
self.prev_msg_queue_hash,
version.fork,
)
}
} }
fn insert_state(&mut self, node: sbv_primitives::Bytes) { fn insert_state(&mut self, node: sbv_primitives::Bytes) {
self.block_witnesses[0].states.push(node); self.block_witnesses[0].states.push(node);
} }
pub fn precheck_and_build_metadata(&self) -> Result<ChunkInfo> { fn precheck(&self) -> Result<(ChunkWitness, ChunkInfo, B256)> {
let witness = self.build_guest_input(); let version = Version::from(self.version);
let archieved = ToArchievedWitness::create(&witness) let witness = self.build_guest_input(version);
.map_err(|e| eyre::eyre!("archieve chunk witness fail: {e}"))?; let chunk_info = ChunkInfo::try_from(witness.clone()).map_err(|e| eyre::eyre!("{e}"))?;
let archieved_witness = archieved assert_eq!(chunk_info.post_msg_queue_hash, self.post_msg_queue_hash);
.access() let chunk_pi_hash = chunk_info.pi_hash_by_version(version);
.map_err(|e| eyre::eyre!("access archieved chunk witness fail: {e}"))?; Ok((witness, chunk_info, chunk_pi_hash))
let ret = ChunkInfo::try_from(archieved_witness).map_err(|e| eyre::eyre!("{e}"))?;
Ok(ret)
} }
/// this method check the validate of current task (there may be missing storage node) /// this method check the validate of current task (there may be missing storage node)
/// and try fixing it until everything is ok /// and try fixing it until everything is ok
#[deprecated]
pub fn prepare_task_via_interpret( pub fn prepare_task_via_interpret(
&mut self, &mut self,
interpreter: impl ChunkInterpreter, interpreter: impl ChunkInterpreter,
@@ -165,14 +212,9 @@ impl ChunkProvingTask {
let err_parse_re = regex::Regex::new(pattern)?; let err_parse_re = regex::Regex::new(pattern)?;
let mut attempts = 0; let mut attempts = 0;
loop { loop {
let witness = self.build_guest_input(); let witness = self.build_guest_input(Version::euclid_v2());
let archieved = ToArchievedWitness::create(&witness)
.map_err(|e| eyre::eyre!("archieve chunk witness fail: {e}"))?;
let archieved_witness = archieved
.access()
.map_err(|e| eyre::eyre!("access archieved chunk witness fail: {e}"))?;
match execute(archieved_witness) { match execute(witness) {
Ok(_) => return Ok(()), Ok(_) => return Ok(()),
Err(e) => { Err(e) => {
if let Some(caps) = err_parse_re.captures(&e) { if let Some(caps) = err_parse_re.captures(&e) {

View File

@@ -1,5 +1,6 @@
use eyre::Result; use eyre::Result;
use sbv_primitives::{types::BlockWitness, Bytes, B256}; use sbv_core::BlockWitness;
use sbv_primitives::{types::consensus::TxL1Message, Bytes, B256};
/// An interpreter which is cirtical in translating chunk data /// An interpreter which is cirtical in translating chunk data
/// since we need to grep block witness and storage node data /// since we need to grep block witness and storage node data
@@ -12,13 +13,22 @@ pub trait ChunkInterpreter {
) -> Result<BlockWitness> { ) -> Result<BlockWitness> {
Err(eyre::eyre!("no implement")) Err(eyre::eyre!("no implement"))
} }
fn try_fetch_storage_node(&self, _node_hash: B256) -> Result<Bytes> { fn try_fetch_storage_node(&self, _node_hash: B256) -> Result<Bytes> {
Err(eyre::eyre!("no implement")) Err(eyre::eyre!("no implement"))
} }
fn try_fetch_l1_msgs(&self, _block_number: u64) -> Result<Vec<TxL1Message>> {
Err(eyre::eyre!("no implement"))
}
} }
pub trait TryFromWithInterpreter<T>: Sized { pub trait TryFromWithInterpreter<T>: Sized {
fn try_from_with_interpret(value: T, intepreter: impl ChunkInterpreter) -> Result<Self>; fn try_from_with_interpret(
value: T,
decryption_key: Option<&[u8]>,
intepreter: impl ChunkInterpreter,
) -> Result<Self>;
} }
pub struct DummyInterpreter {} pub struct DummyInterpreter {}

View File

@@ -41,8 +41,11 @@ pub trait ProofVerifier {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CircuitConfig { pub struct CircuitConfig {
pub version: u8,
pub fork_name: String, pub fork_name: String,
pub assets_path: String, pub assets_path: String,
#[serde(default)]
pub features: Option<String>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@@ -50,7 +53,7 @@ pub struct VerifierConfig {
pub circuits: Vec<CircuitConfig>, pub circuits: Vec<CircuitConfig>,
} }
type HardForkName = String; pub(crate) type HardForkName = String;
type VerifierType = Arc<Mutex<dyn ProofVerifier + Send>>; type VerifierType = Arc<Mutex<dyn ProofVerifier + Send>>;
static VERIFIERS: OnceLock<HashMap<HardForkName, VerifierType>> = OnceLock::new(); static VERIFIERS: OnceLock<HashMap<HardForkName, VerifierType>> = OnceLock::new();
@@ -61,14 +64,18 @@ pub fn init(config: VerifierConfig) {
for cfg in &config.circuits { for cfg in &config.circuits {
let canonical_fork_name = cfg.fork_name.to_lowercase(); let canonical_fork_name = cfg.fork_name.to_lowercase();
let verifier = Verifier::new(&cfg.assets_path, canonical_fork_name.as_str().into()); let verifier = Verifier::new(&cfg.assets_path, cfg.version);
let ret = verifiers.insert(canonical_fork_name, Arc::new(Mutex::new(verifier))); let ret = verifiers.insert(canonical_fork_name, Arc::new(Mutex::new(verifier)));
assert!( assert!(
ret.is_none(), ret.is_none(),
"DO NOT init the same fork {} twice", "DO NOT init the same fork {} twice",
cfg.fork_name cfg.fork_name
); );
tracing::info!("load verifier config for fork {}", cfg.fork_name); tracing::info!(
"load verifier config for fork {} (ver {})",
cfg.fork_name,
cfg.version
);
} }
let ret = VERIFIERS.set(verifiers).is_ok(); let ret = VERIFIERS.set(verifiers).is_ok();

View File

@@ -6,22 +6,22 @@ use crate::{
proofs::{AsRootProof, BatchProof, BundleProof, ChunkProof, IntoEvmProof}, proofs::{AsRootProof, BatchProof, BundleProof, ChunkProof, IntoEvmProof},
utils::panic_catch, utils::panic_catch,
}; };
use scroll_zkvm_types::public_inputs::ForkName; use scroll_zkvm_types::version::Version;
use scroll_zkvm_verifier::verifier::UniversalVerifier; use scroll_zkvm_verifier::verifier::UniversalVerifier;
use std::path::Path; use std::path::Path;
pub struct Verifier { pub struct Verifier {
verifier: UniversalVerifier, verifier: UniversalVerifier,
fork: ForkName, version: Version,
} }
impl Verifier { impl Verifier {
pub fn new(assets_dir: &str, fork: ForkName) -> Self { pub fn new(assets_dir: &str, ver_n: u8) -> Self {
let verifier_bin = Path::new(assets_dir).join("verifier.bin"); let verifier_bin = Path::new(assets_dir);
Self { Self {
verifier: UniversalVerifier::setup(&verifier_bin).expect("Setting up chunk verifier"), verifier: UniversalVerifier::setup(verifier_bin).expect("Setting up chunk verifier"),
fork, version: Version::from(ver_n),
} }
} }
} }
@@ -31,17 +31,21 @@ impl ProofVerifier for Verifier {
panic_catch(|| match task_type { panic_catch(|| match task_type {
TaskType::Chunk => { TaskType::Chunk => {
let proof = serde_json::from_slice::<ChunkProof>(proof).unwrap(); let proof = serde_json::from_slice::<ChunkProof>(proof).unwrap();
assert!(proof.pi_hash_check(self.fork)); assert!(proof.pi_hash_check(self.version));
UniversalVerifier::verify_stark_proof(proof.as_root_proof(), &proof.vk).unwrap() self.verifier
.verify_stark_proof(proof.as_root_proof(), &proof.vk)
.unwrap()
} }
TaskType::Batch => { TaskType::Batch => {
let proof = serde_json::from_slice::<BatchProof>(proof).unwrap(); let proof = serde_json::from_slice::<BatchProof>(proof).unwrap();
assert!(proof.pi_hash_check(self.fork)); assert!(proof.pi_hash_check(self.version));
UniversalVerifier::verify_stark_proof(proof.as_root_proof(), &proof.vk).unwrap() self.verifier
.verify_stark_proof(proof.as_root_proof(), &proof.vk)
.unwrap()
} }
TaskType::Bundle => { TaskType::Bundle => {
let proof = serde_json::from_slice::<BundleProof>(proof).unwrap(); let proof = serde_json::from_slice::<BundleProof>(proof).unwrap();
assert!(proof.pi_hash_check(self.fork)); assert!(proof.pi_hash_check(self.version));
let vk = proof.vk.clone(); let vk = proof.vk.clone();
let evm_proof = proof.into_evm_proof(); let evm_proof = proof.into_evm_proof();
self.verifier.verify_evm_proof(&evm_proof, &vk).unwrap() self.verifier.verify_evm_proof(&evm_proof, &vk).unwrap()

View File

@@ -152,18 +152,30 @@ pub unsafe extern "C" fn gen_universal_task(
fork_name: *const c_char, fork_name: *const c_char,
expected_vk: *const u8, expected_vk: *const u8,
expected_vk_len: usize, expected_vk_len: usize,
decryption_key: *const u8,
decryption_key_len: usize,
) -> HandlingResult { ) -> HandlingResult {
let mut interpreter = None;
let task_json = if task_type == TaskType::Chunk as i32 { let task_json = if task_type == TaskType::Chunk as i32 {
let pre_task_str = c_char_to_str(task); let pre_task_str = c_char_to_str(task);
let cli = l2geth::get_client(); let cli = l2geth::get_client();
match libzkp::checkout_chunk_task(pre_task_str, cli) { let decryption_key = if decryption_key_len > 0 {
Ok(str) => { if decryption_key_len != 32 {
interpreter.replace(cli); tracing::error!(
str "gen_universal_task received {}-byte decryption key; expected 32",
decryption_key_len
);
return failed_handling_result();
} }
Some(std::slice::from_raw_parts(
decryption_key,
decryption_key_len,
))
} else {
None
};
match libzkp::checkout_chunk_task(pre_task_str, decryption_key, cli) {
Ok(str) => str,
Err(e) => { Err(e) => {
println!("gen_universal_task failed at pre interpret step, error: {e}");
tracing::error!("gen_universal_task failed at pre interpret step, error: {e}"); tracing::error!("gen_universal_task failed at pre interpret step, error: {e}");
return failed_handling_result(); return failed_handling_result();
} }
@@ -178,13 +190,8 @@ pub unsafe extern "C" fn gen_universal_task(
&[] &[]
}; };
let ret = libzkp::gen_universal_task( let ret =
task_type, libzkp::gen_universal_task(task_type, &task_json, c_char_to_str(fork_name), expected_vk);
&task_json,
c_char_to_str(fork_name),
expected_vk,
interpreter,
);
if let Ok((pi_hash, meta_json, task_json)) = ret { if let Ok((pi_hash, meta_json, task_json)) = ret {
let expected_pi_hash = pi_hash.0.map(|byte| byte as c_char); let expected_pi_hash = pi_hash.0.map(|byte| byte as c_char);
@@ -248,6 +255,19 @@ pub unsafe extern "C" fn gen_wrapped_proof(
} }
} }
/// # Safety
#[no_mangle]
pub unsafe extern "C" fn univ_task_compatibility_fix(task_json: *const c_char) -> *mut c_char {
let task_json_str = c_char_to_str(task_json);
match libzkp::univ_task_compatibility_fix(task_json_str) {
Ok(result) => CString::new(result).unwrap().into_raw(),
Err(e) => {
tracing::error!("univ_task_compability_fix failed, error: {:#}", e);
std::ptr::null_mut()
}
}
}
/// # Safety /// # Safety
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn release_string(ptr: *mut c_char) { pub unsafe extern "C" fn release_string(ptr: *mut c_char) {

View File

@@ -8,7 +8,8 @@ edition.workspace = true
[dependencies] [dependencies]
scroll-zkvm-types.workspace = true scroll-zkvm-types.workspace = true
scroll-zkvm-prover.workspace = true scroll-zkvm-prover.workspace = true
scroll-proving-sdk = { git = "https://github.com/scroll-tech/scroll-proving-sdk.git", rev = "4c36ab2" } libzkp = { path = "../libzkp"}
scroll-proving-sdk = { git = "https://github.com/scroll-tech/scroll-proving-sdk.git", rev = "05648db" }
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
once_cell.workspace =true once_cell.workspace =true
@@ -33,3 +34,7 @@ clap = { version = "4.5", features = ["derive"] }
ctor = "0.2.8" ctor = "0.2.8"
url = { version = "2.5.4", features = ["serde",] } url = { version = "2.5.4", features = ["serde",] }
serde_bytes = "0.11.15" serde_bytes = "0.11.15"
[features]
default = []
cuda = ["scroll-zkvm-prover/cuda"]

View File

@@ -2,6 +2,9 @@
"feynman": { "feynman": {
"b68fdc3f28a5ce006280980df70cd3447e56913e5bca6054603ba85f0794c23a6618ea25a7991845bbc5fd571670ee47379ba31ace92d345bca59702a0d4112d": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.5.2/chunk/", "b68fdc3f28a5ce006280980df70cd3447e56913e5bca6054603ba85f0794c23a6618ea25a7991845bbc5fd571670ee47379ba31ace92d345bca59702a0d4112d": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.5.2/chunk/",
"9a3f66370f11e3303f1a1248921025104e83253efea43a70d221cf4e15fc145bf2be2f4468d1ac4a70e7682babb1c60417e21c7633d4b55b58f44703ec82b05a": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.5.2/batch/", "9a3f66370f11e3303f1a1248921025104e83253efea43a70d221cf4e15fc145bf2be2f4468d1ac4a70e7682babb1c60417e21c7633d4b55b58f44703ec82b05a": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.5.2/batch/",
"1f8627277e1c1f6e1cc70c03e6fde06929e5ea27ca5b1d56e23b235dfeda282e22c0e5294bcb1b3a9def836f8d0f18612a9860629b9497292976ca11844b7e73": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.5.2/bundle/" "1f8627277e1c1f6e1cc70c03e6fde06929e5ea27ca5b1d56e23b235dfeda282e22c0e5294bcb1b3a9def836f8d0f18612a9860629b9497292976ca11844b7e73": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.5.2/bundle/",
"7eb91f1885cc7a63cc848928f043fa56bf747161a74cd933d88c0456b90643346618ea25a7991845bbc5fd571670ee47379ba31ace92d345bca59702a0d4112d": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.6.0-rc.1/chunk/",
"dc653e7416628c612fa4d80b4724002bad4fde3653aef7316b80df0c19740a1bf2be2f4468d1ac4a70e7682babb1c60417e21c7633d4b55b58f44703ec82b05a": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.6.0-rc.1/batch/",
"14de1c74b663ed3c99acb03e90a5753b5923233c5c590864ad7746570297d16722c0e5294bcb1b3a9def836f8d0f18612a9860629b9497292976ca11844b7e73": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.6.0-rc.1/bundle/"
} }
} }

View File

@@ -12,6 +12,7 @@ use scroll_proving_sdk::{
ProvingService, ProvingService,
}, },
}; };
use scroll_zkvm_types::ProvingTask;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
collections::HashMap, collections::HashMap,
@@ -143,7 +144,6 @@ impl LocalProverConfig {
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct CircuitConfig { pub struct CircuitConfig {
pub hard_fork_name: String,
/// The path to save assets for a specified hard fork phase /// The path to save assets for a specified hard fork phase
pub workspace_path: String, pub workspace_path: String,
#[serde(flatten)] #[serde(flatten)]
@@ -273,6 +273,8 @@ impl LocalProver {
let created_at = duration.as_secs() as f64 + duration.subsec_nanos() as f64 * 1e-9; let created_at = duration.as_secs() as f64 + duration.subsec_nanos() as f64 * 1e-9;
let prover_task = UniversalHandler::get_task_from_input(&req.input)?; let prover_task = UniversalHandler::get_task_from_input(&req.input)?;
let is_openvm_13 = prover_task.use_openvm_13;
let prover_task: ProvingTask = prover_task.into();
let vk = hex::encode(&prover_task.vk); let vk = hex::encode(&prover_task.vk);
let handler = if let Some(handler) = self.handlers.get(&vk) { let handler = if let Some(handler) = self.handlers.get(&vk) {
handler.clone() handler.clone()
@@ -300,7 +302,7 @@ impl LocalProver {
.await?; .await?;
let circuits_handler = Arc::new(Mutex::new(UniversalHandler::new( let circuits_handler = Arc::new(Mutex::new(UniversalHandler::new(
&asset_path, &asset_path,
req.proof_type, is_openvm_13,
)?)); )?));
self.handlers.insert(vk, circuits_handler.clone()); self.handlers.insert(vk, circuits_handler.clone());
circuits_handler circuits_handler

View File

@@ -1,3 +1,5 @@
#![allow(dead_code)]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Serialize, Deserialize, Default)] #[derive(Serialize, Deserialize, Default)]

View File

@@ -2,9 +2,8 @@ use std::path::Path;
use super::CircuitsHandler; use super::CircuitsHandler;
use async_trait::async_trait; use async_trait::async_trait;
use base64::{prelude::BASE64_STANDARD, Engine};
use eyre::Result; use eyre::Result;
use scroll_proving_sdk::prover::ProofType; use libzkp::ProvingTaskExt;
use scroll_zkvm_prover::{Prover, ProverConfig}; use scroll_zkvm_prover::{Prover, ProverConfig};
use scroll_zkvm_types::ProvingTask; use scroll_zkvm_types::ProvingTask;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@@ -12,32 +11,33 @@ pub struct UniversalHandler {
prover: Prover, prover: Prover,
} }
/// Safe for current usage as `CircuitsHandler` trait (protected inside of Mutex and NEVER extract
/// the instance out by `into_inner`)
unsafe impl Send for UniversalHandler {} unsafe impl Send for UniversalHandler {}
impl UniversalHandler { impl UniversalHandler {
pub fn new(workspace_path: impl AsRef<Path>, proof_type: ProofType) -> Result<Self> { pub fn new(workspace_path: impl AsRef<Path>, is_openvm_v13: bool) -> Result<Self> {
let path_app_exe = workspace_path.as_ref().join("app.vmexe"); let path_app_exe = workspace_path.as_ref().join("app.vmexe");
let path_app_config = workspace_path.as_ref().join("openvm.toml"); let path_app_config = workspace_path.as_ref().join("openvm.toml");
let segment_len = Some((1 << 22) - 100); let segment_len = Some((1 << 21) - 100);
let config = ProverConfig { let config = ProverConfig {
path_app_config, path_app_config,
path_app_exe, path_app_exe,
segment_len, segment_len,
is_openvm_v13,
}; };
let use_evm = proof_type == ProofType::Bundle; let prover = Prover::setup(config, None)?;
let prover = Prover::setup(config, use_evm, None)?;
Ok(Self { prover }) Ok(Self { prover })
} }
/// get_prover get the inner prover, later we would replace chunk/batch/bundle_prover with /// get_prover get the inner prover, later we would replace chunk/batch/bundle_prover with
/// universal prover, before that, use bundle_prover as the represent one /// universal prover, before that, use bundle_prover as the represent one
pub fn get_prover(&self) -> &Prover { pub fn get_prover(&mut self) -> &mut Prover {
&self.prover &mut self.prover
} }
pub fn get_task_from_input(input: &str) -> Result<ProvingTask> { pub fn get_task_from_input(input: &str) -> Result<ProvingTaskExt> {
Ok(serde_json::from_str(input)?) Ok(serde_json::from_str(input)?)
} }
} }
@@ -45,14 +45,7 @@ impl UniversalHandler {
#[async_trait] #[async_trait]
impl CircuitsHandler for Mutex<UniversalHandler> { impl CircuitsHandler for Mutex<UniversalHandler> {
async fn get_proof_data(&self, u_task: &ProvingTask, need_snark: bool) -> Result<String> { async fn get_proof_data(&self, u_task: &ProvingTask, need_snark: bool) -> Result<String> {
let handler_self = self.lock().await; let mut handler_self = self.lock().await;
if need_snark && handler_self.prover.evm_prover.is_none() {
eyre::bail!(
"do not init prover for evm (vk: {})",
BASE64_STANDARD.encode(handler_self.get_prover().get_app_vk())
)
}
let proof = handler_self let proof = handler_self
.get_prover() .get_prover()

View File

@@ -8,7 +8,7 @@ require (
github.com/jmoiron/sqlx v1.3.5 github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/pressly/goose/v3 v3.16.0 github.com/pressly/goose/v3 v3.16.0
github.com/scroll-tech/go-ethereum v1.10.14-0.20250305151038-478940e79601 github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.25.7 github.com/urfave/cli/v2 v2.25.7
) )
@@ -34,11 +34,9 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.11.0 // indirect golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

View File

@@ -121,8 +121,8 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250305151038-478940e79601 h1:NEsjCG6uSvLRBlsP3+x6PL1kM+Ojs3g8UGotIPgJSz8= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f h1:j6SjP98MoWFFX9TwB1/nFYEkayqHQsrtE66Ll2C+oT0=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250305151038-478940e79601/go.mod h1:OblWe1+QrZwdpwO0j/LY3BSGuKT3YPUFBDQQgvvfStQ= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f/go.mod h1:Aa/kD1XB+OV/7rRxMQrjcPCB4b0pKyLH0gsTrtuHi38=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec= github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=

View File

@@ -731,8 +731,9 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/compose-spec/compose-go v1.20.0 h1:h4ZKOst1EF/DwZp7dWkb+wbTVE4nEyT9Lc89to84Ol4= github.com/compose-spec/compose-go v1.20.0 h1:h4ZKOst1EF/DwZp7dWkb+wbTVE4nEyT9Lc89to84Ol4=
github.com/compose-spec/compose-go v1.20.0/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM= github.com/compose-spec/compose-go v1.20.0/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
github.com/consensys/bavard v0.1.27/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
github.com/consensys/gnark-crypto v0.13.0/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o=
github.com/container-orchestrated-devices/container-device-interface v0.6.1 h1:mz77uJoP8im/4Zins+mPqt677ZMaflhoGaYrRAl5jvA= github.com/container-orchestrated-devices/container-device-interface v0.6.1 h1:mz77uJoP8im/4Zins+mPqt677ZMaflhoGaYrRAl5jvA=
github.com/container-orchestrated-devices/container-device-interface v0.6.1/go.mod h1:40T6oW59rFrL/ksiSs7q45GzjGlbvxnA4xaK6cyq+kA= github.com/container-orchestrated-devices/container-device-interface v0.6.1/go.mod h1:40T6oW59rFrL/ksiSs7q45GzjGlbvxnA4xaK6cyq+kA=
github.com/containerd/aufs v1.0.0 h1:2oeJiwX5HstO7shSrPZjrohJZLzK36wvpdmzDRkL/LY= github.com/containerd/aufs v1.0.0 h1:2oeJiwX5HstO7shSrPZjrohJZLzK36wvpdmzDRkL/LY=
@@ -792,6 +793,7 @@ github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS3
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0= github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0=
@@ -1199,6 +1201,7 @@ github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4= github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4=
@@ -1409,11 +1412,15 @@ github.com/scroll-tech/da-codec v0.1.3-0.20250609113414-f33adf0904bd/go.mod h1:g
github.com/scroll-tech/da-codec v0.1.3-0.20250609154559-8935de62c148 h1:cyK1ifU2fRoMl8YWR9LOsZK4RvJnlG3RODgakj5I8VY= github.com/scroll-tech/da-codec v0.1.3-0.20250609154559-8935de62c148 h1:cyK1ifU2fRoMl8YWR9LOsZK4RvJnlG3RODgakj5I8VY=
github.com/scroll-tech/da-codec v0.1.3-0.20250609154559-8935de62c148/go.mod h1:gz5x3CsLy5htNTbv4PWRPBU9nSAujfx1U2XtFcXoFuk= github.com/scroll-tech/da-codec v0.1.3-0.20250609154559-8935de62c148/go.mod h1:gz5x3CsLy5htNTbv4PWRPBU9nSAujfx1U2XtFcXoFuk=
github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg=
github.com/scroll-tech/da-codec v0.1.3-0.20250825071838-cddc263e5ef6/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg=
github.com/scroll-tech/ecies-go/v2 v2.0.10-beta.1/go.mod h1:A+pHaITd+ogBm4Rk35xebF9OPiyMYlFlgqBOiY5PSjg=
github.com/scroll-tech/go-ethereum v1.10.14-0.20240607130425-e2becce6a1a4/go.mod h1:byf/mZ8jLYUCnUePTicjJWn+RvKdxDn7buS6glTnMwQ= github.com/scroll-tech/go-ethereum v1.10.14-0.20240607130425-e2becce6a1a4/go.mod h1:byf/mZ8jLYUCnUePTicjJWn+RvKdxDn7buS6glTnMwQ=
github.com/scroll-tech/go-ethereum v1.10.14-0.20240821074444-b3fa00861e5e/go.mod h1:swB5NSp8pKNDuYsTxfR08bHS6L56i119PBx8fxvV8Cs= github.com/scroll-tech/go-ethereum v1.10.14-0.20240821074444-b3fa00861e5e/go.mod h1:swB5NSp8pKNDuYsTxfR08bHS6L56i119PBx8fxvV8Cs=
github.com/scroll-tech/go-ethereum v1.10.14-0.20241010064814-3d88e870ae22/go.mod h1:r9FwtxCtybMkTbWYCyBuevT9TW3zHmOTHqD082Uh+Oo= github.com/scroll-tech/go-ethereum v1.10.14-0.20241010064814-3d88e870ae22/go.mod h1:r9FwtxCtybMkTbWYCyBuevT9TW3zHmOTHqD082Uh+Oo=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250206083728-ea43834c198f/go.mod h1:Ik3OBLl7cJxPC+CFyCBYNXBPek4wpdzkWehn/y5qLM8= github.com/scroll-tech/go-ethereum v1.10.14-0.20250206083728-ea43834c198f/go.mod h1:Ik3OBLl7cJxPC+CFyCBYNXBPek4wpdzkWehn/y5qLM8=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250225152658-bcfdb48dd939/go.mod h1:AgU8JJxC7+nfs7R7ma35AU7dMAGW7wCw3dRZRefIKyQ= github.com/scroll-tech/go-ethereum v1.10.14-0.20250225152658-bcfdb48dd939/go.mod h1:AgU8JJxC7+nfs7R7ma35AU7dMAGW7wCw3dRZRefIKyQ=
github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092359-25d5bf6b817b h1:pMQKnroJoS/FeL1aOWkz7/u1iBHUP8PWjZstNuzoUGE=
github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092359-25d5bf6b817b/go.mod h1:Aa/kD1XB+OV/7rRxMQrjcPCB4b0pKyLH0gsTrtuHi38=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
@@ -1611,6 +1618,7 @@ golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOM
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1632,6 +1640,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
@@ -1781,6 +1790,7 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
@@ -1789,6 +1799,7 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@@ -66,17 +66,26 @@ func action(ctx *cli.Context) error {
registry := prometheus.DefaultRegisterer registry := prometheus.DefaultRegisterer
observability.Server(ctx, db) observability.Server(ctx, db)
l1client, err := ethclient.Dial(cfg.L1Config.Endpoint) // Init L1 connection
l1RpcClient, err := rpc.Dial(cfg.L1Config.Endpoint)
if err != nil { if err != nil {
log.Crit("failed to connect l1 geth", "config file", cfgFile, "error", err) log.Crit("failed to dial raw RPC client to L1 endpoint", "endpoint", cfg.L1Config.Endpoint, "error", err)
}
l1client := ethclient.NewClient(l1RpcClient)
// sanity check config
if cfg.L1Config.RelayerConfig.GasOracleConfig.L1BaseFeeLimit == 0 || cfg.L1Config.RelayerConfig.GasOracleConfig.L1BlobBaseFeeLimit == 0 {
log.Crit("gas-oracle `l1_base_fee_limit` and `l1_blob_base_fee_limit` configs must be set")
} }
l1watcher := watcher.NewL1WatcherClient(ctx.Context, l1client, cfg.L1Config.StartHeight, db, registry) // Init watcher and relayer
l1watcher := watcher.NewL1WatcherClient(ctx.Context, l1RpcClient, cfg.L1Config.StartHeight, db, registry)
l1relayer, err := relayer.NewLayer1Relayer(ctx.Context, db, cfg.L1Config.RelayerConfig, relayer.ServiceTypeL1GasOracle, registry) l1relayer, err := relayer.NewLayer1Relayer(ctx.Context, db, cfg.L1Config.RelayerConfig, relayer.ServiceTypeL1GasOracle, registry)
if err != nil { if err != nil {
log.Crit("failed to create new l1 relayer", "config file", cfgFile, "error", err) log.Crit("failed to create new l1 relayer", "config file", cfgFile, "error", err)
} }
// Start l1 watcher process // Start l1 watcher process
go utils.LoopWithContext(subCtx, 10*time.Second, func(ctx context.Context) { go utils.LoopWithContext(subCtx, 10*time.Second, func(ctx context.Context) {
// Fetch the latest block number to decrease the delay when fetching gas prices // Fetch the latest block number to decrease the delay when fetching gas prices

View File

@@ -10,8 +10,8 @@ import (
"github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/da-codec/encoding"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc"
"scroll-tech/common/database" "scroll-tech/common/database"
"scroll-tech/common/observability" "scroll-tech/common/observability"
@@ -91,12 +91,13 @@ func action(ctx *cli.Context) error {
bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, minCodecVersion, genesis.Config, db, registry) bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, minCodecVersion, genesis.Config, db, registry)
// Init l2geth connection // Init l2geth connection
l2client, err := ethclient.Dial(cfg.L2Config.Endpoint) l2client, err := rpc.Dial(cfg.L2Config.Endpoint)
if err != nil { if err != nil {
return fmt.Errorf("failed to connect to L2geth at RPC=%s: %w", cfg.L2Config.Endpoint, err) return fmt.Errorf("failed to connect to L2geth at RPC=%s: %w", cfg.L2Config.Endpoint, err)
} }
l2Watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) l2Watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress,
cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, cfg.L2Config.RelayerConfig.ValidiumMode, registry)
recovery := permissionless_batches.NewRecovery(subCtx, cfg, genesis, db, chunkProposer, batchProposer, bundleProposer, l2Watcher) recovery := permissionless_batches.NewRecovery(subCtx, cfg, genesis, db, chunkProposer, batchProposer, bundleProposer, l2Watcher)

View File

@@ -12,6 +12,7 @@ import (
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rollup/l1" "github.com/scroll-tech/go-ethereum/rollup/l1"
"github.com/scroll-tech/go-ethereum/rpc"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"scroll-tech/common/database" "scroll-tech/common/database"
@@ -69,10 +70,11 @@ func action(ctx *cli.Context) error {
observability.Server(ctx, db) observability.Server(ctx, db)
// Init l2geth connection // Init l2geth connection
l2client, err := ethclient.Dial(cfg.L2Config.Endpoint) l2client, err := rpc.Dial(cfg.L2Config.Endpoint)
if err != nil { if err != nil {
log.Crit("failed to connect l2 geth", "config file", cfgFile, "error", err) log.Crit("failed to connect l2 geth", "config file", cfgFile, "error", err)
} }
l2ethClient := ethclient.NewClient(l2client)
genesisPath := ctx.String(utils.Genesis.Name) genesisPath := ctx.String(utils.Genesis.Name)
genesis, err := utils.ReadGenesis(genesisPath) genesis, err := utils.ReadGenesis(genesisPath)
@@ -96,8 +98,11 @@ func action(ctx *cli.Context) error {
if cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk <= 0 { if cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk <= 0 {
log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0") log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0")
} }
if cfg.L2Config.RelayerConfig.SenderConfig.FusakaTimestamp == 0 {
log.Crit("cfg.L2Config.RelayerConfig.SenderConfig.FusakaTimestamp must be set")
}
l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2client, db, cfg.L2Config.RelayerConfig, genesis.Config, relayer.ServiceTypeL2RollupRelayer, registry) l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2ethClient, db, cfg.L2Config.RelayerConfig, genesis.Config, relayer.ServiceTypeL2RollupRelayer, registry)
if err != nil { if err != nil {
log.Crit("failed to create l2 relayer", "config file", cfgFile, "error", err) log.Crit("failed to create l2 relayer", "config file", cfgFile, "error", err)
} }
@@ -111,7 +116,7 @@ func action(ctx *cli.Context) error {
batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, minCodecVersion, genesis.Config, db, cfg.L2Config.RelayerConfig.ValidiumMode, registry) batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, minCodecVersion, genesis.Config, db, cfg.L2Config.RelayerConfig.ValidiumMode, registry)
bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, minCodecVersion, genesis.Config, db, registry) bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, minCodecVersion, genesis.Config, db, registry)
l2watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) l2watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, cfg.L2Config.RelayerConfig.ValidiumMode, registry)
if cfg.RecoveryConfig != nil && cfg.RecoveryConfig.Enable { if cfg.RecoveryConfig != nil && cfg.RecoveryConfig.Enable {
log.Info("Starting rollup-relayer in recovery mode", "version", version.Version) log.Info("Starting rollup-relayer in recovery mode", "version", version.Version)
@@ -141,7 +146,7 @@ func action(ctx *cli.Context) error {
// Watcher loop to fetch missing blocks // Watcher loop to fetch missing blocks
go utils.LoopWithContext(subCtx, 2*time.Second, func(ctx context.Context) { go utils.LoopWithContext(subCtx, 2*time.Second, func(ctx context.Context) {
number, loopErr := rutils.GetLatestConfirmedBlockNumber(ctx, l2client, cfg.L2Config.Confirmations) number, loopErr := rutils.GetLatestConfirmedBlockNumber(ctx, l2ethClient, cfg.L2Config.Confirmations)
if loopErr != nil { if loopErr != nil {
log.Error("failed to get block number", "err", loopErr) log.Error("failed to get block number", "err", loopErr)
return return

View File

@@ -21,7 +21,9 @@
"check_committed_batches_window_minutes": 5, "check_committed_batches_window_minutes": 5,
"l1_base_fee_default": 15000000000, "l1_base_fee_default": 15000000000,
"l1_blob_base_fee_default": 1, "l1_blob_base_fee_default": 1,
"l1_blob_base_fee_threshold": 0 "l1_blob_base_fee_threshold": 0,
"l1_base_fee_limit": 20000000000,
"l1_blob_base_fee_limit": 20000000000
}, },
"gas_oracle_sender_signer_config": { "gas_oracle_sender_signer_config": {
"signer_type": "PrivateKey", "signer_type": "PrivateKey",
@@ -49,13 +51,15 @@
"tx_type": "DynamicFeeTx", "tx_type": "DynamicFeeTx",
"check_pending_time": 1, "check_pending_time": 1,
"min_gas_tip": 100000000, "min_gas_tip": 100000000,
"max_pending_blob_txs": 3 "max_pending_blob_txs": 3,
"fusaka_timestamp": 9999999999999
}, },
"batch_submission": { "batch_submission": {
"min_batches": 1, "min_batches": 1,
"max_batches": 6, "max_batches": 6,
"timeout": 7200, "timeout": 7200,
"backlog_max": 75 "backlog_max": 75,
"blob_fee_tolerance": 500000000
}, },
"gas_oracle_config": { "gas_oracle_config": {
"min_gas_price": 0, "min_gas_price": 0,

View File

@@ -15,8 +15,8 @@ require (
github.com/holiman/uint256 v1.3.2 github.com/holiman/uint256 v1.3.2
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/prometheus/client_golang v1.16.0 github.com/prometheus/client_golang v1.16.0
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 github.com/scroll-tech/da-codec v0.10.0
github.com/scroll-tech/go-ethereum v1.10.14-0.20250626110859-cc9a1dd82de7 github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f
github.com/smartystreets/goconvey v1.8.0 github.com/smartystreets/goconvey v1.8.0
github.com/spf13/viper v1.19.0 github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
@@ -49,10 +49,11 @@ require (
github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/consensys/bavard v0.1.29 // indirect github.com/consensys/bavard v0.1.29 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect github.com/deckarep/golang-set v1.8.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/fjl/memsize v0.0.2 // indirect github.com/fjl/memsize v0.0.2 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
@@ -118,7 +119,7 @@ require (
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/status-im/keycard-go v0.2.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/supranational/blst v0.3.13 // indirect github.com/supranational/blst v0.3.15 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect github.com/tklauser/numcpus v0.9.0 // indirect

View File

@@ -79,6 +79,8 @@ github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw
github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU= github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4=
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -86,13 +88,13 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
github.com/ethereum/c-kzg-4844 v1.0.3/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
@@ -285,10 +287,10 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 h1:4utngmJHXSOS5FoSdZhEV1xMRirpArbXvyoCZY9nYj0= github.com/scroll-tech/da-codec v0.10.0 h1:IPHxyTyXTWPV0Q+DZ08cod2fWkhUvrfysmj/VBpB+WU=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= github.com/scroll-tech/da-codec v0.10.0/go.mod h1:MBlIP4wCXPcUDZ/Ci2B7n/2IbVU1WBo9OTFTZ5ffE0U=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250626110859-cc9a1dd82de7 h1:1rN1qocsQlOyk1VCpIEF1J5pfQbLAi1pnMZSLQS37jQ= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f h1:j6SjP98MoWFFX9TwB1/nFYEkayqHQsrtE66Ll2C+oT0=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250626110859-cc9a1dd82de7/go.mod h1:pDCZ4iGvEGmdIe4aSAGBrb7XSrKEML6/L/wEMmNxOdk= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f/go.mod h1:Aa/kD1XB+OV/7rRxMQrjcPCB4b0pKyLH0gsTrtuHi38=
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
@@ -330,8 +332,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o=
github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/supranational/blst v0.3.15/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=

View File

@@ -7,8 +7,14 @@ import (
// SenderConfig The config for transaction sender // SenderConfig The config for transaction sender
type SenderConfig struct { type SenderConfig struct {
// The RPC endpoint of the ethereum or scroll public node. // The RPC endpoint of the ethereum or scroll public node (for backward compatibility).
// If WriteEndpoints is specified, this endpoint will be used only for reading.
// If WriteEndpoints is empty, this endpoint will be used for both reading and writing.
Endpoint string `json:"endpoint"` Endpoint string `json:"endpoint"`
// The RPC endpoints to send transactions to (optional).
// If specified, transactions will be sent to all these endpoints in parallel.
// If empty, transactions will be sent to the Endpoint.
WriteEndpoints []string `json:"write_endpoints,omitempty"`
// The time to trigger check pending txs in sender. // The time to trigger check pending txs in sender.
CheckPendingTime uint64 `json:"check_pending_time"` CheckPendingTime uint64 `json:"check_pending_time"`
// The number of blocks to wait to escalate increase gas price of the transaction. // The number of blocks to wait to escalate increase gas price of the transaction.
@@ -29,6 +35,8 @@ type SenderConfig struct {
TxType string `json:"tx_type"` TxType string `json:"tx_type"`
// The maximum number of pending blob-carrying transactions // The maximum number of pending blob-carrying transactions
MaxPendingBlobTxs int64 `json:"max_pending_blob_txs"` MaxPendingBlobTxs int64 `json:"max_pending_blob_txs"`
// The timestamp of the Ethereum Fusaka upgrade in seconds since epoch.
FusakaTimestamp uint64 `json:"fusaka_timestamp"`
} }
type BatchSubmission struct { type BatchSubmission struct {
@@ -40,6 +48,10 @@ type BatchSubmission struct {
TimeoutSec int64 `json:"timeout"` TimeoutSec int64 `json:"timeout"`
// The maximum number of pending batches to keep in the backlog. // The maximum number of pending batches to keep in the backlog.
BacklogMax int64 `json:"backlog_max"` BacklogMax int64 `json:"backlog_max"`
// BlobFeeTolerance is the absolute tolerance (in wei) added to the target blob fee.
// If the current fee is below target + tolerance, we proceed with submission.
// This prevents skipping submission when the price difference is negligible.
BlobFeeTolerance uint64 `json:"blob_fee_tolerance"`
} }
// ChainMonitor this config is used to get batch status from chain_monitor API. // ChainMonitor this config is used to get batch status from chain_monitor API.
@@ -101,6 +113,10 @@ type GasOracleConfig struct {
L1BaseFeeDefault uint64 `json:"l1_base_fee_default"` L1BaseFeeDefault uint64 `json:"l1_base_fee_default"`
L1BlobBaseFeeDefault uint64 `json:"l1_blob_base_fee_default"` L1BlobBaseFeeDefault uint64 `json:"l1_blob_base_fee_default"`
// Upper limit values for gas oracle updates
L1BaseFeeLimit uint64 `json:"l1_base_fee_limit"`
L1BlobBaseFeeLimit uint64 `json:"l1_blob_base_fee_limit"`
// L1BlobBaseFeeThreshold the threshold of L1 blob base fee to enter the default gas price mode // L1BlobBaseFeeThreshold the threshold of L1 blob base fee to enter the default gas price mode
L1BlobBaseFeeThreshold uint64 `json:"l1_blob_base_fee_threshold"` L1BlobBaseFeeThreshold uint64 `json:"l1_blob_base_fee_threshold"`
} }

View File

@@ -167,7 +167,7 @@ func (b *BlobUploader) constructBlobCodec(dbBatch *orm.Batch) (*kzg4844.Blob, er
Chunks: chunks, Chunks: chunks,
} }
case encoding.CodecV7, encoding.CodecV8: case encoding.CodecV7, encoding.CodecV8, encoding.CodecV9, encoding.CodecV10:
encodingBatch = &encoding.Batch{ encodingBatch = &encoding.Batch{
Index: dbBatch.Index, Index: dbBatch.Index,
ParentBatchHash: common.HexToHash(dbBatch.ParentBatchHash), ParentBatchHash: common.HexToHash(dbBatch.ParentBatchHash),
@@ -242,10 +242,12 @@ func (b *BlobUploader) GetFirstUnuploadedBatchByPlatform(ctx context.Context, st
break break
} }
if len(batch.CommitTxHash) == 0 { // disable this check to upload blobs before it's committed. This is to
log.Debug("got batch not committed for blob uploading", "batch_index", batchIndex, "platform", platform.String()) // alleviate the case nodes try to fetch the blob from s3 before its uploaded.
return nil, nil // if len(batch.CommitTxHash) == 0 {
} // log.Debug("got batch not committed for blob uploading", "batch_index", batchIndex, "platform", platform.String())
// return nil, nil
// }
return batch, nil return batch, nil
} }

View File

@@ -173,6 +173,18 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() {
} else if err != nil { } else if err != nil {
return return
} }
// Cap base fee update at the configured upper limit
if limit := r.cfg.GasOracleConfig.L1BaseFeeLimit; baseFee > limit {
log.Error("L1 base fee exceed max limit, set to max limit", "baseFee", baseFee, "maxLimit", limit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
baseFee = limit
}
// Cap blob base fee update at the configured upper limit
if limit := r.cfg.GasOracleConfig.L1BlobBaseFeeLimit; blobBaseFee > limit {
log.Error("L1 blob base fee exceed max limit, set to max limit", "blobBaseFee", blobBaseFee, "maxLimit", limit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
blobBaseFee = limit
}
data, err := r.l1GasOracleABI.Pack("setL1BaseFeeAndBlobBaseFee", new(big.Int).SetUint64(baseFee), new(big.Int).SetUint64(blobBaseFee)) data, err := r.l1GasOracleABI.Pack("setL1BaseFeeAndBlobBaseFee", new(big.Int).SetUint64(baseFee), new(big.Int).SetUint64(blobBaseFee))
if err != nil { if err != nil {
log.Error("Failed to pack setL1BaseFeeAndBlobBaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "err", err) log.Error("Failed to pack setL1BaseFeeAndBlobBaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "err", err)

View File

@@ -8,11 +8,12 @@ import (
) )
type l1RelayerMetrics struct { type l1RelayerMetrics struct {
rollupL1RelayerGasPriceOraclerRunTotal prometheus.Counter rollupL1RelayerGasPriceOraclerRunTotal prometheus.Counter
rollupL1RelayerLatestBaseFee prometheus.Gauge rollupL1RelayerLatestBaseFee prometheus.Gauge
rollupL1RelayerLatestBlobBaseFee prometheus.Gauge rollupL1RelayerLatestBlobBaseFee prometheus.Gauge
rollupL1UpdateGasOracleConfirmedTotal prometheus.Counter rollupL1UpdateGasOracleConfirmedTotal prometheus.Counter
rollupL1UpdateGasOracleConfirmedFailedTotal prometheus.Counter rollupL1UpdateGasOracleConfirmedFailedTotal prometheus.Counter
rollupL1RelayerGasPriceOracleFeeOverLimitTotal prometheus.Counter
} }
var ( var (
@@ -43,6 +44,10 @@ func initL1RelayerMetrics(reg prometheus.Registerer) *l1RelayerMetrics {
Name: "rollup_layer1_update_gas_oracle_confirmed_failed_total", Name: "rollup_layer1_update_gas_oracle_confirmed_failed_total",
Help: "The total number of updating layer1 gas oracle confirmed failed", Help: "The total number of updating layer1 gas oracle confirmed failed",
}), }),
rollupL1RelayerGasPriceOracleFeeOverLimitTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "rollup_layer1_gas_price_oracle_fee_over_limit_total",
Help: "The total number of times when a gas price oracle fee update went over the configured limit",
}),
} }
}) })
return l1RelayerMetric return l1RelayerMetric

View File

@@ -345,8 +345,16 @@ func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte,
// - backlogCount > r.cfg.BatchSubmission.BacklogMax -> forceSubmit // - backlogCount > r.cfg.BatchSubmission.BacklogMax -> forceSubmit
// - we have at least minBatches AND price hits a desired target price // - we have at least minBatches AND price hits a desired target price
func (r *Layer2Relayer) ProcessPendingBatches() { func (r *Layer2Relayer) ProcessPendingBatches() {
// Get effective batch limits based on whether validium mode is enabled. // First, get the backlog count to determine batch submission strategy
minBatches, maxBatches := r.getEffectiveBatchLimits() backlogCount, err := r.batchOrm.GetFailedAndPendingBatchesCount(r.ctx)
if err != nil {
log.Error("Failed to fetch pending L2 batches count", "err", err)
return
}
r.metrics.rollupL2RelayerBacklogCounts.Set(float64(backlogCount))
// Get effective batch limits based on validium mode and backlog size.
minBatches, maxBatches := r.getEffectiveBatchLimits(backlogCount)
// get pending batches from database in ascending order by their index. // get pending batches from database in ascending order by their index.
dbBatches, err := r.batchOrm.GetFailedAndPendingBatches(r.ctx, maxBatches) dbBatches, err := r.batchOrm.GetFailedAndPendingBatches(r.ctx, maxBatches)
@@ -360,15 +368,6 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
return return
} }
// if backlog outgrow max size, forcesubmit enough oldest batches
backlogCount, err := r.batchOrm.GetFailedAndPendingBatchesCount(r.ctx)
r.metrics.rollupL2RelayerBacklogCounts.Set(float64(backlogCount))
if err != nil {
log.Error("Failed to fetch pending L2 batches", "err", err)
return
}
var forceSubmit bool var forceSubmit bool
startChunk, err := r.chunkOrm.GetChunkByIndex(r.ctx, dbBatches[0].StartChunkIndex) startChunk, err := r.chunkOrm.GetChunkByIndex(r.ctx, dbBatches[0].StartChunkIndex)
@@ -453,6 +452,7 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
// The next call of ProcessPendingBatches will then start with the batch with the different codec version. // The next call of ProcessPendingBatches will then start with the batch with the different codec version.
batchesToSubmitLen := len(batchesToSubmit) batchesToSubmitLen := len(batchesToSubmit)
if batchesToSubmitLen > 0 && batchesToSubmit[batchesToSubmitLen-1].Batch.CodecVersion != dbBatch.CodecVersion { if batchesToSubmitLen > 0 && batchesToSubmit[batchesToSubmitLen-1].Batch.CodecVersion != dbBatch.CodecVersion {
forceSubmit = true
break break
} }
@@ -489,7 +489,7 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
codecVersion := encoding.CodecVersion(firstBatch.CodecVersion) codecVersion := encoding.CodecVersion(firstBatch.CodecVersion)
switch codecVersion { switch codecVersion {
case encoding.CodecV7, encoding.CodecV8: case encoding.CodecV7, encoding.CodecV8, encoding.CodecV9, encoding.CodecV10:
if r.cfg.ValidiumMode { if r.cfg.ValidiumMode {
if len(batchesToSubmit) != 1 { if len(batchesToSubmit) != 1 {
log.Error("validium mode only supports committing one batch at a time", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "batches count", len(batchesToSubmit)) log.Error("validium mode only supports committing one batch at a time", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "batches count", len(batchesToSubmit))
@@ -563,12 +563,22 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
log.Info("Sent the commitBatches tx to layer1", "batches count", len(batchesToSubmit), "start index", firstBatch.Index, "start hash", firstBatch.Hash, "end index", lastBatch.Index, "end hash", lastBatch.Hash, "tx hash", txHash.String()) log.Info("Sent the commitBatches tx to layer1", "batches count", len(batchesToSubmit), "start index", firstBatch.Index, "start hash", firstBatch.Hash, "end index", lastBatch.Index, "end hash", lastBatch.Hash, "tx hash", txHash.String())
} }
// getEffectiveBatchLimits returns the effective min and max batch limits based on whether validium mode is enabled. // getEffectiveBatchLimits returns the effective min and max batch limits based on whether validium mode is enabled
func (r *Layer2Relayer) getEffectiveBatchLimits() (int, int) { // and the current backlog size.
// When backlogCount >= backlog_max: submit min_batches for fast inclusion at slightly higher price.
// When backlogCount < backlog_max: submit max_batches for better cost amortization.
func (r *Layer2Relayer) getEffectiveBatchLimits(backlogCount int64) (int, int) {
if r.cfg.ValidiumMode { if r.cfg.ValidiumMode {
return 1, 1 // minBatches=1, maxBatches=1 return 1, 1 // minBatches=1, maxBatches=1
} }
return r.cfg.BatchSubmission.MinBatches, r.cfg.BatchSubmission.MaxBatches
// If backlog is at or above max, prioritize fast inclusion by submitting min_batches
if backlogCount >= r.cfg.BatchSubmission.BacklogMax {
return r.cfg.BatchSubmission.MinBatches, r.cfg.BatchSubmission.MinBatches
}
// Otherwise, prioritize cost efficiency by trying to submit max_batches
return r.cfg.BatchSubmission.MaxBatches, r.cfg.BatchSubmission.MaxBatches
} }
func (r *Layer2Relayer) contextIDFromBatches(codecVersion encoding.CodecVersion, batches []*dbBatchWithChunks) string { func (r *Layer2Relayer) contextIDFromBatches(codecVersion encoding.CodecVersion, batches []*dbBatchWithChunks) string {
@@ -738,7 +748,7 @@ func (r *Layer2Relayer) finalizeBundle(bundle *orm.Bundle, withProof bool) error
var calldata []byte var calldata []byte
switch encoding.CodecVersion(bundle.CodecVersion) { switch encoding.CodecVersion(bundle.CodecVersion) {
case encoding.CodecV7, encoding.CodecV8: case encoding.CodecV7, encoding.CodecV8, encoding.CodecV9, encoding.CodecV10:
if r.cfg.ValidiumMode { if r.cfg.ValidiumMode {
calldata, err = r.constructFinalizeBundlePayloadValidium(dbBatch, endChunk, aggProof) calldata, err = r.constructFinalizeBundlePayloadValidium(dbBatch, endChunk, aggProof)
if err != nil { if err != nil {
@@ -1040,7 +1050,15 @@ func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batch *dbBatchWithCh
lastChunk := batch.Chunks[len(batch.Chunks)-1] lastChunk := batch.Chunks[len(batch.Chunks)-1]
commitment := common.HexToHash(lastChunk.EndBlockHash) commitment := common.HexToHash(lastChunk.EndBlockHash)
version := encoding.CodecVersion(batch.Batch.CodecVersion) var version uint8
if encoding.CodecVersion(batch.Batch.CodecVersion) == encoding.CodecV8 || encoding.CodecVersion(batch.Batch.CodecVersion) == encoding.CodecV9 || encoding.CodecVersion(batch.Batch.CodecVersion) == encoding.CodecV10 {
// Validium version line starts with v1,
// but rollup-relayer behavior follows v8.
version = 1
} else {
return nil, 0, 0, fmt.Errorf("unexpected codec version %d for validium mode", batch.Batch.CodecVersion)
}
calldata, err := r.validiumABI.Pack("commitBatch", version, common.HexToHash(batch.Batch.ParentBatchHash), common.HexToHash(batch.Batch.StateRoot), common.HexToHash(batch.Batch.WithdrawRoot), commitment[:]) calldata, err := r.validiumABI.Pack("commitBatch", version, common.HexToHash(batch.Batch.ParentBatchHash), common.HexToHash(batch.Batch.StateRoot), common.HexToHash(batch.Batch.WithdrawRoot), commitment[:])
if err != nil { if err != nil {
return nil, 0, 0, fmt.Errorf("failed to pack commitBatch: %w", err) return nil, 0, 0, fmt.Errorf("failed to pack commitBatch: %w", err)
@@ -1237,16 +1255,20 @@ func (r *Layer2Relayer) skipSubmitByFee(oldest time.Time, metrics *l2RelayerMetr
target := calculateTargetPrice(windowSec, r.batchStrategy, oldest, hist) target := calculateTargetPrice(windowSec, r.batchStrategy, oldest, hist)
current := hist[len(hist)-1] current := hist[len(hist)-1]
// apply absolute tolerance offset to target
tolerance := new(big.Int).SetUint64(r.cfg.BatchSubmission.BlobFeeTolerance)
threshold := new(big.Int).Add(target, tolerance)
currentFloat, _ := current.Float64() currentFloat, _ := current.Float64()
targetFloat, _ := target.Float64() targetFloat, _ := target.Float64()
metrics.rollupL2RelayerCurrentBlobPrice.Set(currentFloat) metrics.rollupL2RelayerCurrentBlobPrice.Set(currentFloat)
metrics.rollupL2RelayerTargetBlobPrice.Set(targetFloat) metrics.rollupL2RelayerTargetBlobPrice.Set(targetFloat)
// if current fee > target and still inside the timeout window, skip // if current fee > threshold (target + tolerance) and still inside the timeout window, skip
if current.Cmp(target) > 0 && time.Since(oldest) < time.Duration(windowSec)*time.Second { if current.Cmp(threshold) > 0 && time.Since(oldest) < time.Duration(windowSec)*time.Second {
return true, fmt.Errorf( return true, fmt.Errorf(
"blob-fee above target & window not yet passed; current=%s target=%s age=%s", "blob-fee above threshold & window not yet passed; current=%s target=%s threshold=%s tolerance=%s age=%s",
current.String(), target.String(), time.Since(oldest), current.String(), target.String(), threshold.String(), tolerance.String(), time.Since(oldest),
) )
} }

View File

@@ -56,6 +56,7 @@ func setupEnv(t *testing.T) {
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint, err = testApps.GetPoSL1EndPoint() cfg.L2Config.RelayerConfig.SenderConfig.Endpoint, err = testApps.GetPoSL1EndPoint()
assert.NoError(t, err) assert.NoError(t, err)
cfg.L2Config.RelayerConfig.SenderConfig.WriteEndpoints = []string{cfg.L2Config.RelayerConfig.SenderConfig.Endpoint, cfg.L2Config.RelayerConfig.SenderConfig.Endpoint}
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint, err = testApps.GetL2GethEndPoint() cfg.L1Config.RelayerConfig.SenderConfig.Endpoint, err = testApps.GetL2GethEndPoint()
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -2,6 +2,7 @@ package sender
import ( import (
"errors" "errors"
"fmt"
"math/big" "math/big"
"github.com/scroll-tech/go-ethereum" "github.com/scroll-tech/go-ethereum"
@@ -52,7 +53,7 @@ func (s *Sender) estimateDynamicGas(to *common.Address, data []byte, baseFee uin
if err != nil { if err != nil {
log.Error("estimateDynamicGas estimateGasLimit failure", log.Error("estimateDynamicGas estimateGasLimit failure",
"from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "to address", to.String(), "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "to address", to.String(),
"fallback gas limit", "error", err) "error", err)
return nil, err return nil, err
} }
@@ -118,7 +119,7 @@ func (s *Sender) estimateGasLimit(to *common.Address, data []byte, sidecar *type
gasLimitWithoutAccessList, err := s.client.EstimateGas(s.ctx, msg) gasLimitWithoutAccessList, err := s.client.EstimateGas(s.ctx, msg)
if err != nil { if err != nil {
log.Error("estimateGasLimit EstimateGas failure without access list", "error", err) log.Error("estimateGasLimit EstimateGas failure without access list", "error", err, "msg", fmt.Sprintf("%+v", msg))
return 0, nil, err return 0, nil, err
} }

View File

@@ -7,12 +7,13 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"strings" "strings"
"sync"
"time" "time"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/consensus/misc" "github.com/scroll-tech/go-ethereum/common/hexutil"
gethTypes "github.com/scroll-tech/go-ethereum/core/types" gethTypes "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto/kzg4844" "github.com/scroll-tech/go-ethereum/crypto/kzg4844"
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/ethclient"
@@ -66,8 +67,10 @@ type FeeData struct {
// Sender Transaction sender to send transaction to l1/l2 // Sender Transaction sender to send transaction to l1/l2
type Sender struct { type Sender struct {
config *config.SenderConfig config *config.SenderConfig
gethClient *gethclient.Client rpcClient *rpc.Client // Raw RPC client
client *ethclient.Client // The client to retrieve on chain data or send transaction. gethClient *gethclient.Client // Client to use for CreateAccessList
client *ethclient.Client // The client to retrieve on chain data (read-only)
writeClients []*ethclient.Client // The clients to send transactions to (write operations)
transactionSigner *TransactionSigner transactionSigner *TransactionSigner
chainID *big.Int // The chain id of the endpoint chainID *big.Int // The chain id of the endpoint
ctx context.Context ctx context.Context
@@ -90,9 +93,10 @@ func NewSender(ctx context.Context, config *config.SenderConfig, signerConfig *c
return nil, fmt.Errorf("invalid params, EscalateMultipleNum; %v, EscalateMultipleDen: %v", config.EscalateMultipleNum, config.EscalateMultipleDen) return nil, fmt.Errorf("invalid params, EscalateMultipleNum; %v, EscalateMultipleDen: %v", config.EscalateMultipleNum, config.EscalateMultipleDen)
} }
// Initialize read client
rpcClient, err := rpc.Dial(config.Endpoint) rpcClient, err := rpc.Dial(config.Endpoint)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to dial eth client, err: %w", err) return nil, fmt.Errorf("failed to dial read client, err: %w", err)
} }
client := ethclient.NewClient(rpcClient) client := ethclient.NewClient(rpcClient)
@@ -105,12 +109,43 @@ func NewSender(ctx context.Context, config *config.SenderConfig, signerConfig *c
return nil, fmt.Errorf("failed to create transaction signer, err: %w", err) return nil, fmt.Errorf("failed to create transaction signer, err: %w", err)
} }
// Initialize write clients
var writeClients []*ethclient.Client
if len(config.WriteEndpoints) > 0 {
// Use specified write endpoints
for i, endpoint := range config.WriteEndpoints {
writeRpcClient, err := rpc.Dial(endpoint)
if err != nil {
return nil, fmt.Errorf("failed to dial write client %d (endpoint: %s), err: %w", i, endpoint, err)
}
writeClient := ethclient.NewClient(writeRpcClient)
// Verify the write client is connected to the same chain
writeChainID, err := writeClient.ChainID(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get chain ID from write client %d (endpoint: %s), err: %w", i, endpoint, err)
}
if writeChainID.Cmp(chainID) != 0 {
return nil, fmt.Errorf("write client %d (endpoint: %s) has different chain ID %s, expected %s", i, endpoint, writeChainID.String(), chainID.String())
}
writeClients = append(writeClients, writeClient)
}
log.Info("initialized sender with multiple write clients", "service", service, "name", name, "readEndpoint", config.Endpoint, "writeEndpoints", config.WriteEndpoints)
} else {
// Use read client for writing (backward compatibility)
writeClients = append(writeClients, client)
log.Info("initialized sender with single client", "service", service, "name", name, "endpoint", config.Endpoint)
}
// Create sender instance first and then initialize nonce // Create sender instance first and then initialize nonce
sender := &Sender{ sender := &Sender{
ctx: ctx, ctx: ctx,
config: config, config: config,
rpcClient: rpcClient,
gethClient: gethclient.New(rpcClient), gethClient: gethclient.New(rpcClient),
client: client, client: client,
writeClients: writeClients,
chainID: chainID, chainID: chainID,
transactionSigner: transactionSigner, transactionSigner: transactionSigner,
db: db, db: db,
@@ -169,6 +204,82 @@ func (s *Sender) getFeeData(target *common.Address, data []byte, sidecar *gethTy
} }
} }
// sendTransactionToMultipleClients sends a transaction to all write clients in parallel
// and returns success if at least one client succeeds
func (s *Sender) sendTransactionToMultipleClients(signedTx *gethTypes.Transaction) error {
ctx, cancel := context.WithTimeout(s.ctx, 15*time.Second)
defer cancel()
if len(s.writeClients) == 1 {
// Single client - use direct approach
return s.writeClients[0].SendTransaction(ctx, signedTx)
}
// Multiple clients - send in parallel
type result struct {
endpoint string
err error
}
resultChan := make(chan result, len(s.writeClients))
var wg sync.WaitGroup
// Send transaction to all write clients in parallel
for i, client := range s.writeClients {
wg.Add(1)
// Determine endpoint URL for this client
endpoint := s.config.WriteEndpoints[i]
go func(ep string, writeClient *ethclient.Client) {
defer wg.Done()
err := writeClient.SendTransaction(ctx, signedTx)
resultChan <- result{endpoint: ep, err: err}
}(endpoint, client)
}
// Wait for all goroutines to finish
go func() {
wg.Wait()
close(resultChan)
}()
// Collect results
var errs []error
for res := range resultChan {
if res.err != nil {
errs = append(errs, fmt.Errorf("%s: %w", res.endpoint, res.err))
log.Warn("failed to send transaction to write client",
"endpoint", res.endpoint,
"txHash", signedTx.Hash().Hex(),
"nonce", signedTx.Nonce(),
"from", s.transactionSigner.GetAddr().String(),
"error", res.err)
} else {
log.Info("successfully sent transaction to write client",
"endpoint", res.endpoint,
"txHash", signedTx.Hash().Hex(),
"nonce", signedTx.Nonce(),
"from", s.transactionSigner.GetAddr().String())
}
}
// Check if at least one client succeeded
if len(errs) < len(s.writeClients) {
successCount := len(s.writeClients) - len(errs)
if len(errs) > 0 {
log.Info("transaction partially succeeded",
"txHash", signedTx.Hash().Hex(),
"successCount", successCount,
"totalClients", len(s.writeClients),
"failures", errors.Join(errs...))
}
return nil
}
// All clients failed
return fmt.Errorf("failed to send transaction to all %d write clients: %w", len(s.writeClients), errors.Join(errs...))
}
// SendTransaction send a signed L2tL1 transaction. // SendTransaction send a signed L2tL1 transaction.
func (s *Sender) SendTransaction(contextID string, target *common.Address, data []byte, blobs []*kzg4844.Blob) (common.Hash, uint64, error) { func (s *Sender) SendTransaction(contextID string, target *common.Address, data []byte, blobs []*kzg4844.Blob) (common.Hash, uint64, error) {
s.metrics.sendTransactionTotal.WithLabelValues(s.service, s.name).Inc() s.metrics.sendTransactionTotal.WithLabelValues(s.service, s.name).Inc()
@@ -178,6 +289,12 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data
err error err error
) )
blockNumber, blockTimestamp, baseFee, blobBaseFee, err := s.getBlockNumberAndTimestampAndBaseFeeAndBlobFee(s.ctx)
if err != nil {
log.Error("failed to get block number and base fee", "error", err)
return common.Hash{}, 0, fmt.Errorf("failed to get block number and base fee, err: %w", err)
}
if blobs != nil { if blobs != nil {
// check that number of pending blob-carrying txs is not too big // check that number of pending blob-carrying txs is not too big
if s.senderType == types.SenderTypeCommitBatch { if s.senderType == types.SenderTypeCommitBatch {
@@ -194,21 +311,24 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data
if numPendingTransactions >= s.config.MaxPendingBlobTxs { if numPendingTransactions >= s.config.MaxPendingBlobTxs {
return common.Hash{}, 0, ErrTooManyPendingBlobTxs return common.Hash{}, 0, ErrTooManyPendingBlobTxs
} }
} }
sidecar, err = makeSidecar(blobs)
if blockTimestamp < s.config.FusakaTimestamp && (s.config.FusakaTimestamp-blockTimestamp) < 180 {
return common.Hash{}, 0, fmt.Errorf("pausing blob txs before Fusaka upgrade, eta %d seconds", s.config.FusakaTimestamp-blockTimestamp)
}
version := gethTypes.BlobSidecarVersion0
if blockTimestamp >= s.config.FusakaTimestamp {
version = gethTypes.BlobSidecarVersion1
}
sidecar, err = makeSidecar(version, blobs)
if err != nil { if err != nil {
log.Error("failed to make sidecar for blob transaction", "error", err) log.Error("failed to make sidecar for blob transaction", "error", err)
return common.Hash{}, 0, fmt.Errorf("failed to make sidecar for blob transaction, err: %w", err) return common.Hash{}, 0, fmt.Errorf("failed to make sidecar for blob transaction, err: %w", err)
} }
} }
blockNumber, baseFee, blobBaseFee, err := s.getBlockNumberAndBaseFeeAndBlobFee(s.ctx)
if err != nil {
log.Error("failed to get block number and base fee", "error", err)
return common.Hash{}, 0, fmt.Errorf("failed to get block number and base fee, err: %w", err)
}
if feeData, err = s.getFeeData(target, data, sidecar, baseFee, blobBaseFee); err != nil { if feeData, err = s.getFeeData(target, data, sidecar, baseFee, blobBaseFee); err != nil {
s.metrics.sendTransactionFailureGetFee.WithLabelValues(s.service, s.name).Inc() s.metrics.sendTransactionFailureGetFee.WithLabelValues(s.service, s.name).Inc()
log.Error("failed to get fee data", "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "err", err) log.Error("failed to get fee data", "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "err", err)
@@ -230,7 +350,7 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data
return common.Hash{}, 0, fmt.Errorf("failed to insert transaction, err: %w", err) return common.Hash{}, 0, fmt.Errorf("failed to insert transaction, err: %w", err)
} }
if err := s.client.SendTransaction(s.ctx, signedTx); err != nil { if err := s.sendTransactionToMultipleClients(signedTx); err != nil {
// Delete the transaction from the pending transaction table if it fails to send. // Delete the transaction from the pending transaction table if it fails to send.
if updateErr := s.pendingTransactionOrm.DeleteTransactionByTxHash(s.ctx, signedTx.Hash()); updateErr != nil { if updateErr := s.pendingTransactionOrm.DeleteTransactionByTxHash(s.ctx, signedTx.Hash()); updateErr != nil {
log.Error("failed to delete transaction", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", updateErr) log.Error("failed to delete transaction", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", updateErr)
@@ -515,6 +635,10 @@ func (s *Sender) createReplacingTransaction(tx *gethTypes.Transaction, baseFee,
nonce := tx.Nonce() nonce := tx.Nonce()
s.metrics.resubmitTransactionTotal.WithLabelValues(s.service, s.name).Inc() s.metrics.resubmitTransactionTotal.WithLabelValues(s.service, s.name).Inc()
// Note: This might fail during the Fusaka upgrade, if we originally sent a V0 blob tx.
// Normally we would need to convert it to V1 before resubmitting. However, this case is
// unlikely and geth would still accept the V0 version, so we omit the conversion.
signedTx, err := s.createTx(&feeData, tx.To(), tx.Data(), tx.BlobTxSidecar(), nonce) signedTx, err := s.createTx(&feeData, tx.To(), tx.Data(), tx.BlobTxSidecar(), nonce)
if err != nil { if err != nil {
log.Error("failed to create signed tx (resubmit case)", "from", s.transactionSigner.GetAddr().String(), "nonce", nonce, "err", err) log.Error("failed to create signed tx (resubmit case)", "from", s.transactionSigner.GetAddr().String(), "nonce", nonce, "err", err)
@@ -528,7 +652,7 @@ func (s *Sender) createReplacingTransaction(tx *gethTypes.Transaction, baseFee,
func (s *Sender) checkPendingTransaction() { func (s *Sender) checkPendingTransaction() {
s.metrics.senderCheckPendingTransactionTotal.WithLabelValues(s.service, s.name).Inc() s.metrics.senderCheckPendingTransactionTotal.WithLabelValues(s.service, s.name).Inc()
blockNumber, baseFee, blobBaseFee, err := s.getBlockNumberAndBaseFeeAndBlobFee(s.ctx) blockNumber, _, baseFee, blobBaseFee, err := s.getBlockNumberAndTimestampAndBaseFeeAndBlobFee(s.ctx)
if err != nil { if err != nil {
log.Error("failed to get block number and base fee", "error", err) log.Error("failed to get block number and base fee", "error", err)
return return
@@ -645,7 +769,7 @@ func (s *Sender) checkPendingTransaction() {
return return
} }
if err := s.client.SendTransaction(s.ctx, newSignedTx); err != nil { if err := s.sendTransactionToMultipleClients(newSignedTx); err != nil {
if strings.Contains(err.Error(), "nonce too low") { if strings.Contains(err.Error(), "nonce too low") {
// When we receive a 'nonce too low' error but cannot find the transaction receipt, it indicates another transaction with this nonce has already been processed, so this transaction will never be mined and should be marked as failed. // When we receive a 'nonce too low' error but cannot find the transaction receipt, it indicates another transaction with this nonce has already been processed, so this transaction will never be mined and should be marked as failed.
log.Warn("nonce too low detected, marking all non-confirmed transactions with same nonce as failed", "nonce", originalTx.Nonce(), "address", s.transactionSigner.GetAddr().Hex(), "txHash", originalTx.Hash().Hex(), "newTxHash", newSignedTx.Hash().Hex(), "err", err) log.Warn("nonce too low detected, marking all non-confirmed transactions with same nonce as failed", "nonce", originalTx.Nonce(), "address", s.transactionSigner.GetAddr().Hex(), "txHash", originalTx.Hash().Hex(), "newTxHash", newSignedTx.Hash().Hex(), "err", err)
@@ -706,10 +830,10 @@ func (s *Sender) getSenderMeta() *orm.SenderMeta {
} }
} }
func (s *Sender) getBlockNumberAndBaseFeeAndBlobFee(ctx context.Context) (uint64, uint64, uint64, error) { func (s *Sender) getBlockNumberAndTimestampAndBaseFeeAndBlobFee(ctx context.Context) (uint64, uint64, uint64, uint64, error) {
header, err := s.client.HeaderByNumber(ctx, big.NewInt(rpc.PendingBlockNumber.Int64())) header, err := s.client.HeaderByNumber(ctx, big.NewInt(rpc.PendingBlockNumber.Int64()))
if err != nil { if err != nil {
return 0, 0, 0, fmt.Errorf("failed to get header by number, err: %w", err) return 0, 0, 0, 0, fmt.Errorf("failed to get header by number, err: %w", err)
} }
var baseFee uint64 var baseFee uint64
@@ -719,13 +843,24 @@ func (s *Sender) getBlockNumberAndBaseFeeAndBlobFee(ctx context.Context) (uint64
var blobBaseFee uint64 var blobBaseFee uint64
if excess := header.ExcessBlobGas; excess != nil { if excess := header.ExcessBlobGas; excess != nil {
blobBaseFee = misc.CalcBlobFee(*excess).Uint64() // Leave it up to the L1 node to compute the correct blob base fee.
// Previously we would compute it locally using `CalcBlobFee`, but
// that approach requires syncing any future L1 configuration changes.
// Note: The fetched blob base fee might not correspond to the block
// that we fetched in the previous step, but this is acceptable.
var blobBaseFeeHex hexutil.Big
if err := s.rpcClient.CallContext(ctx, &blobBaseFeeHex, "eth_blobBaseFee"); err != nil {
return 0, 0, 0, 0, fmt.Errorf("failed to call eth_blobBaseFee, err: %w", err)
}
// A correct L1 node could not return a value that overflows uint64
blobBaseFee = blobBaseFeeHex.ToInt().Uint64()
} }
// header.Number.Uint64() returns the pendingBlockNumber, so we minus 1 to get the latestBlockNumber. // header.Number.Uint64() returns the pendingBlockNumber, so we minus 1 to get the latestBlockNumber.
return header.Number.Uint64() - 1, baseFee, blobBaseFee, nil return header.Number.Uint64() - 1, header.Time, baseFee, blobBaseFee, nil
} }
func makeSidecar(blobsInput []*kzg4844.Blob) (*gethTypes.BlobTxSidecar, error) { func makeSidecar(version byte, blobsInput []*kzg4844.Blob) (*gethTypes.BlobTxSidecar, error) {
if len(blobsInput) == 0 { if len(blobsInput) == 0 {
return nil, errors.New("blobsInput is empty") return nil, errors.New("blobsInput is empty")
} }
@@ -742,23 +877,33 @@ func makeSidecar(blobsInput []*kzg4844.Blob) (*gethTypes.BlobTxSidecar, error) {
var proofs []kzg4844.Proof var proofs []kzg4844.Proof
for i := range blobs { for i := range blobs {
// Calculate commitment
c, err := kzg4844.BlobToCommitment(&blobs[i]) c, err := kzg4844.BlobToCommitment(&blobs[i])
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get blob commitment, err: %w", err) return nil, fmt.Errorf("failed to get blob commitment, err: %w", err)
} }
p, err := kzg4844.ComputeBlobProof(&blobs[i], c)
if err != nil {
return nil, fmt.Errorf("failed to compute blob proof, err: %w", err)
}
commitments = append(commitments, c) commitments = append(commitments, c)
proofs = append(proofs, p)
// Calculate proof
switch version {
case gethTypes.BlobSidecarVersion0:
p, err := kzg4844.ComputeBlobProof(&blobs[i], c)
if err != nil {
return nil, fmt.Errorf("failed to compute v0 blob proof, err: %w", err)
}
proofs = append(proofs, p)
case gethTypes.BlobSidecarVersion1:
ps, err := kzg4844.ComputeCellProofs(&blobs[i])
if err != nil {
return nil, fmt.Errorf("failed to compute v1 blob cell proofs, err: %w", err)
}
proofs = append(proofs, ps...)
default:
return nil, fmt.Errorf("unsupported blob sidecar version: %d", version)
}
} }
return &gethTypes.BlobTxSidecar{ return gethTypes.NewBlobTxSidecar(version, blobs, commitments, proofs), nil
Blobs: blobs,
Commitments: commitments,
Proofs: proofs,
}, nil
} }

View File

@@ -21,6 +21,7 @@ import (
gethTypes "github.com/scroll-tech/go-ethereum/core/types" gethTypes "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/crypto/kzg4844" "github.com/scroll-tech/go-ethereum/crypto/kzg4844"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc" "github.com/scroll-tech/go-ethereum/rpc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -94,8 +95,9 @@ func setupEnv(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, migrate.ResetDB(sqlDB)) assert.NoError(t, migrate.ResetDB(sqlDB))
l1Client, err := testApps.GetPoSL1Client() l1RawClient, err := testApps.GetPoSL1Client()
assert.NoError(t, err) assert.NoError(t, err)
l1Client := ethclient.NewClient(l1RawClient)
chainID, err := l1Client.ChainID(context.Background()) chainID, err := l1Client.ChainID(context.Background())
assert.NoError(t, err) assert.NoError(t, err)
@@ -291,7 +293,7 @@ func testAccessListTransactionGasLimit(t *testing.T) {
var sidecar *gethTypes.BlobTxSidecar var sidecar *gethTypes.BlobTxSidecar
if txBlob[i] != nil { if txBlob[i] != nil {
sidecar, err = makeSidecar([]*kzg4844.Blob{txBlob[i]}) sidecar, err = makeSidecar(gethTypes.BlobSidecarVersion0, []*kzg4844.Blob{txBlob[i]})
assert.NoError(t, err) assert.NoError(t, err)
} }
@@ -332,7 +334,7 @@ func testResubmitNonZeroGasPriceTransaction(t *testing.T) {
} }
var sidecar *gethTypes.BlobTxSidecar var sidecar *gethTypes.BlobTxSidecar
if txBlob[i] != nil { if txBlob[i] != nil {
sidecar, err = makeSidecar([]*kzg4844.Blob{txBlob[i]}) sidecar, err = makeSidecar(gethTypes.BlobSidecarVersion0, []*kzg4844.Blob{txBlob[i]})
assert.NoError(t, err) assert.NoError(t, err)
} }
tx, err := s.createTx(feeData, &common.Address{}, nil, sidecar, s.transactionSigner.GetNonce()) tx, err := s.createTx(feeData, &common.Address{}, nil, sidecar, s.transactionSigner.GetNonce())
@@ -467,7 +469,7 @@ func testResubmitBlobTransactionWithRisingBaseFeeAndBlobBaseFee(t *testing.T) {
}) })
defer patchGuard.Reset() defer patchGuard.Reset()
sidecar, err := makeSidecar(randBlobs(1)) sidecar, err := makeSidecar(gethTypes.BlobSidecarVersion0, randBlobs(1))
assert.NoError(t, err) assert.NoError(t, err)
tx := gethTypes.NewTx(&gethTypes.BlobTx{ tx := gethTypes.NewTx(&gethTypes.BlobTx{
ChainID: uint256.MustFromBig(s.chainID), ChainID: uint256.MustFromBig(s.chainID),
@@ -799,7 +801,7 @@ func testBlobTransactionWithBlobhashOpContractCall(t *testing.T) {
assert.NoError(t, migrate.ResetDB(sqlDB)) assert.NoError(t, migrate.ResetDB(sqlDB))
blobs := randBlobs(1) blobs := randBlobs(1)
sideCar, err := makeSidecar(blobs) sideCar, err := makeSidecar(gethTypes.BlobSidecarVersion0, blobs)
assert.NoError(t, err) assert.NoError(t, err)
versionedHash := sideCar.BlobHashes()[0] versionedHash := sideCar.BlobHashes()[0]
blsModulo, ok := new(big.Int).SetString("52435875175126190479447740508185965837690552500527637822603658699938581184513", 10) blsModulo, ok := new(big.Int).SetString("52435875175126190479447740508185965837690552500527637822603658699938581184513", 10)

View File

@@ -245,11 +245,13 @@ func (p *ChunkProposer) ProposeChunk() error {
// Ensure all blocks in the same chunk use the same hardfork name // Ensure all blocks in the same chunk use the same hardfork name
// If a different hardfork name is found, truncate the blocks slice at that point // If a different hardfork name is found, truncate the blocks slice at that point
hardforkName := encoding.GetHardforkName(p.chainCfg, blocks[0].Header.Number.Uint64(), blocks[0].Header.Time) hardforkName := encoding.GetHardforkName(p.chainCfg, blocks[0].Header.Number.Uint64(), blocks[0].Header.Time)
hardforkBoundary := false
for i := 1; i < len(blocks); i++ { for i := 1; i < len(blocks); i++ {
currentHardfork := encoding.GetHardforkName(p.chainCfg, blocks[i].Header.Number.Uint64(), blocks[i].Header.Time) currentHardfork := encoding.GetHardforkName(p.chainCfg, blocks[i].Header.Number.Uint64(), blocks[i].Header.Time)
if currentHardfork != hardforkName { if currentHardfork != hardforkName {
blocks = blocks[:i]
// Truncate blocks at hardfork boundary // Truncate blocks at hardfork boundary
blocks = blocks[:i]
hardforkBoundary = true
break break
} }
} }
@@ -321,6 +323,19 @@ func (p *ChunkProposer) ProposeChunk() error {
return fmt.Errorf("failed to calculate chunk metrics: %w", calcErr) return fmt.Errorf("failed to calculate chunk metrics: %w", calcErr)
} }
// No breaking condition met, but hardfork boundary reached
if hardforkBoundary {
log.Info("hardfork boundary reached, proposing chunk",
"block count", len(chunk.Blocks),
"codec version", codecVersion,
"start block number", chunk.Blocks[0].Header.Number,
"end block number", chunk.Blocks[len(chunk.Blocks)-1].Header.Number)
p.recordAllChunkMetrics(metrics)
return p.updateDBChunkInfo(&chunk, codecVersion, metrics)
}
// No breaking condition met, check for timeout
currentTimeSec := uint64(time.Now().Unix()) currentTimeSec := uint64(time.Now().Unix())
if metrics.FirstBlockTimestamp+p.cfg.ChunkTimeoutSec < currentTimeSec { if metrics.FirstBlockTimestamp+p.cfg.ChunkTimeoutSec < currentTimeSec {
log.Info("first block timeout reached", log.Info("first block timeout reached",

View File

@@ -19,6 +19,8 @@ import (
"scroll-tech/rollup/internal/utils" "scroll-tech/rollup/internal/utils"
) )
func newUint64(val uint64) *uint64 { return &val }
func testChunkProposerLimitsCodecV7(t *testing.T) { func testChunkProposerLimitsCodecV7(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
@@ -26,6 +28,7 @@ func testChunkProposerLimitsCodecV7(t *testing.T) {
chunkTimeoutSec uint64 chunkTimeoutSec uint64
expectedChunksLen int expectedChunksLen int
expectedBlocksInFirstChunk int // only be checked when expectedChunksLen > 0 expectedBlocksInFirstChunk int // only be checked when expectedChunksLen > 0
GalileoTime *uint64
}{ }{
{ {
name: "NoLimitReached", name: "NoLimitReached",
@@ -62,6 +65,14 @@ func testChunkProposerLimitsCodecV7(t *testing.T) {
expectedChunksLen: 1, expectedChunksLen: 1,
expectedBlocksInFirstChunk: 1, expectedBlocksInFirstChunk: 1,
}, },
{
name: "SingleBlockByForkBoundary",
maxL2Gas: 20_000_000,
chunkTimeoutSec: 1000000000000,
expectedChunksLen: 1,
expectedBlocksInFirstChunk: 1,
GalileoTime: newUint64(1669364525), // timestamp of `block2`
},
} }
for _, tt := range tests { for _, tt := range tests {
@@ -78,11 +89,26 @@ func testChunkProposerLimitsCodecV7(t *testing.T) {
_, err = chunkOrm.InsertChunk(context.Background(), &encoding.Chunk{Blocks: []*encoding.Block{{Header: &gethTypes.Header{Number: big.NewInt(0)}}}}, encoding.CodecV0, utils.ChunkMetrics{}) _, err = chunkOrm.InsertChunk(context.Background(), &encoding.Chunk{Blocks: []*encoding.Block{{Header: &gethTypes.Header{Number: big.NewInt(0)}}}}, encoding.CodecV0, utils.ChunkMetrics{})
assert.NoError(t, err) assert.NoError(t, err)
// Initialize the chunk proposer.
chainConfig := &params.ChainConfig{
LondonBlock: big.NewInt(0),
BernoulliBlock: big.NewInt(0),
CurieBlock: big.NewInt(0),
DarwinTime: new(uint64),
DarwinV2Time: new(uint64),
EuclidTime: new(uint64),
EuclidV2Time: new(uint64),
FeynmanTime: new(uint64),
GalileoTime: tt.GalileoTime,
}
cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{
MaxL2GasPerChunk: tt.maxL2Gas, MaxL2GasPerChunk: tt.maxL2Gas,
ChunkTimeoutSec: tt.chunkTimeoutSec, ChunkTimeoutSec: tt.chunkTimeoutSec,
MaxUncompressedBatchBytesSize: math.MaxUint64, MaxUncompressedBatchBytesSize: math.MaxUint64,
}, encoding.CodecV7, &params.ChainConfig{LondonBlock: big.NewInt(0), BernoulliBlock: big.NewInt(0), CurieBlock: big.NewInt(0), DarwinTime: new(uint64), DarwinV2Time: new(uint64), EuclidTime: new(uint64), EuclidV2Time: new(uint64)}, db, nil) }, encoding.CodecV7, chainConfig, db, nil)
// Run one round of chunk proposing.
cp.TryProposeChunk() cp.TryProposeChunk()
chunks, err := chunkOrm.GetChunksGEIndex(context.Background(), 1, 0) chunks, err := chunkOrm.GetChunksGEIndex(context.Background(), 1, 0)

View File

@@ -3,13 +3,15 @@ package watcher
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"math/big" "math/big"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/scroll-tech/go-ethereum/consensus/misc" "github.com/scroll-tech/go-ethereum/common/hexutil"
gethTypes "github.com/scroll-tech/go-ethereum/core/types" gethTypes "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc"
"gorm.io/gorm" "gorm.io/gorm"
"scroll-tech/common/types" "scroll-tech/common/types"
@@ -20,7 +22,8 @@ import (
// L1WatcherClient will listen for smart contract events from Eth L1. // L1WatcherClient will listen for smart contract events from Eth L1.
type L1WatcherClient struct { type L1WatcherClient struct {
ctx context.Context ctx context.Context
client *ethclient.Client rpcClient *rpc.Client // Raw RPC client
client *ethclient.Client // Go SDK RPC client
l1BlockOrm *orm.L1Block l1BlockOrm *orm.L1Block
// The height of the block that the watcher has retrieved header rlp // The height of the block that the watcher has retrieved header rlp
@@ -30,7 +33,7 @@ type L1WatcherClient struct {
} }
// NewL1WatcherClient returns a new instance of L1WatcherClient. // NewL1WatcherClient returns a new instance of L1WatcherClient.
func NewL1WatcherClient(ctx context.Context, client *ethclient.Client, startHeight uint64, db *gorm.DB, reg prometheus.Registerer) *L1WatcherClient { func NewL1WatcherClient(ctx context.Context, rpcClient *rpc.Client, startHeight uint64, db *gorm.DB, reg prometheus.Registerer) *L1WatcherClient {
l1BlockOrm := orm.NewL1Block(db) l1BlockOrm := orm.NewL1Block(db)
savedL1BlockHeight, err := l1BlockOrm.GetLatestL1BlockHeight(ctx) savedL1BlockHeight, err := l1BlockOrm.GetLatestL1BlockHeight(ctx)
if err != nil { if err != nil {
@@ -43,7 +46,8 @@ func NewL1WatcherClient(ctx context.Context, client *ethclient.Client, startHeig
return &L1WatcherClient{ return &L1WatcherClient{
ctx: ctx, ctx: ctx,
client: client, rpcClient: rpcClient,
client: ethclient.NewClient(rpcClient),
l1BlockOrm: l1BlockOrm, l1BlockOrm: l1BlockOrm,
processedBlockHeight: savedL1BlockHeight, processedBlockHeight: savedL1BlockHeight,
@@ -80,7 +84,17 @@ func (w *L1WatcherClient) FetchBlockHeader(blockHeight uint64) error {
var blobBaseFee uint64 var blobBaseFee uint64
if excess := block.ExcessBlobGas; excess != nil { if excess := block.ExcessBlobGas; excess != nil {
blobBaseFee = misc.CalcBlobFee(*excess).Uint64() // Leave it up to the L1 node to compute the correct blob base fee.
// Previously we would compute it locally using `CalcBlobFee`, but
// that approach requires syncing any future L1 configuration changes.
// Note: The fetched blob base fee might not correspond to the block
// that we fetched in the previous step, but this is acceptable.
var blobBaseFeeHex hexutil.Big
if err := w.rpcClient.CallContext(w.ctx, &blobBaseFeeHex, "eth_blobBaseFee"); err != nil {
return fmt.Errorf("failed to call eth_blobBaseFee, err: %w", err)
}
// A correct L1 node could not return a value that overflows uint64
blobBaseFee = blobBaseFeeHex.ToInt().Uint64()
} }
l1Block := orm.L1Block{ l1Block := orm.L1Block{

View File

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

View File

@@ -8,6 +8,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/da-codec/encoding"
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/event" "github.com/scroll-tech/go-ethereum/event"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
@@ -24,6 +25,7 @@ type L2WatcherClient struct {
event.Feed event.Feed
*ethclient.Client *ethclient.Client
rpcCli *rpc.Client
l2BlockOrm *orm.L2Block l2BlockOrm *orm.L2Block
@@ -32,16 +34,19 @@ type L2WatcherClient struct {
messageQueueAddress common.Address messageQueueAddress common.Address
withdrawTrieRootSlot common.Hash withdrawTrieRootSlot common.Hash
validiumMode bool
metrics *l2WatcherMetrics metrics *l2WatcherMetrics
chainCfg *params.ChainConfig chainCfg *params.ChainConfig
} }
// NewL2WatcherClient take a l2geth instance to generate a l2watcherclient instance // NewL2WatcherClient take a l2geth instance to generate a l2watcherclient instance
func NewL2WatcherClient(ctx context.Context, client *ethclient.Client, confirmations rpc.BlockNumber, messageQueueAddress common.Address, withdrawTrieRootSlot common.Hash, chainCfg *params.ChainConfig, db *gorm.DB, reg prometheus.Registerer) *L2WatcherClient { func NewL2WatcherClient(ctx context.Context, client *rpc.Client, confirmations rpc.BlockNumber, messageQueueAddress common.Address, withdrawTrieRootSlot common.Hash, chainCfg *params.ChainConfig, db *gorm.DB, validiumMode bool, reg prometheus.Registerer) *L2WatcherClient {
return &L2WatcherClient{ return &L2WatcherClient{
ctx: ctx, ctx: ctx,
Client: client, Client: ethclient.NewClient(client),
rpcCli: client,
l2BlockOrm: orm.NewL2Block(db), l2BlockOrm: orm.NewL2Block(db),
@@ -50,6 +55,8 @@ func NewL2WatcherClient(ctx context.Context, client *ethclient.Client, confirmat
messageQueueAddress: messageQueueAddress, messageQueueAddress: messageQueueAddress,
withdrawTrieRootSlot: withdrawTrieRootSlot, withdrawTrieRootSlot: withdrawTrieRootSlot,
validiumMode: validiumMode,
metrics: initL2WatcherMetrics(reg), metrics: initL2WatcherMetrics(reg),
chainCfg: chainCfg, chainCfg: chainCfg,
@@ -95,21 +102,51 @@ func (w *L2WatcherClient) GetAndStoreBlocks(ctx context.Context, from, to uint64
return fmt.Errorf("failed to BlockByNumber: %v. number: %v", err, number) return fmt.Errorf("failed to BlockByNumber: %v. number: %v", err, number)
} }
blockTxs := block.Transactions()
var count int var count int
for _, tx := range block.Transactions() { for _, tx := range blockTxs {
if tx.IsL1MessageTx() { if tx.IsL1MessageTx() {
count++ count++
} }
} }
log.Info("retrieved block", "height", block.Header().Number, "hash", block.Header().Hash().String(), "L1 message count", count) log.Info("retrieved block", "height", block.Header().Number, "hash", block.Header().Hash().String(), "L1 message count", count)
// use original (encrypted) L1 message txs in validium mode
if w.validiumMode {
var txs []*types.Transaction
if count > 0 {
log.Info("Fetching encrypted messages in validium mode")
err = w.rpcCli.CallContext(ctx, &txs, "scroll_getL1MessagesInBlock", block.Hash(), "synced")
if err != nil {
return fmt.Errorf("failed to get L1 messages: %v, block hash: %v", err, block.Hash().Hex())
}
}
// sanity check
if len(txs) != count {
return fmt.Errorf("L1 message count mismatch: expected %d, got %d", count, len(txs))
}
for ii := 0; ii < count; ii++ {
// sanity check
if blockTxs[ii].AsL1MessageTx().QueueIndex != txs[ii].AsL1MessageTx().QueueIndex {
return fmt.Errorf("L1 message queue index mismatch at index %d: expected %d, got %d", ii, blockTxs[ii].AsL1MessageTx().QueueIndex, txs[ii].AsL1MessageTx().QueueIndex)
}
log.Info("Replacing L1 message tx in validium mode", "index", ii, "queueIndex", txs[ii].AsL1MessageTx().QueueIndex, "decryptedTxHash", blockTxs[ii].Hash().Hex(), "originalTxHash", txs[ii].Hash().Hex())
blockTxs[ii] = txs[ii]
}
}
withdrawRoot, err3 := w.StorageAt(ctx, w.messageQueueAddress, w.withdrawTrieRootSlot, big.NewInt(int64(number))) withdrawRoot, err3 := w.StorageAt(ctx, w.messageQueueAddress, w.withdrawTrieRootSlot, big.NewInt(int64(number)))
if err3 != nil { if err3 != nil {
return fmt.Errorf("failed to get withdrawRoot: %v. number: %v", err3, number) return fmt.Errorf("failed to get withdrawRoot: %v. number: %v", err3, number)
} }
blocks = append(blocks, &encoding.Block{ blocks = append(blocks, &encoding.Block{
Header: block.Header(), Header: block.Header(),
Transactions: encoding.TxsToTxsData(block.Transactions()), Transactions: encoding.TxsToTxsData(blockTxs),
WithdrawRoot: common.BytesToHash(withdrawRoot), WithdrawRoot: common.BytesToHash(withdrawRoot),
}) })
} }

View File

@@ -2,12 +2,13 @@ package watcher
import ( import (
"context" "context"
"os"
"testing" "testing"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/rpc" "github.com/scroll-tech/go-ethereum/rpc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -20,7 +21,7 @@ import (
func setupL2Watcher(t *testing.T) (*L2WatcherClient, *gorm.DB) { func setupL2Watcher(t *testing.T) (*L2WatcherClient, *gorm.DB) {
db := setupDB(t) db := setupDB(t)
l2cfg := cfg.L2Config l2cfg := cfg.L2Config
watcher := NewL2WatcherClient(context.Background(), l2Cli, l2cfg.Confirmations, l2cfg.L2MessageQueueAddress, l2cfg.WithdrawTrieRootSlot, nil, db, nil) watcher := NewL2WatcherClient(context.Background(), l2Rpc, l2cfg.Confirmations, l2cfg.L2MessageQueueAddress, l2cfg.WithdrawTrieRootSlot, nil, db, false, nil)
return watcher, db return watcher, db
} }
@@ -34,7 +35,7 @@ func testFetchRunningMissingBlocks(t *testing.T) {
if err != nil { if err != nil {
return false return false
} }
wc := prepareWatcherClient(l2Cli, db) wc := prepareWatcherClient(l2Rpc, db)
wc.TryFetchRunningMissingBlocks(latestHeight) wc.TryFetchRunningMissingBlocks(latestHeight)
fetchedHeight, err := l2BlockOrm.GetL2BlocksLatestHeight(context.Background()) fetchedHeight, err := l2BlockOrm.GetL2BlocksLatestHeight(context.Background())
return err == nil && fetchedHeight == latestHeight return err == nil && fetchedHeight == latestHeight
@@ -42,7 +43,32 @@ func testFetchRunningMissingBlocks(t *testing.T) {
assert.True(t, ok) assert.True(t, ok)
} }
func prepareWatcherClient(l2Cli *ethclient.Client, db *gorm.DB) *L2WatcherClient { func prepareWatcherClient(l2Cli *rpc.Client, db *gorm.DB) *L2WatcherClient {
confirmations := rpc.LatestBlockNumber confirmations := rpc.LatestBlockNumber
return NewL2WatcherClient(context.Background(), l2Cli, confirmations, common.Address{}, common.Hash{}, nil, db, nil) return NewL2WatcherClient(context.Background(), l2Cli, confirmations, common.Address{}, common.Hash{}, nil, db, false, nil)
}
// New test for raw RPC GetBlockByHash from an endpoint URL in env.
func TestRawRPCGetBlockByHash(t *testing.T) {
url := os.Getenv("RPC_ENDPOINT_URL")
if url == "" {
t.Log("warn: RPC_ENDPOINT_URL not set, skipping raw RPC test")
t.Skip("missing RPC_ENDPOINT_URL")
}
ctx := context.Background()
cli, err := rpc.DialContext(ctx, url)
if err != nil {
t.Fatalf("failed to dial RPC endpoint %s: %v", url, err)
}
defer cli.Close()
var txs []*types.Transaction
blkHash := common.HexToHash("0xc80cf12883341827d71c08f734ba9a9d6da7e59eb16921d26e6706887e552c74")
err = cli.CallContext(ctx, &txs, "scroll_getL1MessagesInBlock", blkHash, "synced")
if err != nil {
t.Logf("scroll_getL1MessagesInBlock failed: err=%v", err)
t.Fail()
}
t.Log(txs, txs[0].Hash())
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/da-codec/encoding"
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gorm.io/gorm" "gorm.io/gorm"
@@ -27,6 +28,7 @@ var (
// l2geth client // l2geth client
l2Cli *ethclient.Client l2Cli *ethclient.Client
l2Rpc *rpc.Client
// block trace // block trace
block1 *encoding.Block block1 *encoding.Block
@@ -62,8 +64,9 @@ func setupEnv(t *testing.T) (err error) {
} }
// Create l2geth client. // Create l2geth client.
l2Cli, err = testApps.GetL2GethClient() l2Rpc, err = testApps.GetL2Client()
assert.NoError(t, err) assert.NoError(t, err)
l2Cli = ethclient.NewClient(l2Rpc)
block1 = readBlockFromJSON(t, "../../../testdata/blockTrace_02.json") block1 = readBlockFromJSON(t, "../../../testdata/blockTrace_02.json")
block2 = readBlockFromJSON(t, "../../../testdata/blockTrace_03.json") block2 = readBlockFromJSON(t, "../../../testdata/blockTrace_03.json")

View File

@@ -8,6 +8,7 @@ import (
"github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/da-codec/encoding"
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/log"
) )
// ChunkMetrics indicates the metrics for proposing a chunk. // ChunkMetrics indicates the metrics for proposing a chunk.
@@ -138,6 +139,26 @@ func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVer
// TODO: This is a temporary solution, we might use a larger commitment in the future // TODO: This is a temporary solution, we might use a larger commitment in the future
lastBlock := b.Blocks[len(b.Blocks)-1] lastBlock := b.Blocks[len(b.Blocks)-1]
commitment := lastBlock.Header.Hash() commitment := lastBlock.Header.Hash()
stateRoot := b.StateRoot()
// Temporary workaround for the wrong genesis state root configuration issue.
if lastBlock.Header.Number.Uint64() == 0 {
if commitment == common.HexToHash("0x76a8e1359fe1a51ec3917ca98dec95ba005f1a73bcdbc2c7f87c7683e828fbb1") && stateRoot == common.HexToHash("0x08d535cc60f40af5dd3b31e0998d7567c2d568b224bed2ba26070aeb078d1339") {
// cloak-xen/sepolia
stateRoot = common.HexToHash("0x0711f02d6f85b0597c4705298e01ee27159fdd8bd8bdeda670ae8b9073091246")
} else if commitment == common.HexToHash("0x8005a02271085eaded2565f3e252013cd9d3cd0a4775d89f9ba4224289671276") && stateRoot == common.HexToHash("0x08d535cc60f40af5dd3b31e0998d7567c2d568b224bed2ba26070aeb078d1339") {
// cloak-xen/mainnet
stateRoot = common.HexToHash("0x8da1aaf41660ddf7870ab5ff4f6a3ab4b2e652568d341ede87ada56aad5fb097")
} else if commitment == common.HexToHash("0xa7e50dfc812039410c2009c74cdcb0c0797aa5485dec062985eaa43b17d333ea") && stateRoot == common.HexToHash("0x08d535cc60f40af5dd3b31e0998d7567c2d568b224bed2ba26070aeb078d1339") {
// cloak-etherfi/sepolia
stateRoot = common.HexToHash("0x7b44ea23770dda8810801779eb6847d56be0399e35de7c56465ccf8b7578ddf6")
} else if commitment == common.HexToHash("0xeccf4fab24f8b5dd3b72667c6bf5e28b17ccffdea01e3e5c08f393edaa9e7657") && stateRoot == common.HexToHash("0x08d535cc60f40af5dd3b31e0998d7567c2d568b224bed2ba26070aeb078d1339") {
// cloak-shiga/sepolia
stateRoot = common.HexToHash("0x05973227854ac82c22f164ed3d4510b7df516a0eecdfd9bed5f2446efc9994b9")
}
log.Warn("Using genesis state root", "stateRoot", stateRoot.Hex())
}
// Batch header field sizes // Batch header field sizes
const ( const (
@@ -164,10 +185,22 @@ func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVer
commitmentOffset = withdrawRootOffset + withdrawRootSize commitmentOffset = withdrawRootOffset + withdrawRootSize
) )
batchBytes[versionOffset] = uint8(codecVersion) // version var version uint8
if codecVersion == encoding.CodecV8 || codecVersion == encoding.CodecV9 || codecVersion == encoding.CodecV10 {
// Validium version line starts with v1,
// but rollup-relayer behavior follows v8.
version = 1
} else if codecVersion == encoding.CodecV0 {
// Special case for genesis batch
version = 0
} else {
return nil, common.Hash{}, fmt.Errorf("unexpected codec version %d for batch %v in validium mode", codecVersion, b.Index)
}
batchBytes[versionOffset] = version // version
binary.BigEndian.PutUint64(batchBytes[indexOffset:indexOffset+indexSize], b.Index) // batch index binary.BigEndian.PutUint64(batchBytes[indexOffset:indexOffset+indexSize], b.Index) // batch index
copy(batchBytes[parentHashOffset:parentHashOffset+parentHashSize], b.ParentBatchHash[0:parentHashSize]) // parentBatchHash copy(batchBytes[parentHashOffset:parentHashOffset+parentHashSize], b.ParentBatchHash[0:parentHashSize]) // parentBatchHash
copy(batchBytes[stateRootOffset:stateRootOffset+stateRootSize], b.StateRoot().Bytes()[0:stateRootSize]) // postStateRoot copy(batchBytes[stateRootOffset:stateRootOffset+stateRootSize], stateRoot.Bytes()[0:stateRootSize]) // postStateRoot
copy(batchBytes[withdrawRootOffset:withdrawRootOffset+withdrawRootSize], b.WithdrawRoot().Bytes()[0:withdrawRootSize]) // postWithdrawRoot copy(batchBytes[withdrawRootOffset:withdrawRootOffset+withdrawRootSize], b.WithdrawRoot().Bytes()[0:withdrawRootSize]) // postWithdrawRoot
copy(batchBytes[commitmentOffset:commitmentOffset+commitmentSize], commitment[0:commitmentSize]) // data commitment copy(batchBytes[commitmentOffset:commitmentOffset+commitmentSize], commitment[0:commitmentSize]) // data commitment

View File

@@ -19,6 +19,7 @@ import (
"github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gorm.io/gorm" "gorm.io/gorm"
@@ -37,8 +38,9 @@ var (
rollupApp *bcmd.MockApp rollupApp *bcmd.MockApp
// clients // clients
l1Client *ethclient.Client l1RawClient *rpc.Client
l2Client *ethclient.Client l1Client *ethclient.Client
l2Client *ethclient.Client
l1Auth *bind.TransactOpts l1Auth *bind.TransactOpts
l2Auth *bind.TransactOpts l2Auth *bind.TransactOpts
@@ -91,8 +93,9 @@ func setupEnv(t *testing.T) {
assert.NoError(t, testApps.StartPoSL1Container()) assert.NoError(t, testApps.StartPoSL1Container())
rollupApp = bcmd.NewRollupApp(testApps, "../conf/config.json") rollupApp = bcmd.NewRollupApp(testApps, "../conf/config.json")
l1Client, err = testApps.GetPoSL1Client() l1RawClient, err = testApps.GetPoSL1Client()
assert.NoError(t, err) assert.NoError(t, err)
l1Client = ethclient.NewClient(l1RawClient)
l2Client, err = testApps.GetL2GethClient() l2Client, err = testApps.GetL2GethClient()
assert.NoError(t, err) assert.NoError(t, err)
l1GethChainID, err = l1Client.ChainID(context.Background()) l1GethChainID, err = l1Client.ChainID(context.Background())

View File

@@ -36,7 +36,7 @@ func testImportL1GasPrice(t *testing.T) {
// Create L1Watcher // Create L1Watcher
startHeight, err := l1Client.BlockNumber(context.Background()) startHeight, err := l1Client.BlockNumber(context.Background())
assert.NoError(t, err) assert.NoError(t, err)
l1Watcher := watcher.NewL1WatcherClient(context.Background(), l1Client, startHeight-1, db, nil) l1Watcher := watcher.NewL1WatcherClient(context.Background(), l1RawClient, startHeight-1, db, nil)
// fetch new blocks // fetch new blocks
number, err := l1Client.BlockNumber(context.Background()) number, err := l1Client.BlockNumber(context.Background())
@@ -110,7 +110,7 @@ func testImportDefaultL1GasPriceDueToL1GasPriceSpike(t *testing.T) {
// Create L1Watcher // Create L1Watcher
startHeight, err := l1Client.BlockNumber(context.Background()) startHeight, err := l1Client.BlockNumber(context.Background())
assert.NoError(t, err) assert.NoError(t, err)
l1Watcher := watcher.NewL1WatcherClient(context.Background(), l1Client, startHeight-2, db, nil) l1Watcher := watcher.NewL1WatcherClient(context.Background(), l1RawClient, startHeight-2, db, nil)
// fetch new blocks // fetch new blocks
number, err := l1Client.BlockNumber(context.Background()) number, err := l1Client.BlockNumber(context.Background())

View File

@@ -0,0 +1,84 @@
package main
import (
"context"
"fmt"
"math/big"
"github.com/scroll-tech/da-codec/encoding"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc"
)
func fetchAndStoreBlocks(ctx context.Context, from, to uint64) ([]*encoding.Block, error) {
validiumMode := cfg.ValidiumMode
cfg := cfg.FetchConfig
client, err := rpc.Dial(cfg.Endpoint)
if err != nil {
return nil, fmt.Errorf("failed to connect l2 geth, endpoint %s, err %v", cfg.Endpoint, err)
}
defer client.Close()
ethCli := ethclient.NewClient(client)
var blocks []*encoding.Block
for number := from; number <= to; number++ {
log.Debug("retrieving block", "height", number)
block, err := ethCli.BlockByNumber(ctx, new(big.Int).SetUint64(number))
if err != nil {
return nil, fmt.Errorf("failed to BlockByNumber: %v. number: %v", err, number)
}
blockTxs := block.Transactions()
var count int
for _, tx := range blockTxs {
if tx.IsL1MessageTx() {
count++
}
}
log.Info("retrieved block", "height", block.Header().Number, "hash", block.Header().Hash().String(), "L1 message count", count)
// use original (encrypted) L1 message txs in validium mode
if validiumMode {
var txs []*types.Transaction
if count > 0 {
log.Info("Fetching encrypted messages in validium mode")
err = client.CallContext(ctx, &txs, "scroll_getL1MessagesInBlock", block.Hash(), "synced")
if err != nil {
return nil, fmt.Errorf("failed to get L1 messages: %v, block hash: %v", err, block.Hash().Hex())
}
}
// sanity check
if len(txs) != count {
return nil, fmt.Errorf("L1 message count mismatch: expected %d, got %d", count, len(txs))
}
for ii := 0; ii < count; ii++ {
// sanity check
if blockTxs[ii].AsL1MessageTx().QueueIndex != txs[ii].AsL1MessageTx().QueueIndex {
return nil, fmt.Errorf("L1 message queue index mismatch at index %d: expected %d, got %d", ii, blockTxs[ii].AsL1MessageTx().QueueIndex, txs[ii].AsL1MessageTx().QueueIndex)
}
log.Info("Replacing L1 message tx in validium mode", "index", ii, "queueIndex", txs[ii].AsL1MessageTx().QueueIndex, "decryptedTxHash", blockTxs[ii].Hash().Hex(), "originalTxHash", txs[ii].Hash().Hex())
blockTxs[ii] = txs[ii]
}
}
withdrawRoot, err3 := ethCli.StorageAt(ctx, cfg.L2MessageQueueAddress, cfg.WithdrawTrieRootSlot, big.NewInt(int64(number)))
if err3 != nil {
return nil, fmt.Errorf("failed to get withdrawRoot: %v. number: %v", err3, number)
}
blocks = append(blocks, &encoding.Block{
Header: block.Header(),
Transactions: encoding.TxsToTxsData(blockTxs),
WithdrawRoot: common.BytesToHash(withdrawRoot),
})
}
return blocks, nil
}

View File

@@ -10,9 +10,11 @@ import (
"github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/da-codec/encoding"
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"scroll-tech/common/database" "scroll-tech/common/database"
ctypes "scroll-tech/common/types"
"scroll-tech/rollup/internal/orm" "scroll-tech/rollup/internal/orm"
"scroll-tech/rollup/internal/utils" "scroll-tech/rollup/internal/utils"
@@ -40,12 +42,21 @@ func randomPickKfromN(n, k int, rng *rand.Rand) []int {
return ret return ret
} }
func importData(ctx context.Context, beginBlk, endBlk uint64, chkNum, batchNum, bundleNum int, seed int64) (*importRecord, error) { func importData(ctx context.Context, beginBlk, endBlk uint64, blocks []*encoding.Block, chkNum, batchNum, bundleNum int, seed int64) (*importRecord, error) {
db, err := database.InitDB(cfg.DBConfig) db, err := database.InitDB(cfg.DBConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(blocks) > 0 {
log.Info("import block")
blockOrm := orm.NewL2Block(db)
if err := blockOrm.InsertL2Blocks(ctx, blocks); err != nil {
return nil, err
}
}
ret := &importRecord{} ret := &importRecord{}
// Create a new random source with the provided seed // Create a new random source with the provided seed
source := rand.NewSource(seed) source := rand.NewSource(seed)
@@ -62,6 +73,9 @@ func importData(ctx context.Context, beginBlk, endBlk uint64, chkNum, batchNum,
log.Info("separated chunk", "border", chkSep) log.Info("separated chunk", "border", chkSep)
head := beginBlk head := beginBlk
lastMsgHash := common.Hash{} lastMsgHash := common.Hash{}
if err := initLeadingChunk(ctx, db, beginBlk, endBlk, lastMsgHash); err != nil {
return nil, err
}
ormChks := make([]*orm.Chunk, 0, chkNum) ormChks := make([]*orm.Chunk, 0, chkNum)
encChks := make([]*encoding.Chunk, 0, chkNum) encChks := make([]*encoding.Chunk, 0, chkNum)
@@ -118,6 +132,73 @@ func importData(ctx context.Context, beginBlk, endBlk uint64, chkNum, batchNum,
return ret, nil return ret, nil
} }
func initLeadingChunk(ctx context.Context, db *gorm.DB, beginBlk, endBlk uint64, prevMsgQueueHash common.Hash) error {
blockOrm := orm.NewL2Block(db)
if beginBlk <= 1 {
log.Info("start from genesis, no need to insert leading chunk")
return nil
}
var l1MsgPoppedBefore uint64
blks, err := blockOrm.GetL2BlocksGEHeight(ctx, beginBlk, int(endBlk-beginBlk+1))
if err != nil {
return err
}
for i, block := range blks {
for _, tx := range block.Transactions {
if tx.Type == types.L1MessageTxType {
l1MsgPoppedBefore = tx.Nonce
log.Info("search first l1 nonce", "index", l1MsgPoppedBefore, "blk", beginBlk+uint64(i))
break
}
}
if l1MsgPoppedBefore != 0 {
break
}
}
if l1MsgPoppedBefore == 0 {
log.Info("no l1 message in target blks, no need for leading chunk")
return nil
}
prevBlks, err := blockOrm.GetL2BlocksGEHeight(ctx, beginBlk-1, 1)
if err != nil {
log.Error("get prev block fail, we also need at least 1 block before selected range", "need block", beginBlk-1, "err", err)
return err
}
// we use InsertTestChunkForProposerTool to insert leading chunk, which do not calculate l1 message
// so we simply exclude l1 in this hacked chunk
prevBlk := prevBlks[0]
var trimLen int
for _, tx := range prevBlk.Transactions {
if tx.Type != types.L1MessageTxType {
prevBlk.Transactions[trimLen] = tx
trimLen++
}
}
prevBlk.Transactions = prevBlk.Transactions[:trimLen]
postHash, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(prevMsgQueueHash, prevBlks)
if err != nil {
return err
}
chunkOrm := orm.NewChunk(db)
log.Info("Insert leading chunk with prev block", "msgPoppedBefore", l1MsgPoppedBefore)
leadingChunk, err := chunkOrm.InsertTestChunkForProposerTool(ctx, &encoding.Chunk{
Blocks: prevBlks,
PrevL1MessageQueueHash: prevMsgQueueHash,
PostL1MessageQueueHash: postHash,
}, codecCfg, l1MsgPoppedBefore)
if err != nil {
return err
}
return chunkOrm.UpdateProvingStatus(ctx, leadingChunk.Hash, ctypes.ProvingTaskProvedDEPRECATED)
}
func importChunk(ctx context.Context, db *gorm.DB, beginBlk, endBlk uint64, prevMsgQueueHash common.Hash) (*orm.Chunk, *encoding.Chunk, error) { func importChunk(ctx context.Context, db *gorm.DB, beginBlk, endBlk uint64, prevMsgQueueHash common.Hash) (*orm.Chunk, *encoding.Chunk, error) {
nblk := int(endBlk-beginBlk) + 1 nblk := int(endBlk-beginBlk) + 1
blockOrm := orm.NewL2Block(db) blockOrm := orm.NewL2Block(db)
@@ -183,9 +264,13 @@ func importBatch(ctx context.Context, db *gorm.DB, chks []*orm.Chunk, encChks []
ParentBatchHash: parentHash, ParentBatchHash: parentHash,
Chunks: encChks, Chunks: encChks,
Blocks: blks, Blocks: blks,
PrevL1MessageQueueHash: encChks[0].PrevL1MessageQueueHash,
PostL1MessageQueueHash: encChks[len(encChks)-1].PostL1MessageQueueHash,
} }
dbBatch, err := batchOrm.InsertBatch(ctx, batch, codecCfg, utils.BatchMetrics{}) dbBatch, err := batchOrm.InsertBatch(ctx, batch, codecCfg, utils.BatchMetrics{
ValidiumMode: cfg.ValidiumMode,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -10,6 +10,7 @@ import (
"strings" "strings"
"github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/da-codec/encoding"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@@ -20,7 +21,7 @@ import (
var app *cli.App var app *cli.App
var cfg *config var cfg *config
var codecCfg encoding.CodecVersion = encoding.CodecV8 var codecCfg encoding.CodecVersion = encoding.CodecV9
var outputNumFlag = cli.StringFlag{ var outputNumFlag = cli.StringFlag{
Name: "counts", Name: "counts",
@@ -40,12 +41,6 @@ var seedFlag = cli.Int64Flag{
Value: 0, Value: 0,
} }
var codecFlag = cli.IntFlag{
Name: "codec",
Usage: "codec version, valid from 6, default(auto) is 0",
Value: 0,
}
func parseThreeIntegers(value string) (int, int, int, error) { func parseThreeIntegers(value string) (int, int, int, error) {
// Split the input string by comma // Split the input string by comma
parts := strings.Split(value, ",") parts := strings.Split(value, ",")
@@ -84,9 +79,21 @@ func parseThreeIntegers(value string) (int, int, int, error) {
return values[0], values[1], values[2], nil return values[0], values[1], values[2], nil
} }
type fetchConfig struct {
// node url.
Endpoint string `json:"endpoint"`
// The L2MessageQueue contract address deployed on layer 2 chain.
L2MessageQueueAddress common.Address `json:"l2_message_queue_address"`
// The WithdrawTrieRootSlot in L2MessageQueue contract.
WithdrawTrieRootSlot common.Hash `json:"withdraw_trie_root_slot,omitempty"`
}
// load a comptabile type of config for rollup // load a comptabile type of config for rollup
type config struct { type config struct {
DBConfig *database.Config `json:"db_config"` DBConfig *database.Config `json:"db_config"`
FetchConfig *fetchConfig `json:"fetch_config,omitempty"`
ValidiumMode bool `json:"validium_mode"`
CodecVersion int `json:"codec_version"`
} }
func init() { func init() {
@@ -96,7 +103,7 @@ func init() {
app.Name = "integration-test-tool" app.Name = "integration-test-tool"
app.Usage = "The Scroll L2 Integration Test Tool" app.Usage = "The Scroll L2 Integration Test Tool"
app.Version = version.Version app.Version = version.Version
app.Flags = append(app.Flags, &codecFlag, &seedFlag, &outputNumFlag, &outputPathFlag) app.Flags = append(app.Flags, &seedFlag, &outputNumFlag, &outputPathFlag)
app.Flags = append(app.Flags, utils.CommonFlags...) app.Flags = append(app.Flags, utils.CommonFlags...)
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
if err := utils.LogSetup(ctx); err != nil { if err := utils.LogSetup(ctx); err != nil {
@@ -119,13 +126,13 @@ func newConfig(file string) (*config, error) {
return nil, err return nil, err
} }
cfg := &config{} loadCfg := &config{}
err = json.Unmarshal(buf, cfg) err = json.Unmarshal(buf, loadCfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return cfg, nil return loadCfg, nil
} }
func action(ctx *cli.Context) error { func action(ctx *cli.Context) error {
@@ -134,17 +141,20 @@ func action(ctx *cli.Context) error {
return fmt.Errorf("specify begin and end block number") return fmt.Errorf("specify begin and end block number")
} }
codecFl := ctx.Int(codecFlag.Name) if cfg.CodecVersion != 0 {
if codecFl != 0 { switch cfg.CodecVersion {
switch codecFl {
case 6: case 6:
codecCfg = encoding.CodecV6 codecCfg = encoding.CodecV6
case 7: case 7:
codecCfg = encoding.CodecV7 codecCfg = encoding.CodecV7
case 8: case 8:
codecCfg = encoding.CodecV8 codecCfg = encoding.CodecV8
case 9:
codecCfg = encoding.CodecV9
case 10:
codecCfg = encoding.CodecV10
default: default:
return fmt.Errorf("invalid codec version %d", codecFl) return fmt.Errorf("invalid codec version %d", cfg.CodecVersion)
} }
log.Info("set codec", "version", codecCfg) log.Info("set codec", "version", codecCfg)
} }
@@ -158,6 +168,14 @@ func action(ctx *cli.Context) error {
return fmt.Errorf("invalid begin block number: %w", err) return fmt.Errorf("invalid begin block number: %w", err)
} }
var import_blocks []*encoding.Block
if cfg.FetchConfig != nil {
import_blocks, err = fetchAndStoreBlocks(ctx.Context, beginBlk, endBlk)
if err != nil {
return err
}
}
chkNum, batchNum, bundleNum, err := parseThreeIntegers(ctx.String(outputNumFlag.Name)) chkNum, batchNum, bundleNum, err := parseThreeIntegers(ctx.String(outputNumFlag.Name))
if err != nil { if err != nil {
return err return err
@@ -171,7 +189,7 @@ func action(ctx *cli.Context) error {
outputPath := ctx.String(outputPathFlag.Name) outputPath := ctx.String(outputPathFlag.Name)
log.Info("output", "Seed", seed, "file", outputPath) log.Info("output", "Seed", seed, "file", outputPath)
ret, err := importData(ctx.Context, beginBlk, endBlk, chkNum, batchNum, bundleNum, seed) ret, err := importData(ctx.Context, beginBlk, endBlk, import_blocks, chkNum, batchNum, bundleNum, seed)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,3 +1,4 @@
[toolchain] [toolchain]
channel = "nightly-2025-02-14" channel = "nightly-2025-08-18"
targets = ["riscv32im-unknown-none-elf", "x86_64-unknown-linux-gnu"] targets = ["riscv32im-unknown-none-elf", "x86_64-unknown-linux-gnu"]
components = ["llvm-tools", "rustc-dev"]

View File

@@ -5,8 +5,8 @@ go 1.22
toolchain go1.22.2 toolchain go1.22.2
require ( require (
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 github.com/scroll-tech/da-codec v0.10.0
github.com/scroll-tech/go-ethereum v1.10.14-0.20250625112225-a67863c65587 github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde
) )
@@ -16,10 +16,10 @@ require (
github.com/btcsuite/btcd v0.20.1-beta // indirect github.com/btcsuite/btcd v0.20.1-beta // indirect
github.com/consensys/bavard v0.1.29 // indirect github.com/consensys/bavard v0.1.29 // indirect
github.com/consensys/gnark-crypto v0.16.0 // indirect github.com/consensys/gnark-crypto v0.16.0 // indirect
github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
@@ -34,7 +34,7 @@ require (
github.com/rjeczalik/notify v0.9.1 // indirect github.com/rjeczalik/notify v0.9.1 // indirect
github.com/scroll-tech/zktrie v0.8.4 // indirect github.com/scroll-tech/zktrie v0.8.4 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/supranational/blst v0.3.13 // indirect github.com/supranational/blst v0.3.15 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect github.com/tklauser/numcpus v0.9.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect

View File

@@ -22,8 +22,8 @@ github.com/consensys/bavard v0.1.29 h1:fobxIYksIQ+ZSrTJUuQgu+HIJwclrAPcdXqd7H2hh
github.com/consensys/bavard v0.1.29/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= github.com/consensys/bavard v0.1.29/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw4KoTAawo= github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw4KoTAawo=
github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU= github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU=
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -31,8 +31,8 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
github.com/ethereum/c-kzg-4844 v1.0.3/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
@@ -93,18 +93,18 @@ github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeC
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178 h1:4utngmJHXSOS5FoSdZhEV1xMRirpArbXvyoCZY9nYj0= github.com/scroll-tech/da-codec v0.10.0 h1:IPHxyTyXTWPV0Q+DZ08cod2fWkhUvrfysmj/VBpB+WU=
github.com/scroll-tech/da-codec v0.1.3-0.20250826112206-b4cce5c5d178/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= github.com/scroll-tech/da-codec v0.10.0/go.mod h1:MBlIP4wCXPcUDZ/Ci2B7n/2IbVU1WBo9OTFTZ5ffE0U=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250625112225-a67863c65587 h1:wG1+gb+K4iLtxAHhiAreMdIjP5x9hB64duraN2+u1QU= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f h1:j6SjP98MoWFFX9TwB1/nFYEkayqHQsrtE66Ll2C+oT0=
github.com/scroll-tech/go-ethereum v1.10.14-0.20250625112225-a67863c65587/go.mod h1:YyfB2AyAtphlbIuDQgaxc2b9mo0zE4EBA1+qtXvzlmg= github.com/scroll-tech/go-ethereum v1.10.14-0.20251128092113-8629f088d78f/go.mod h1:Aa/kD1XB+OV/7rRxMQrjcPCB4b0pKyLH0gsTrtuHi38=
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o=
github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/supranational/blst v0.3.15/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=

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