mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-12 15:38:18 -05:00
Compare commits
19 Commits
deploy_2_v
...
fix/some-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af5997f871 | ||
|
|
2f1abc06f6 | ||
|
|
cc5fd778c7 | ||
|
|
8587116ff8 | ||
|
|
a75813e6c1 | ||
|
|
01d35d7449 | ||
|
|
59c8470c04 | ||
|
|
5622f8f627 | ||
|
|
5936cd61d6 | ||
|
|
f031c38890 | ||
|
|
9bfefa0474 | ||
|
|
a6c72a2ce2 | ||
|
|
299f5e46fe | ||
|
|
7629f06243 | ||
|
|
5902bee340 | ||
|
|
e79900e24c | ||
|
|
0803dd97fb | ||
|
|
bdbddc38f5 | ||
|
|
f011fd5ac6 |
6
.github/workflows/bridge_history_api.yml
vendored
6
.github/workflows/bridge_history_api.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Lint
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Test
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install goimports
|
||||
|
||||
10
.github/workflows/common.yml
vendored
10
.github/workflows/common.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache cargo
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install goimports
|
||||
@@ -79,15 +79,15 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Solc
|
||||
uses: supplypike/setup-bin@v3
|
||||
with:
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux'
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.16/solc-static-linux'
|
||||
name: 'solc'
|
||||
version: '0.8.24'
|
||||
version: '0.8.16'
|
||||
- name: Install Geth Tools
|
||||
uses: gacts/install-geth-tools@v1
|
||||
- name: Build prerequisites
|
||||
|
||||
30
.github/workflows/contracts.yml
vendored
30
.github/workflows/contracts.yml
vendored
@@ -43,10 +43,10 @@ jobs:
|
||||
- name: Setup LCOV
|
||||
uses: hrishikesh-kadam/setup-lcov@v1
|
||||
|
||||
- name: Install Node.js 18
|
||||
- name: Install Node.js 14
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: '14'
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
@@ -73,24 +73,26 @@ jobs:
|
||||
run: yarn install
|
||||
|
||||
- name: Compile with foundry
|
||||
run: forge build --evm-version cancun
|
||||
run: forge build
|
||||
|
||||
- name: Run foundry tests
|
||||
run: forge test --evm-version cancun -vvv
|
||||
run: forge test -vvv
|
||||
|
||||
- name: Run foundry coverage
|
||||
run : forge coverage --evm-version cancun --report lcov
|
||||
run : forge coverage --report lcov
|
||||
|
||||
- name : Prune coverage
|
||||
run : lcov --rc branch_coverage=1 --remove ./lcov.info -o ./lcov.info.pruned 'src/mocks/*' 'src/test/*' 'scripts/*' 'node_modules/*' 'lib/*'
|
||||
run : lcov --remove ./lcov.info -o ./lcov.info.pruned 'src/mocks/*' 'src/test/*' 'scripts/*' 'node_modules/*' 'lib/*'
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
- name: Report code coverage
|
||||
uses: zgosalvez/github-actions-report-lcov@v3
|
||||
with:
|
||||
files: contracts/lcov.info.pruned
|
||||
flags: contracts
|
||||
coverage-files: contracts/lcov.info.pruned
|
||||
minimum-coverage: 0
|
||||
artifact-name: code-coverage-report
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
working-directory: contracts
|
||||
update-comment: true
|
||||
|
||||
hardhat:
|
||||
if: github.event.pull_request.draft == false
|
||||
@@ -102,10 +104,10 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Node.js 18
|
||||
- name: Install Node.js 14
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: '14'
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
|
||||
10
.github/workflows/coordinator.yml
vendored
10
.github/workflows/coordinator.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Lint
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install goimports
|
||||
@@ -95,15 +95,15 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Solc
|
||||
uses: supplypike/setup-bin@v3
|
||||
with:
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux'
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.16/solc-static-linux'
|
||||
name: 'solc'
|
||||
version: '0.8.24'
|
||||
version: '0.8.16'
|
||||
- name: Install Geth Tools
|
||||
uses: gacts/install-geth-tools@v1
|
||||
- name: Build prerequisites
|
||||
|
||||
10
.github/workflows/database.yml
vendored
10
.github/workflows/database.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Lint
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install goimports
|
||||
@@ -72,15 +72,15 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Solc
|
||||
uses: supplypike/setup-bin@v3
|
||||
with:
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux'
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.16/solc-static-linux'
|
||||
name: 'solc'
|
||||
version: '0.8.24'
|
||||
version: '0.8.16'
|
||||
- name: Install Geth Tools
|
||||
uses: gacts/install-geth-tools@v1
|
||||
- name: Build prerequisites
|
||||
|
||||
419
.github/workflows/docker.yml
vendored
419
.github/workflows/docker.yml
vendored
@@ -5,314 +5,151 @@ on:
|
||||
tags:
|
||||
- v**
|
||||
|
||||
env:
|
||||
AWS_REGION: us-west-2
|
||||
|
||||
jobs:
|
||||
event_watcher:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: event-watcher
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: event-watcher
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/event_watcher.Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push event_watcher docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/event_watcher.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/event-watcher:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
gas_oracle:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: gas-oracle
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: gas-oracle
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/gas_oracle.Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push gas_oracle docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/gas_oracle.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/gas-oracle:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
rollup_relayer:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: rollup-relayer
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: rollup-relayer
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/rollup_relayer.Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
|
||||
bridgehistoryapi-fetcher:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push rollup_relayer docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/rollup_relayer.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/rollup-relayer:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
bridgehistoryapi-cross-msg-fetcher:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: bridgehistoryapi-fetcher
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: bridgehistoryapi-fetcher
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/bridgehistoryapi-fetcher.Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
|
||||
bridgehistoryapi-api:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push bridgehistoryapi-cross-msg-fetcher docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/bridgehistoryapi-cross-msg-fetcher.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/bridgehistoryapi-cross-msg-fetcher:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
bridgehistoryapi-server:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: bridgehistoryapi-api
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: bridgehistoryapi-api
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/bridgehistoryapi-api.Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push bridgehistoryapi-server docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/bridgehistoryapi-server.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/bridgehistoryapi-server:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
coordinator-api:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: coordinator-api
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: coordinator-api
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/coordinator-api.Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push coordinator docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/coordinator-api.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/coordinator-api:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
coordinator-cron:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: coordinator-cron
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: coordinator-cron
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/coordinator-cron.Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push coordinator docker
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/coordinator-cron.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/coordinator-cron:${{github.ref_name}}
|
||||
# cache-from: type=gha,scope=${{ github.workflow }}
|
||||
# cache-to: type=gha,scope=${{ github.workflow }}
|
||||
|
||||
6
.github/workflows/integration.yml
vendored
6
.github/workflows/integration.yml
vendored
@@ -22,15 +22,15 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Solc
|
||||
uses: supplypike/setup-bin@v3
|
||||
with:
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux'
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.16/solc-static-linux'
|
||||
name: 'solc'
|
||||
version: '0.8.24'
|
||||
version: '0.8.16'
|
||||
- name: Install Geth Tools
|
||||
uses: gacts/install-geth-tools@v1
|
||||
- name: Build prerequisites
|
||||
|
||||
2
.github/workflows/intermediate-docker.yml
vendored
2
.github/workflows/intermediate-docker.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
description: 'Go version'
|
||||
required: true
|
||||
type: string
|
||||
default: '1.20'
|
||||
default: '1.19'
|
||||
RUST_VERSION:
|
||||
description: 'Rust toolchain version'
|
||||
required: true
|
||||
|
||||
8
.github/workflows/prover.yml
vendored
8
.github/workflows/prover.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Test
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache cargo
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Lint
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install goimports
|
||||
|
||||
14
.github/workflows/rollup.yml
vendored
14
.github/workflows/rollup.yml
vendored
@@ -34,15 +34,15 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Solc
|
||||
uses: supplypike/setup-bin@v3
|
||||
with:
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux'
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.16/solc-static-linux'
|
||||
name: 'solc'
|
||||
version: '0.8.24'
|
||||
version: '0.8.16'
|
||||
- name: Install Geth Tools
|
||||
uses: gacts/install-geth-tools@v1
|
||||
- name: Lint
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install goimports
|
||||
@@ -83,15 +83,15 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
go-version: 1.19.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Solc
|
||||
uses: supplypike/setup-bin@v3
|
||||
with:
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux'
|
||||
uri: 'https://github.com/ethereum/solidity/releases/download/v0.8.16/solc-static-linux'
|
||||
name: 'solc'
|
||||
version: '0.8.24'
|
||||
version: '0.8.16'
|
||||
- name: Install Geth Tools
|
||||
uses: gacts/install-geth-tools@v1
|
||||
- name: Build prerequisites
|
||||
|
||||
@@ -33,7 +33,7 @@ Examples of unacceptable behavior include:
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct that could reasonably be considered inappropriate in a
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
@@ -22,11 +22,10 @@ We'd also love PRs. If you're thinking of a large PR, we advise opening up an is
|
||||
## Submitting a pull request
|
||||
|
||||
1. [Fork][fork] and clone the repository.
|
||||
2. Create a new branch: `git checkout -b my-branch-name`.
|
||||
3. Make your change, add tests, and make sure the tests still pass.
|
||||
4. Format your code in scroll home directory: `make lint && make fmt`
|
||||
5. Push to your fork and [submit a pull request][pr].
|
||||
6. Pat yourself on the back and wait for your pull request to be reviewed and merged.
|
||||
1. Create a new branch: `git checkout -b my-branch-name`.
|
||||
1. Make your change, add tests, and make sure the tests still pass.
|
||||
1. Push to your fork and [submit a pull request][pr].
|
||||
1. Pat yourself on the back and wait for your pull request to be reviewed and merged.
|
||||
|
||||
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2024 Scroll
|
||||
Copyright (c) 2022-2023 Scroll
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
37
Makefile
37
Makefile
@@ -1,20 +1,11 @@
|
||||
.PHONY: fmt dev_docker build_test_docker run_test_docker clean update
|
||||
.PHONY: check update dev_docker build_test_docker run_test_docker clean
|
||||
|
||||
L2GETH_TAG=scroll-v5.1.6
|
||||
L2GETH_TAG=scroll-v4.3.55
|
||||
|
||||
help: ## Display this help message
|
||||
@grep -h \
|
||||
-E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
update:
|
||||
go work sync
|
||||
cd $(PWD)/bridge-history-api/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/common/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG}&& go mod tidy
|
||||
cd $(PWD)/coordinator/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/database/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/prover/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG}&& go mod tidy
|
||||
cd $(PWD)/rollup/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/tests/integration-test/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
|
||||
lint: ## The code's format and security checks.
|
||||
make -C rollup lint
|
||||
@@ -24,26 +15,26 @@ lint: ## The code's format and security checks.
|
||||
make -C prover lint
|
||||
make -C bridge-history-api lint
|
||||
|
||||
fmt: ## format the code
|
||||
update: ## update dependencies
|
||||
go work sync
|
||||
cd $(PWD)/bridge-history-api/ && go mod tidy
|
||||
cd $(PWD)/common/ && go mod tidy
|
||||
cd $(PWD)/coordinator/ && go mod tidy
|
||||
cd $(PWD)/database/ && go mod tidy
|
||||
cd $(PWD)/prover/ && go mod tidy
|
||||
cd $(PWD)/rollup/ && go mod tidy
|
||||
cd $(PWD)/tests/integration-test/ && go mod tidy
|
||||
|
||||
cd $(PWD)/rollup/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/bridge-history-api/ && go get -u github.com/ethereum/go-ethereum@latest && go mod tidy
|
||||
cd $(PWD)/common/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/coordinator/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/database/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/prover/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/prover-stats-api/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/tests/integration-test/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
goimports -local $(PWD)/rollup/ -w .
|
||||
goimports -local $(PWD)/bridge-history-api/ -w .
|
||||
goimports -local $(PWD)/common/ -w .
|
||||
goimports -local $(PWD)/coordinator/ -w .
|
||||
goimports -local $(PWD)/database/ -w .
|
||||
goimports -local $(PWD)/prover/ -w .
|
||||
goimports -local $(PWD)/rollup/ -w .
|
||||
goimports -local $(PWD)/prover-stats-api/ -w .
|
||||
goimports -local $(PWD)/tests/integration-test/ -w .
|
||||
|
||||
dev_docker: ## build docker images for development/testing usages
|
||||
docker pull postgres
|
||||
docker build -t scroll_l1geth ./common/docker/l1geth/
|
||||
docker build -t scroll_l2geth ./common/docker/l2geth/
|
||||
|
||||
@@ -51,7 +42,7 @@ build_test_docker: ## build Docker image for local testing on M1/M2 Silicon Mac
|
||||
docker build -t scroll_test_image -f ./build/dockerfiles/local_testing.Dockerfile $$(mktemp -d)
|
||||
|
||||
run_test_docker: ## run Docker image for local testing on M1/M2 Silicon Mac
|
||||
docker run -it --rm --name scroll_test_container --network=host -v /var/run/docker.sock:/var/run/docker.sock -v $(PWD):/go/src/app -e HOST_PATH=$(PWD) scroll_test_image
|
||||
docker run -it --rm --name scroll_test_container --network=host -v /var/run/docker.sock:/var/run/docker.sock -v $(PWD):/go/src/app scroll_test_image
|
||||
|
||||
clean: ## Empty out the bin folder
|
||||
@rm -rf build/bin
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
## Directory Structure
|
||||
|
||||
<pre>
|
||||
├── <a href="./bridge-history-api/">bridge-history-api</a>: Bridge history service that collects deposit and withdraw events from both L1 and L2 chains and generates withdrawal proofs
|
||||
├── <a href="./bridge-history-api/">bridge-history-api</a>: Bridge history service that collects deposit and withdraw events from both L1 and L2 chain and generates withdrawal proofs
|
||||
├── <a href="./common/">common</a>: Common libraries and types
|
||||
├── <a href="./coordinator/">coordinator</a>: Prover coordinator service that dispatches proving tasks to provers
|
||||
├── <a href="./database">database</a>: Database client and schema definition
|
||||
@@ -29,7 +29,7 @@
|
||||
We welcome community contributions to this repository. Before you submit any issues or PRs, please read the [Code of Conduct](CODE_OF_CONDUCT.md) and the [Contribution Guideline](CONTRIBUTING.md).
|
||||
|
||||
## Prerequisites
|
||||
+ Go 1.21
|
||||
+ Go 1.19
|
||||
+ Rust (for version, see [rust-toolchain](./common/libzkp/impl/rust-toolchain))
|
||||
+ Hardhat / Foundry
|
||||
+ Docker
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
.PHONY: lint
|
||||
REPO_ROOT_DIR=./..
|
||||
IMAGE_VERSION=latest
|
||||
PWD=$(shell pwd)
|
||||
|
||||
lint: ## Lint the files - used for CI
|
||||
GOBIN=$(PWD)/build/bin go run ../build/lint.go
|
||||
@@ -18,25 +17,14 @@ bridgehistoryapi-fetcher:
|
||||
bridgehistoryapi-api:
|
||||
go build -o $(PWD)/build/bin/bridgehistoryapi-api ./cmd/api
|
||||
|
||||
reset-env:
|
||||
if docker ps -a -q -f name=bridgehistoryapi-redis | grep -q . ; then \
|
||||
docker stop bridgehistoryapi-redis; \
|
||||
docker rm bridgehistoryapi-redis; \
|
||||
fi
|
||||
docker run --name bridgehistoryapi-redis -d -p 6379:6379 redis:latest
|
||||
if docker ps -a -q -f name=bridgehistoryapi-history-db | grep -q . ; then \
|
||||
docker stop bridgehistoryapi-history-db; \
|
||||
docker rm bridgehistoryapi-history-db; \
|
||||
fi
|
||||
reset-db-docker:
|
||||
-docker stop bridgehistoryapi-history-db
|
||||
-docker rm bridgehistoryapi-history-db
|
||||
docker run --name bridgehistoryapi-history-db -p 5444:5432 -e POSTGRES_PASSWORD=123456 -e POSTGRES_DB=test -d postgres
|
||||
until docker exec bridgehistoryapi-history-db pg_isready -h localhost -p 5432 -U postgres > /dev/null; do \
|
||||
echo "Waiting for postgres to be ready..."; \
|
||||
sleep 1; \
|
||||
done
|
||||
echo "Postgres is ready."
|
||||
go build -o $(PWD)/build/bin/bridgehistoryapi-db-cli ./cmd/db_cli && $(PWD)/build/bin/bridgehistoryapi-db-cli reset
|
||||
go build -o $(PWD)/build/bin/bridgehistoryapi-db-cli ./cmd/db_cli & sleep 2
|
||||
$(PWD)/build/bin/bridgehistoryapi-db-cli reset
|
||||
|
||||
bridgehistoryapi-docker:
|
||||
DOCKER_BUILDKIT=1 docker build -t scrolltech/bridgehistoryapi-fetcher:${IMAGE_VERSION} ${REPO_ROOT_DIR}/ -f ${REPO_ROOT_DIR}/build/dockerfiles/bridgehistoryapi-fetcher.Dockerfile
|
||||
DOCKER_BUILDKIT=1 docker build -t scrolltech/bridgehistoryapi-api:${IMAGE_VERSION} ${REPO_ROOT_DIR}/ -f ${REPO_ROOT_DIR}/build/dockerfiles/bridgehistoryapi-api.Dockerfile
|
||||
DOCKER_BUILDKIT=1 docker build -t scrolltech/bridgehistoryapi-db-cli:${IMAGE_VERSION} ${REPO_ROOT_DIR}/ -f ${REPO_ROOT_DIR}/build/dockerfiles/bridgehistoryapi-db-cli.Dockerfile
|
||||
DOCKER_BUILDKIT=1 docker build -t scrolltech/bridgehistoryapi-cross-message-fetcher:${IMAGE_VERSION} ${REPO_ROOT_DIR}/ -f ${REPO_ROOT_DIR}/build/dockerfiles/bridgehistoryapi-cross-message-fetcher.Dockerfile
|
||||
DOCKER_BUILDKIT=1 docker build -t scrolltech/bridgehistoryapi-server:${IMAGE_VERSION} ${REPO_ROOT_DIR}/ -f ${REPO_ROOT_DIR}/build/dockerfiles/bridgehistoryapi-server.Dockerfile
|
||||
DOCKER_BUILDKIT=1 docker build -t scrolltech/bridgehistoryapi-db-cli:${IMAGE_VERSION} ${REPO_ROOT_DIR}/ -f ${REPO_ROOT_DIR}/build/dockerfiles/bridgehistoryapi-db-cli.Dockerfile
|
||||
@@ -7,36 +7,39 @@ The bridge-history-api contains three distinct components
|
||||
|
||||
### bridgehistoryapi-db-cli
|
||||
|
||||
Provide init, show version, rollback, and check status services of DB
|
||||
Provide init, show version, rollback, check status services of DB
|
||||
```
|
||||
cd ./bridge-history-api
|
||||
make bridgehistoryapi-db-cli
|
||||
./build/bin/bridgehistoryapi-db-cli [command]
|
||||
```
|
||||
|
||||
### bridgehistoryapi-fetcher
|
||||
### bridgehistoryapi-cross-msg-fetcher
|
||||
|
||||
Fetch the transactions from both L1 and L2
|
||||
```
|
||||
cd ./bridge-history-api
|
||||
make bridgehistoryapi-fetcher
|
||||
./build/bin/bridgehistoryapi-fetcher
|
||||
make bridgehistoryapi-cross-msg-fetcher
|
||||
./build/bin/bridgehistoryapi-cross-msg-fetcher
|
||||
```
|
||||
|
||||
### bridgehistoryapi-api
|
||||
### bridgehistoryapi-server
|
||||
|
||||
provides REST APIs. Please refer to the API details below.
|
||||
```
|
||||
cd ./bridge-history-api
|
||||
make bridgehistoryapi-api
|
||||
./build/bin/bridgehistoryapi-api
|
||||
make bridgehistoryapi-server
|
||||
./build/bin/bridgehistoryapi-server
|
||||
```
|
||||
|
||||
## APIs provided by bridgehistoryapi-api
|
||||
## APIs provided by bridgehistoryapi-server
|
||||
|
||||
1. `/api/txs`
|
||||
assume `bridgehistoryapi-server` listening on `https://localhost:8080`
|
||||
can change this port thru modify `config.json`
|
||||
|
||||
1. `/txs`
|
||||
```
|
||||
// @Summary get all txs under the given address
|
||||
// @Summary get all txs under given address
|
||||
// @Accept plain
|
||||
// @Produce plain
|
||||
// @Param address query string true "wallet address"
|
||||
@@ -46,7 +49,7 @@ provides REST APIs. Please refer to the API details below.
|
||||
// @Router /api/txs [get]
|
||||
```
|
||||
|
||||
2. `/api/l2/withdrawals`
|
||||
2. `/withdrawals`
|
||||
```
|
||||
// @Summary get all L2 withdrawals under given address
|
||||
// @Accept plain
|
||||
@@ -55,22 +58,22 @@ provides REST APIs. Please refer to the API details below.
|
||||
// @Param page_size query int true "page size"
|
||||
// @Param page query int true "page"
|
||||
// @Success 200
|
||||
// @Router /api/l2/withdrawals [get]
|
||||
// @Router /api/withdrawals [get]
|
||||
```
|
||||
|
||||
3. `/api/l2/unclaimed/withdrawals`
|
||||
3. `/claimablewithdrawals`
|
||||
```
|
||||
// @Summary get all L2 unclaimed withdrawals under the given address
|
||||
// @Summary get all L2 claimable withdrawals under given address
|
||||
// @Accept plain
|
||||
// @Produce plain
|
||||
// @Param address query string true "wallet address"
|
||||
// @Param page_size query int true "page size"
|
||||
// @Param page query int true "page"
|
||||
// @Success 200
|
||||
// @Router /api/l2/unclaimed/withdrawals [get]
|
||||
// @Router /api/claimablewithdrawals [get]
|
||||
```
|
||||
|
||||
4. `/api/txsbyhashes`
|
||||
4. `/txsbyhashes`
|
||||
```
|
||||
// @Summary get txs by given tx hashes
|
||||
// @Accept plain
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-redis/redis/v8"
|
||||
@@ -22,14 +20,16 @@ import (
|
||||
"scroll-tech/bridge-history-api/internal/route"
|
||||
)
|
||||
|
||||
var app *cli.App
|
||||
var (
|
||||
app *cli.App
|
||||
)
|
||||
|
||||
func init() {
|
||||
app = cli.NewApp()
|
||||
|
||||
app.Action = action
|
||||
app.Name = "Scroll Bridge History API Web Service"
|
||||
app.Usage = "The Scroll Bridge History API Web Service"
|
||||
app.Name = "Scroll Bridge History Web Service"
|
||||
app.Usage = "The Scroll Bridge History Web Service"
|
||||
app.Flags = append(app.Flags, utils.CommonFlags...)
|
||||
app.Commands = []*cli.Command{}
|
||||
|
||||
@@ -54,23 +54,15 @@ func action(ctx *cli.Context) error {
|
||||
log.Error("failed to close db", "err", err)
|
||||
}
|
||||
}()
|
||||
opts := &redis.Options{
|
||||
Addr: cfg.Redis.Address,
|
||||
Username: cfg.Redis.Username,
|
||||
Password: cfg.Redis.Password,
|
||||
MinIdleConns: cfg.Redis.MinIdleConns,
|
||||
ReadTimeout: time.Duration(cfg.Redis.ReadTimeoutMs * int(time.Millisecond)),
|
||||
|
||||
redisClient := redis.NewClient(&redis.Options{
|
||||
Addr: cfg.Redis.Address,
|
||||
Password: cfg.Redis.Password,
|
||||
DB: cfg.Redis.DB,
|
||||
})
|
||||
if redisClient == nil {
|
||||
log.Crit("failed to init redis client")
|
||||
}
|
||||
// Production Redis service has enabled transit_encryption.
|
||||
if !cfg.Redis.Local {
|
||||
opts.TLSConfig = &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: true, //nolint:gosec
|
||||
}
|
||||
}
|
||||
log.Info("init redis client", "addr", opts.Addr, "user name", opts.Username, "is local", cfg.Redis.Local,
|
||||
"min idle connections", opts.MinIdleConns, "read timeout", opts.ReadTimeout)
|
||||
redisClient := redis.NewClient(opts)
|
||||
api.InitController(db, redisClient)
|
||||
|
||||
router := gin.Default()
|
||||
@@ -78,8 +70,8 @@ func action(ctx *cli.Context) error {
|
||||
route.Route(router, cfg, registry)
|
||||
|
||||
go func() {
|
||||
port := ctx.Int(utils.ServicePortFlag.Name)
|
||||
if runServerErr := router.Run(fmt.Sprintf(":%d", port)); runServerErr != nil {
|
||||
port := utils.ServicePortFlag.Name
|
||||
if runServerErr := router.Run(fmt.Sprintf(":%s", port)); runServerErr != nil {
|
||||
log.Crit("run http server failure", "error", runServerErr)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -9,10 +9,14 @@ import (
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
var app *cli.App
|
||||
var (
|
||||
// Set up database app info.
|
||||
app *cli.App
|
||||
)
|
||||
|
||||
func init() {
|
||||
app = cli.NewApp()
|
||||
// Set up database app info.
|
||||
app.Name = "db_cli"
|
||||
app.Usage = "The Scroll Bridge-history-api DB CLI"
|
||||
app.Flags = append(app.Flags, utils.CommonFlags...)
|
||||
@@ -56,8 +60,7 @@ func init() {
|
||||
Name: "version",
|
||||
Usage: "Rollback to the specified version.",
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,15 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"scroll-tech/common/database"
|
||||
"scroll-tech/common/observability"
|
||||
"scroll-tech/common/utils"
|
||||
|
||||
"scroll-tech/bridge-history-api/internal/config"
|
||||
"scroll-tech/bridge-history-api/internal/controller/fetcher"
|
||||
)
|
||||
|
||||
var app *cli.App
|
||||
var (
|
||||
app *cli.App
|
||||
)
|
||||
|
||||
func init() {
|
||||
app = cli.NewApp()
|
||||
@@ -66,12 +67,16 @@ func action(ctx *cli.Context) error {
|
||||
log.Crit("failed to connect to db", "config file", cfgFile, "error", err)
|
||||
}
|
||||
|
||||
observability.Server(ctx, db)
|
||||
|
||||
l1MessageFetcher := fetcher.NewL1MessageFetcher(subCtx, cfg.L1, db, l1Client)
|
||||
l1MessageFetcher, err := fetcher.NewL1MessageFetcher(subCtx, cfg.L1, db, l1Client)
|
||||
if err != nil {
|
||||
log.Crit("failed to create L1 cross message fetcher", "error", err)
|
||||
}
|
||||
go l1MessageFetcher.Start()
|
||||
|
||||
l2MessageFetcher := fetcher.NewL2MessageFetcher(subCtx, cfg.L2, db, l2Client)
|
||||
l2MessageFetcher, err := fetcher.NewL2MessageFetcher(subCtx, cfg.L2, db, l2Client)
|
||||
if err != nil {
|
||||
log.Crit("failed to create L2 cross message fetcher", "error", err)
|
||||
}
|
||||
go l2MessageFetcher.Start()
|
||||
|
||||
// Catch CTRL-C to ensure a graceful shutdown.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"L1": {
|
||||
"confirmation": 0,
|
||||
"confirmation": 64,
|
||||
"endpoint": "https://rpc.ankr.com/eth",
|
||||
"startHeight": 18306000,
|
||||
"blockTime": 12,
|
||||
"fetchLimit": 16,
|
||||
"startHeight": 18318215,
|
||||
"blockTime": 10,
|
||||
"fetchLimit": 30,
|
||||
"MessengerAddr": "0x6774Bcbd5ceCeF1336b5300fb5186a12DDD8b367",
|
||||
"ETHGatewayAddr": "0x7F2b8C31F88B6006c382775eea88297Ec1e3E905",
|
||||
"WETHGatewayAddr": "0x7AC440cAe8EB6328de4fA621163a792c1EA9D4fE",
|
||||
@@ -20,10 +20,10 @@
|
||||
"MessageQueueAddr": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B"
|
||||
},
|
||||
"L2": {
|
||||
"confirmation": 0,
|
||||
"endpoint": "https://rpc.scroll.io",
|
||||
"confirmation": 1,
|
||||
"endpoint": "http://mainnet-l2geth-internal-1.mainnet.scroll.tech:8545",
|
||||
"blockTime": 3,
|
||||
"fetchLimit": 64,
|
||||
"fetchLimit": 100,
|
||||
"MessengerAddr": "0x781e90f1c8Fc4611c9b7497C3B47F99Ef6969CbC",
|
||||
"ETHGatewayAddr": "0x6EA73e05AdC79974B931123675ea8F78FfdacDF0",
|
||||
"WETHGatewayAddr": "0x7003E7B7186f0E6601203b99F7B8DECBfA391cf9",
|
||||
@@ -44,10 +44,7 @@
|
||||
},
|
||||
"redis": {
|
||||
"address": "localhost:6379",
|
||||
"username": "default",
|
||||
"password": "",
|
||||
"local": true,
|
||||
"minIdleConns": 10,
|
||||
"readTimeoutMs": 500
|
||||
"db": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,36 @@
|
||||
module scroll-tech/bridge-history-api
|
||||
|
||||
go 1.21
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/cors v1.5.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/pressly/goose/v3 v3.16.0
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20240326144132-0f0cd99f7a2e
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230829000527-f883dcdc21fc
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/sync v0.5.0
|
||||
gorm.io/gorm v1.25.5
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.12.0 // indirect
|
||||
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
||||
github.com/bytedance/sonic v1.10.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.0 // indirect
|
||||
github.com/consensys/bavard v0.1.13 // indirect
|
||||
github.com/consensys/gnark-crypto v0.12.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/docker/cli v25.0.1+incompatible // indirect
|
||||
github.com/docker/docker v25.0.3+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4 // indirect
|
||||
github.com/fjl/memsize v0.0.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-kit/kit v0.9.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.15.5 // indirect
|
||||
@@ -52,53 +39,37 @@ require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/go-bexpr v0.1.10 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.4 // indirect
|
||||
github.com/huin/goupnp v1.3.0 // indirect
|
||||
github.com/holiman/uint256 v1.2.3 // indirect
|
||||
github.com/huin/goupnp v1.0.3 // indirect
|
||||
github.com/iden3/go-iden3-crypto v0.0.15 // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.4 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/gomega v1.27.1 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/prometheus/tsdb v0.7.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/scroll-tech/zktrie v0.7.1 // indirect
|
||||
github.com/scroll-tech/zktrie v0.6.0 // indirect
|
||||
github.com/sethvargo/go-retry v0.2.4 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/status-im/keycard-go v0.2.0 // indirect
|
||||
github.com/supranational/blst v0.3.11-0.20230124161941-ca03e11a3ff2 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
@@ -106,19 +77,15 @@ require (
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/mod v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.15.0 // indirect
|
||||
golang.org/x/net v0.18.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
||||
|
||||
@@ -1,30 +1,13 @@
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0=
|
||||
github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.15.0 h1:G0hTKyO8fXXR1bGnZ0DY3vTG01xYfOGW76zgjg5tmC4=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.15.0/go.mod h1:kXt1SRq0PIRa6aKZD7TnFnY9PQKmc2b13sHtOYcK6cQ=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA=
|
||||
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
@@ -39,10 +22,7 @@ github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ
|
||||
github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc=
|
||||
github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
@@ -51,16 +31,9 @@ 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/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
|
||||
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.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
|
||||
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
|
||||
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/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/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA=
|
||||
github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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 v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -70,35 +43,21 @@ github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsP
|
||||
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbTO1lpcGSkU=
|
||||
github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ=
|
||||
github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
|
||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T/Lao=
|
||||
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/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
|
||||
github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4 h1:B2mpK+MNqgPqk2/KNi1LbqwtZDy5F7iy0mynQiBr8VA=
|
||||
github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4/go.mod h1:y4GA2JbAUama1S4QwYjC2hefgGLU8Ul0GMtL/ADMF1c=
|
||||
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.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
|
||||
github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk=
|
||||
github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
@@ -106,20 +65,10 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||
github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI=
|
||||
github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
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/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
@@ -129,65 +78,44 @@ github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QX
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
|
||||
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
|
||||
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
|
||||
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4=
|
||||
github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
|
||||
github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
@@ -196,28 +124,22 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
||||
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
||||
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/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
@@ -225,126 +147,86 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
|
||||
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
||||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
|
||||
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40=
|
||||
github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M=
|
||||
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
|
||||
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
|
||||
github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s=
|
||||
github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pressly/goose/v3 v3.16.0 h1:xMJUsZdHLqSnCqESyKSqEfcYVYsUuup1nrOhaEFftQg=
|
||||
github.com/pressly/goose/v3 v3.16.0/go.mod h1:JwdKVnmCRhnF6XLQs2mHEQtucFD49cQBdRM4UiwkxsM=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI=
|
||||
github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
|
||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
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/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/scroll-tech/go-ethereum v1.10.14-0.20240326144132-0f0cd99f7a2e h1:FcoK0rykAWI+5E7cQM6ALRLd5CmjBTHRvJztRBH2xeM=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20240326144132-0f0cd99f7a2e/go.mod h1:7Rz2bh9pn42rGuxjh51CG7HL9SKMG3ZugJkL3emdZx8=
|
||||
github.com/scroll-tech/zktrie v0.7.1 h1:NrmZNjuBzsbrKePqdHDG+t2cXnimbtezPAFS0+L9ElE=
|
||||
github.com/scroll-tech/zktrie v0.7.1/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230829000527-f883dcdc21fc h1:eK3NOpjgm/b2TQ6rYqWx92Zri0kBuxf6gKjjsVxWKr8=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230829000527-f883dcdc21fc/go.mod h1:DiN3p2inoXOxGffxSswDKqWjQ7bU+Mp0c9v0XQXKmaA=
|
||||
github.com/scroll-tech/zktrie v0.6.0 h1:xLrMAO31Yo2BiPg1jtYKzcjpEFnXy8acbB7iIsyshPs=
|
||||
github.com/scroll-tech/zktrie v0.6.0/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
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/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
|
||||
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/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
|
||||
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
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.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
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.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/supranational/blst v0.3.11-0.20230124161941-ca03e11a3ff2 h1:wh1wzwAhZBNiZO37uWS/nDaKiIwHz4mDo4pnA+fqTO0=
|
||||
github.com/supranational/blst v0.3.11-0.20230124161941-ca03e11a3ff2/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/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
@@ -358,25 +240,17 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
|
||||
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw=
|
||||
github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dzWP1Lu+A40W883dK/Mr3xyDSM/2MggS8GtHT0qgAnE=
|
||||
github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
|
||||
go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
@@ -385,112 +259,69 @@ 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-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.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
|
||||
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
|
||||
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
|
||||
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
|
||||
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
|
||||
modernc.org/libc v1.32.0 h1:yXatHTrACp3WaKNRCoZwUK7qj5V8ep1XyY0ka4oYcNc=
|
||||
modernc.org/libc v1.32.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
||||
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8=
|
||||
modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
|
||||
|
||||
@@ -8,11 +8,11 @@ import (
|
||||
"scroll-tech/common/database"
|
||||
)
|
||||
|
||||
// FetcherConfig is the configuration of Layer1 or Layer2 fetcher.
|
||||
type FetcherConfig struct {
|
||||
// LayerConfig is the configuration of Layer1/Layer2
|
||||
type LayerConfig struct {
|
||||
Confirmation uint64 `json:"confirmation"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
StartHeight uint64 `json:"startHeight"` // Can only be configured to contract deployment height, message proof should be updated from the very beginning.
|
||||
StartHeight uint64 `json:"startHeight"`
|
||||
BlockTime int64 `json:"blockTime"`
|
||||
FetchLimit uint64 `json:"fetchLimit"`
|
||||
MessengerAddr string `json:"MessengerAddr"`
|
||||
@@ -23,7 +23,6 @@ type FetcherConfig struct {
|
||||
DAIGatewayAddr string `json:"DAIGatewayAddr"`
|
||||
USDCGatewayAddr string `json:"USDCGatewayAddr"`
|
||||
LIDOGatewayAddr string `json:"LIDOGatewayAddr"`
|
||||
PufferGatewayAddr string `json:"PufferGatewayAddr"`
|
||||
ERC721GatewayAddr string `json:"ERC721GatewayAddr"`
|
||||
ERC1155GatewayAddr string `json:"ERC1155GatewayAddr"`
|
||||
ScrollChainAddr string `json:"ScrollChainAddr"`
|
||||
@@ -33,19 +32,15 @@ type FetcherConfig struct {
|
||||
|
||||
// RedisConfig redis config
|
||||
type RedisConfig struct {
|
||||
Address string `json:"address"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
DB int `json:"db"`
|
||||
Local bool `json:"local"`
|
||||
MinIdleConns int `json:"minIdleConns"`
|
||||
ReadTimeoutMs int `json:"readTimeoutMs"`
|
||||
Address string `json:"address"`
|
||||
Password string `json:"password"`
|
||||
DB int `json:"db"`
|
||||
}
|
||||
|
||||
// Config is the configuration of the bridge history backend
|
||||
type Config struct {
|
||||
L1 *FetcherConfig `json:"L1"`
|
||||
L2 *FetcherConfig `json:"L2"`
|
||||
L1 *LayerConfig `json:"L1"`
|
||||
L2 *LayerConfig `json:"L2"`
|
||||
DB *database.Config `json:"db"`
|
||||
Redis *RedisConfig `json:"redis"`
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"gorm.io/gorm"
|
||||
@@ -21,21 +23,21 @@ func NewHistoryController(db *gorm.DB, redis *redis.Client) *HistoryController {
|
||||
}
|
||||
}
|
||||
|
||||
// GetL2UnclaimedWithdrawalsByAddress defines the http get method behavior
|
||||
func (c *HistoryController) GetL2UnclaimedWithdrawalsByAddress(ctx *gin.Context) {
|
||||
// GetL2ClaimableWithdrawalsByAddress defines the http get method behavior
|
||||
func (c *HistoryController) GetL2ClaimableWithdrawalsByAddress(ctx *gin.Context) {
|
||||
var req types.QueryByAddressRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, err)
|
||||
return
|
||||
}
|
||||
|
||||
pagedTxs, total, err := c.historyLogic.GetL2UnclaimedWithdrawalsByAddress(ctx, req.Address, req.Page, req.PageSize)
|
||||
pagedTxs, total, err := c.historyLogic.GetL2ClaimableWithdrawalsByAddress(ctx, req.Address, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
types.RenderFailure(ctx, types.ErrGetL2ClaimableWithdrawalsError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resultData := &types.ResultData{Results: pagedTxs, Total: total}
|
||||
resultData := &types.ResultData{Result: pagedTxs, Total: total}
|
||||
types.RenderSuccess(ctx, resultData)
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ func (c *HistoryController) GetL2WithdrawalsByAddress(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
resultData := &types.ResultData{Results: pagedTxs, Total: total}
|
||||
resultData := &types.ResultData{Result: pagedTxs, Total: total}
|
||||
types.RenderSuccess(ctx, resultData)
|
||||
}
|
||||
|
||||
@@ -71,7 +73,7 @@ func (c *HistoryController) GetTxsByAddress(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
resultData := &types.ResultData{Results: pagedTxs, Total: total}
|
||||
resultData := &types.ResultData{Result: pagedTxs, Total: total}
|
||||
types.RenderSuccess(ctx, resultData)
|
||||
}
|
||||
|
||||
@@ -83,12 +85,17 @@ func (c *HistoryController) PostQueryTxsByHashes(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Txs) > 100 {
|
||||
types.RenderFailure(ctx, types.ErrParameterInvalidNo, errors.New("number of hashes exceeds the allowed maximum (100)"))
|
||||
return
|
||||
}
|
||||
|
||||
results, err := c.historyLogic.GetTxsByHashes(ctx, req.Txs)
|
||||
if err != nil {
|
||||
types.RenderFailure(ctx, types.ErrGetTxsByHashError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resultData := &types.ResultData{Results: results, Total: uint64(len(results))}
|
||||
resultData := &types.ResultData{Result: results, Total: uint64(len(results))}
|
||||
types.RenderSuccess(ctx, resultData)
|
||||
}
|
||||
|
||||
@@ -5,94 +5,73 @@ import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/scroll-tech/go-ethereum"
|
||||
"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"
|
||||
"gorm.io/gorm"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
"scroll-tech/bridge-history-api/internal/config"
|
||||
"scroll-tech/bridge-history-api/internal/logic"
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// L1MessageFetcher fetches cross message events from L1 and saves them to database.
|
||||
type L1MessageFetcher struct {
|
||||
ctx context.Context
|
||||
cfg *config.FetcherConfig
|
||||
client *ethclient.Client
|
||||
|
||||
l1SyncHeight uint64
|
||||
l1LastSyncBlockHash common.Hash
|
||||
|
||||
eventUpdateLogic *logic.EventUpdateLogic
|
||||
l1FetcherLogic *logic.L1FetcherLogic
|
||||
|
||||
l1MessageFetcherRunningTotal prometheus.Counter
|
||||
l1MessageFetcherReorgTotal prometheus.Counter
|
||||
l1MessageFetcherSyncHeight prometheus.Gauge
|
||||
ctx context.Context
|
||||
cfg *config.LayerConfig
|
||||
db *gorm.DB
|
||||
crossMessageOrm *orm.CrossMessage
|
||||
batchEventOrm *orm.BatchEvent
|
||||
client *ethclient.Client
|
||||
addressList []common.Address
|
||||
}
|
||||
|
||||
// NewL1MessageFetcher creates a new L1MessageFetcher instance.
|
||||
func NewL1MessageFetcher(ctx context.Context, cfg *config.FetcherConfig, db *gorm.DB, client *ethclient.Client) *L1MessageFetcher {
|
||||
c := &L1MessageFetcher{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
client: client,
|
||||
eventUpdateLogic: logic.NewEventUpdateLogic(db, true),
|
||||
l1FetcherLogic: logic.NewL1FetcherLogic(cfg, db, client),
|
||||
func NewL1MessageFetcher(ctx context.Context, cfg *config.LayerConfig, db *gorm.DB, client *ethclient.Client) (*L1MessageFetcher, error) {
|
||||
addressList := []common.Address{
|
||||
common.HexToAddress(cfg.ETHGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.StandardERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.CustomERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.WETHGatewayAddr),
|
||||
common.HexToAddress(cfg.DAIGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.ERC721GatewayAddr),
|
||||
common.HexToAddress(cfg.ERC1155GatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessengerAddr),
|
||||
|
||||
common.HexToAddress(cfg.ScrollChainAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessageQueueAddr),
|
||||
}
|
||||
|
||||
reg := prometheus.DefaultRegisterer
|
||||
c.l1MessageFetcherRunningTotal = promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "L1_message_fetcher_running_total",
|
||||
Help: "Current count of running L1 message fetcher instances.",
|
||||
})
|
||||
c.l1MessageFetcherReorgTotal = promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "L1_message_fetcher_reorg_total",
|
||||
Help: "Total count of blockchain reorgs encountered by the L1 message fetcher.",
|
||||
})
|
||||
c.l1MessageFetcherSyncHeight = promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "L1_message_fetcher_sync_height",
|
||||
Help: "Latest blockchain height the L1 message fetcher has synced with.",
|
||||
})
|
||||
// Optional erc20 gateways.
|
||||
if cfg.USDCGatewayAddr != "" {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.USDCGatewayAddr))
|
||||
}
|
||||
|
||||
return c
|
||||
if cfg.LIDOGatewayAddr != "" {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.LIDOGatewayAddr))
|
||||
}
|
||||
|
||||
return &L1MessageFetcher{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
db: db,
|
||||
crossMessageOrm: orm.NewCrossMessage(db),
|
||||
batchEventOrm: orm.NewBatchEvent(db),
|
||||
client: client,
|
||||
addressList: addressList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Start starts the L1 message fetching process.
|
||||
func (c *L1MessageFetcher) Start() {
|
||||
messageSyncedHeight, batchSyncedHeight, dbErr := c.eventUpdateLogic.GetL1SyncHeight(c.ctx)
|
||||
if dbErr != nil {
|
||||
log.Crit("L1MessageFetcher start failed", "err", dbErr)
|
||||
}
|
||||
|
||||
l1SyncHeight := messageSyncedHeight
|
||||
if batchSyncedHeight > l1SyncHeight {
|
||||
l1SyncHeight = batchSyncedHeight
|
||||
}
|
||||
if c.cfg.StartHeight > l1SyncHeight {
|
||||
l1SyncHeight = c.cfg.StartHeight - 1
|
||||
}
|
||||
|
||||
// Sync from an older block to prevent reorg during restart.
|
||||
if l1SyncHeight < logic.L1ReorgSafeDepth {
|
||||
l1SyncHeight = 0
|
||||
} else {
|
||||
l1SyncHeight -= logic.L1ReorgSafeDepth
|
||||
}
|
||||
|
||||
header, err := c.client.HeaderByNumber(c.ctx, new(big.Int).SetUint64(l1SyncHeight))
|
||||
if err != nil {
|
||||
log.Crit("failed to get L1 header by number", "block number", l1SyncHeight, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.updateL1SyncHeight(l1SyncHeight, header.Hash())
|
||||
|
||||
log.Info("Start L1 message fetcher", "message synced height", messageSyncedHeight, "batch synced height", batchSyncedHeight, "config start height", c.cfg.StartHeight, "sync start height", c.l1SyncHeight+1)
|
||||
|
||||
tick := time.NewTicker(time.Duration(c.cfg.BlockTime) * time.Second)
|
||||
go func() {
|
||||
for {
|
||||
@@ -108,47 +87,175 @@ func (c *L1MessageFetcher) Start() {
|
||||
}
|
||||
|
||||
func (c *L1MessageFetcher) fetchAndSaveEvents(confirmation uint64) {
|
||||
startHeight := c.l1SyncHeight + 1
|
||||
endHeight, rpcErr := utils.GetBlockNumber(c.ctx, c.client, confirmation)
|
||||
if rpcErr != nil {
|
||||
log.Error("failed to get L1 block number", "confirmation", confirmation, "err", rpcErr)
|
||||
endHeight, err := utils.GetBlockNumber(c.ctx, c.client, confirmation)
|
||||
if err != nil {
|
||||
log.Error("failed to get L1 safe block number", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info("fetch and save missing L1 events", "start height", startHeight, "end height", endHeight, "confirmation", confirmation)
|
||||
l1SentMessageProcessedHeight, err := c.crossMessageOrm.GetMessageProcessedHeightInDB(c.ctx, orm.MessageTypeL1SentMessage)
|
||||
if err != nil {
|
||||
log.Error("failed to get L1 cross message processed height", "err", err)
|
||||
return
|
||||
}
|
||||
startHeight := c.cfg.StartHeight
|
||||
if l1SentMessageProcessedHeight+1 > startHeight {
|
||||
startHeight = l1SentMessageProcessedHeight + 1
|
||||
}
|
||||
log.Info("fetch and save missing L1 events", "start height", startHeight, "config height", c.cfg.StartHeight, "db height", l1SentMessageProcessedHeight)
|
||||
|
||||
for from := startHeight; from <= endHeight; from += c.cfg.FetchLimit {
|
||||
to := from + c.cfg.FetchLimit - 1
|
||||
if to > endHeight {
|
||||
to = endHeight
|
||||
}
|
||||
|
||||
isReorg, resyncHeight, lastBlockHash, l1FetcherResult, fetcherErr := c.l1FetcherLogic.L1Fetcher(c.ctx, from, to, c.l1LastSyncBlockHash)
|
||||
if fetcherErr != nil {
|
||||
log.Error("failed to fetch L1 events", "from", from, "to", to, "err", fetcherErr)
|
||||
err = c.doFetchAndSaveEvents(c.ctx, from, to, c.addressList)
|
||||
if err != nil {
|
||||
log.Error("failed to fetch and save L1 events", "from", from, "to", to, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
if isReorg {
|
||||
c.l1MessageFetcherReorgTotal.Inc()
|
||||
log.Warn("L1 reorg happened, exit and re-enter fetchAndSaveEvents", "re-sync height", resyncHeight)
|
||||
c.updateL1SyncHeight(resyncHeight, lastBlockHash)
|
||||
c.l1MessageFetcherRunningTotal.Inc()
|
||||
return
|
||||
}
|
||||
|
||||
if insertUpdateErr := c.eventUpdateLogic.L1InsertOrUpdate(c.ctx, l1FetcherResult); insertUpdateErr != nil {
|
||||
log.Error("failed to save L1 events", "from", from, "to", to, "err", insertUpdateErr)
|
||||
return
|
||||
}
|
||||
|
||||
c.updateL1SyncHeight(to, lastBlockHash)
|
||||
c.l1MessageFetcherRunningTotal.Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *L1MessageFetcher) updateL1SyncHeight(height uint64, blockHash common.Hash) {
|
||||
c.l1MessageFetcherSyncHeight.Set(float64(height))
|
||||
c.l1LastSyncBlockHash = blockHash
|
||||
c.l1SyncHeight = height
|
||||
func (c *L1MessageFetcher) doFetchAndSaveEvents(ctx context.Context, from uint64, to uint64, addrList []common.Address) error {
|
||||
log.Info("fetch and save L1 events", "from", from, "to", to)
|
||||
var l1FailedGatewayRouterTxs []*orm.CrossMessage
|
||||
blockTimestampsMap := make(map[uint64]uint64)
|
||||
for number := from; number <= to; number++ {
|
||||
blockNumber := new(big.Int).SetUint64(number)
|
||||
block, err := c.client.BlockByNumber(ctx, blockNumber)
|
||||
if err != nil {
|
||||
log.Error("failed to get block by number", "number", blockNumber.String(), "err", err)
|
||||
return err
|
||||
}
|
||||
blockTimestampsMap[block.NumberU64()] = block.Time()
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
to := tx.To()
|
||||
if to == nil {
|
||||
continue
|
||||
}
|
||||
toAddress := to.String()
|
||||
if toAddress == c.cfg.GatewayRouterAddr {
|
||||
receipt, err := c.client.TransactionReceipt(ctx, tx.Hash())
|
||||
if err != nil {
|
||||
log.Error("Failed to get transaction receipt", "txHash", tx.Hash().String(), "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the transaction failed
|
||||
if receipt.Status == types.ReceiptStatusFailed {
|
||||
signer := types.NewLondonSigner(new(big.Int).SetUint64(tx.ChainId().Uint64()))
|
||||
sender, err := signer.Sender(tx)
|
||||
if err != nil {
|
||||
log.Error("get sender failed", "chain id", tx.ChainId().Uint64(), "tx hash", tx.Hash().String(), "err", err)
|
||||
return err
|
||||
}
|
||||
l1FailedGatewayRouterTxs = append(l1FailedGatewayRouterTxs, &orm.CrossMessage{
|
||||
L1TxHash: tx.Hash().String(),
|
||||
MessageType: int(orm.MessageTypeL1SentMessage),
|
||||
Sender: sender.String(),
|
||||
Receiver: (*tx.To()).String(),
|
||||
BlockTimestamp: block.Time(),
|
||||
TxStatus: int(orm.TxStatusTypeSentFailed),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query := ethereum.FilterQuery{
|
||||
FromBlock: new(big.Int).SetUint64(from), // inclusive
|
||||
ToBlock: new(big.Int).SetUint64(to), // inclusive
|
||||
Addresses: addrList,
|
||||
Topics: make([][]common.Hash, 1),
|
||||
}
|
||||
query.Topics[0] = make([]common.Hash, 13)
|
||||
query.Topics[0][0] = backendabi.L1DepositETHSig
|
||||
query.Topics[0][1] = backendabi.L1DepositERC20Sig
|
||||
query.Topics[0][2] = backendabi.L1DepositERC721Sig
|
||||
query.Topics[0][3] = backendabi.L1DepositERC1155Sig
|
||||
query.Topics[0][4] = backendabi.L1SentMessageEventSig
|
||||
query.Topics[0][5] = backendabi.L1RelayedMessageEventSig
|
||||
query.Topics[0][6] = backendabi.L1FailedRelayedMessageEventSig
|
||||
query.Topics[0][7] = backendabi.L1CommitBatchEventSig
|
||||
query.Topics[0][8] = backendabi.L1RevertBatchEventSig
|
||||
query.Topics[0][9] = backendabi.L1FinalizeBatchEventSig
|
||||
query.Topics[0][10] = backendabi.L1QueueTransactionEventSig
|
||||
query.Topics[0][11] = backendabi.L1DequeueTransactionEventSig
|
||||
query.Topics[0][12] = backendabi.L1DropTransactionEventSig
|
||||
|
||||
logs, err := c.client.FilterLogs(ctx, query)
|
||||
if err != nil {
|
||||
log.Error("failed to filter L1 event logs", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
l1DepositMessages, l1RelayedMessages, err := logic.ParseL1CrossChainEventLogs(ctx, logs, blockTimestampsMap, c.client)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L1 cross chain event logs", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
l1BatchEvents, err := logic.ParseL1BatchEventLogs(ctx, logs, blockTimestampsMap, c.client)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L1 batch event logs", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
l1MessageQueueEvents, err := logic.ParseL1MessageQueueEventLogs(ctx, logs, blockTimestampsMap, c.client)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L1 message queue event logs", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
err = c.db.Transaction(func(tx *gorm.DB) error {
|
||||
if txErr := c.crossMessageOrm.InsertOrUpdateL1Messages(ctx, l1DepositMessages, tx); txErr != nil {
|
||||
log.Error("failed to insert L1 deposit messages", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
if txErr := c.crossMessageOrm.InsertOrUpdateL1RelayedMessagesOfL2Withdrawals(ctx, l1RelayedMessages, tx); txErr != nil {
|
||||
log.Error("failed to update L1 relayed messages of L2 withdrawals", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
if txErr := c.batchEventOrm.InsertOrUpdateBatchEvents(ctx, l1BatchEvents, tx); txErr != nil {
|
||||
log.Error("failed to insert or update batch events", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
if txErr := c.crossMessageOrm.UpdateL1MessageQueueEventsInfo(ctx, l1MessageQueueEvents, tx); txErr != nil {
|
||||
log.Error("failed to insert L1 message queue events", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
if txErr := c.crossMessageOrm.InsertFailedGatewayRouterTxs(ctx, l1FailedGatewayRouterTxs, tx); txErr != nil {
|
||||
log.Error("failed to insert L1 failed gateway router transactions", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("failed to update db of L1 events", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
if err = c.updateBatchIndexAndStatus(ctx); err != nil {
|
||||
log.Error("failed to update batch index and status", "err", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *L1MessageFetcher) updateBatchIndexAndStatus(ctx context.Context) error {
|
||||
latestMessageHeight, err := c.crossMessageOrm.GetLatestFinalizedL2WithdrawalBlockHeight(ctx)
|
||||
if err != nil {
|
||||
log.Error("failed to get latest finalized L2 sent message block height", "error", err)
|
||||
return err
|
||||
}
|
||||
batches, err := c.batchEventOrm.GetBatchesGEBlockHeight(ctx, latestMessageHeight+1)
|
||||
if err != nil {
|
||||
log.Error("failed to get batches >= block height", "error", err)
|
||||
return err
|
||||
}
|
||||
for _, batch := range batches {
|
||||
log.Info("update batch info of L2 withdrawals", "index", batch.BatchIndex, "start", batch.StartBlockNumber, "end", batch.EndBlockNumber)
|
||||
if err := c.crossMessageOrm.UpdateBatchStatusOfL2Withdrawals(ctx, batch.StartBlockNumber, batch.EndBlockNumber, batch.BatchIndex); err != nil {
|
||||
log.Error("failed to update batch status of L2 sent messages", "start", batch.StartBlockNumber, "end", batch.EndBlockNumber, "index", batch.BatchIndex, "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,92 +2,73 @@ package fetcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/scroll-tech/go-ethereum"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/scroll-tech/go-ethereum/rpc"
|
||||
"gorm.io/gorm"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
"scroll-tech/bridge-history-api/internal/config"
|
||||
"scroll-tech/bridge-history-api/internal/logic"
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// L2MessageFetcher fetches cross message events from L2 and saves them to database.
|
||||
type L2MessageFetcher struct {
|
||||
ctx context.Context
|
||||
cfg *config.FetcherConfig
|
||||
db *gorm.DB
|
||||
client *ethclient.Client
|
||||
l2SyncHeight uint64
|
||||
l2LastSyncBlockHash common.Hash
|
||||
|
||||
eventUpdateLogic *logic.EventUpdateLogic
|
||||
l2FetcherLogic *logic.L2FetcherLogic
|
||||
|
||||
l2MessageFetcherRunningTotal prometheus.Counter
|
||||
l2MessageFetcherReorgTotal prometheus.Counter
|
||||
l2MessageFetcherSyncHeight prometheus.Gauge
|
||||
ctx context.Context
|
||||
cfg *config.LayerConfig
|
||||
db *gorm.DB
|
||||
crossMessageOrm *orm.CrossMessage
|
||||
client *ethclient.Client
|
||||
addressList []common.Address
|
||||
}
|
||||
|
||||
// NewL2MessageFetcher creates a new L2MessageFetcher instance.
|
||||
func NewL2MessageFetcher(ctx context.Context, cfg *config.FetcherConfig, db *gorm.DB, client *ethclient.Client) *L2MessageFetcher {
|
||||
c := &L2MessageFetcher{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
db: db,
|
||||
client: client,
|
||||
eventUpdateLogic: logic.NewEventUpdateLogic(db, false),
|
||||
l2FetcherLogic: logic.NewL2FetcherLogic(cfg, db, client),
|
||||
func NewL2MessageFetcher(ctx context.Context, cfg *config.LayerConfig, db *gorm.DB, client *ethclient.Client) (*L2MessageFetcher, error) {
|
||||
addressList := []common.Address{
|
||||
common.HexToAddress(cfg.ETHGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.StandardERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.CustomERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.WETHGatewayAddr),
|
||||
common.HexToAddress(cfg.DAIGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.ERC721GatewayAddr),
|
||||
common.HexToAddress(cfg.ERC1155GatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessengerAddr),
|
||||
}
|
||||
|
||||
reg := prometheus.DefaultRegisterer
|
||||
c.l2MessageFetcherRunningTotal = promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "L2_message_fetcher_running_total",
|
||||
Help: "Current count of running L2 message fetcher instances.",
|
||||
})
|
||||
c.l2MessageFetcherReorgTotal = promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "L2_message_fetcher_reorg_total",
|
||||
Help: "Total count of blockchain reorgs encountered by the L2 message fetcher.",
|
||||
})
|
||||
c.l2MessageFetcherSyncHeight = promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "L2_message_fetcher_sync_height",
|
||||
Help: "Latest blockchain height the L2 message fetcher has synced with.",
|
||||
})
|
||||
// Optional erc20 gateways.
|
||||
if cfg.USDCGatewayAddr != "" {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.USDCGatewayAddr))
|
||||
}
|
||||
|
||||
return c
|
||||
if cfg.LIDOGatewayAddr != "" {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.LIDOGatewayAddr))
|
||||
}
|
||||
|
||||
return &L2MessageFetcher{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
db: db,
|
||||
crossMessageOrm: orm.NewCrossMessage(db),
|
||||
client: client,
|
||||
addressList: addressList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Start starts the L2 message fetching process.
|
||||
func (c *L2MessageFetcher) Start() {
|
||||
l2SentMessageSyncedHeight, dbErr := c.eventUpdateLogic.GetL2MessageSyncedHeightInDB(c.ctx)
|
||||
if dbErr != nil {
|
||||
log.Crit("failed to get L2 cross message processed height", "err", dbErr)
|
||||
return
|
||||
}
|
||||
|
||||
l2SyncHeight := l2SentMessageSyncedHeight
|
||||
// Sync from an older block to prevent reorg during restart.
|
||||
if l2SyncHeight < logic.L2ReorgSafeDepth {
|
||||
l2SyncHeight = 0
|
||||
} else {
|
||||
l2SyncHeight -= logic.L2ReorgSafeDepth
|
||||
}
|
||||
|
||||
header, err := c.client.HeaderByNumber(c.ctx, new(big.Int).SetUint64(l2SyncHeight))
|
||||
if err != nil {
|
||||
log.Crit("failed to get L2 header by number", "block number", l2SyncHeight, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.updateL2SyncHeight(l2SyncHeight, header.Hash())
|
||||
|
||||
log.Info("Start L2 message fetcher", "message synced height", l2SentMessageSyncedHeight, "sync start height", l2SyncHeight+1)
|
||||
|
||||
tick := time.NewTicker(time.Duration(c.cfg.BlockTime) * time.Second)
|
||||
go func() {
|
||||
for {
|
||||
@@ -103,51 +84,175 @@ func (c *L2MessageFetcher) Start() {
|
||||
}
|
||||
|
||||
func (c *L2MessageFetcher) fetchAndSaveEvents(confirmation uint64) {
|
||||
startHeight := c.l2SyncHeight + 1
|
||||
endHeight, rpcErr := utils.GetBlockNumber(c.ctx, c.client, confirmation)
|
||||
if rpcErr != nil {
|
||||
log.Error("failed to get L2 block number", "confirmation", confirmation, "err", rpcErr)
|
||||
endHeight, err := utils.GetBlockNumber(c.ctx, c.client, confirmation)
|
||||
if err != nil {
|
||||
log.Error("failed to get L1 safe block number", "err", err)
|
||||
return
|
||||
}
|
||||
log.Info("fetch and save missing L2 events", "start height", startHeight, "end height", endHeight, "confirmation", confirmation)
|
||||
|
||||
l2SentMessageProcessedHeight, err := c.crossMessageOrm.GetMessageProcessedHeightInDB(c.ctx, orm.MessageTypeL2SentMessage)
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 cross message processed height", "err", err)
|
||||
return
|
||||
}
|
||||
startHeight := c.cfg.StartHeight
|
||||
if l2SentMessageProcessedHeight+1 > startHeight {
|
||||
startHeight = l2SentMessageProcessedHeight + 1
|
||||
}
|
||||
log.Info("fetch and save missing L2 events", "start height", startHeight, "config height", c.cfg.StartHeight, "db height", l2SentMessageProcessedHeight)
|
||||
|
||||
for from := startHeight; from <= endHeight; from += c.cfg.FetchLimit {
|
||||
to := from + c.cfg.FetchLimit - 1
|
||||
if to > endHeight {
|
||||
to = endHeight
|
||||
}
|
||||
|
||||
isReorg, resyncHeight, lastBlockHash, l2FetcherResult, fetcherErr := c.l2FetcherLogic.L2Fetcher(c.ctx, from, to, c.l2LastSyncBlockHash)
|
||||
if fetcherErr != nil {
|
||||
log.Error("failed to fetch L2 events", "from", from, "to", to, "err", fetcherErr)
|
||||
err = c.doFetchAndSaveEvents(c.ctx, from, to, c.addressList)
|
||||
if err != nil {
|
||||
log.Error("failed to fetch and save L2 events", "from", from, "to", to, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
if isReorg {
|
||||
c.l2MessageFetcherReorgTotal.Inc()
|
||||
log.Warn("L2 reorg happened, exit and re-enter fetchAndSaveEvents", "re-sync height", resyncHeight)
|
||||
c.updateL2SyncHeight(resyncHeight, lastBlockHash)
|
||||
c.l2MessageFetcherRunningTotal.Inc()
|
||||
return
|
||||
}
|
||||
|
||||
if insertUpdateErr := c.eventUpdateLogic.L2InsertOrUpdate(c.ctx, l2FetcherResult); insertUpdateErr != nil {
|
||||
log.Error("failed to save L2 events", "from", from, "to", to, "err", insertUpdateErr)
|
||||
return
|
||||
}
|
||||
|
||||
if updateErr := c.eventUpdateLogic.UpdateL1BatchIndexAndStatus(c.ctx, c.l2SyncHeight); updateErr != nil {
|
||||
log.Error("failed to update L1 batch index and status", "from", from, "to", to, "err", updateErr)
|
||||
return
|
||||
}
|
||||
|
||||
c.updateL2SyncHeight(to, lastBlockHash)
|
||||
c.l2MessageFetcherRunningTotal.Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *L2MessageFetcher) updateL2SyncHeight(height uint64, blockHash common.Hash) {
|
||||
c.l2MessageFetcherSyncHeight.Set(float64(height))
|
||||
c.l2LastSyncBlockHash = blockHash
|
||||
c.l2SyncHeight = height
|
||||
func (c *L2MessageFetcher) doFetchAndSaveEvents(ctx context.Context, from uint64, to uint64, addrList []common.Address) error {
|
||||
log.Info("fetch and save L2 events", "from", from, "to", to)
|
||||
var l2FailedGatewayRouterTxs []*orm.CrossMessage
|
||||
var l2RevertedRelayedMessages []*orm.CrossMessage
|
||||
blockTimestampsMap := make(map[uint64]uint64)
|
||||
for number := from; number <= to; number++ {
|
||||
blockNumber := new(big.Int).SetUint64(number)
|
||||
block, err := c.client.GetBlockByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(number)))
|
||||
if err != nil {
|
||||
log.Error("failed to get block by number", "number", blockNumber.String(), "err", err)
|
||||
return err
|
||||
}
|
||||
blockTimestampsMap[block.NumberU64()] = block.Time()
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
to := tx.To()
|
||||
if to == nil {
|
||||
continue
|
||||
}
|
||||
toAddress := to.String()
|
||||
if toAddress == c.cfg.GatewayRouterAddr {
|
||||
receipt, err := c.client.TransactionReceipt(ctx, tx.Hash())
|
||||
if err != nil {
|
||||
log.Error("Failed to get transaction receipt", "txHash", tx.Hash().String(), "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the transaction failed
|
||||
if receipt.Status == types.ReceiptStatusFailed {
|
||||
signer := types.NewLondonSigner(new(big.Int).SetUint64(tx.ChainId().Uint64()))
|
||||
sender, err := signer.Sender(tx)
|
||||
if err != nil {
|
||||
log.Error("get sender failed", "chain id", tx.ChainId().Uint64(), "tx hash", tx.Hash().String(), "err", err)
|
||||
return err
|
||||
}
|
||||
l2FailedGatewayRouterTxs = append(l2FailedGatewayRouterTxs, &orm.CrossMessage{
|
||||
L2TxHash: tx.Hash().String(),
|
||||
MessageType: int(orm.MessageTypeL2SentMessage),
|
||||
Sender: sender.String(),
|
||||
Receiver: (*tx.To()).String(),
|
||||
BlockTimestamp: block.Time(),
|
||||
TxStatus: int(orm.TxStatusTypeSentFailed),
|
||||
})
|
||||
}
|
||||
}
|
||||
if tx.Type() == types.L1MessageTxType {
|
||||
receipt, err := c.client.TransactionReceipt(ctx, tx.Hash())
|
||||
if err != nil {
|
||||
log.Error("Failed to get transaction receipt", "txHash", tx.Hash().String(), "err", err)
|
||||
return err
|
||||
}
|
||||
// Check if the transaction failed
|
||||
if receipt.Status == types.ReceiptStatusFailed {
|
||||
l2RevertedRelayedMessages = append(l2RevertedRelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: common.Bytes2Hex(crypto.Keccak256(tx.AsL1MessageTx().Data)),
|
||||
L2TxHash: tx.Hash().String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayedFailed),
|
||||
L2BlockNumber: receipt.BlockNumber.Uint64(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query := ethereum.FilterQuery{
|
||||
FromBlock: new(big.Int).SetUint64(from), // inclusive
|
||||
ToBlock: new(big.Int).SetUint64(to), // inclusive
|
||||
Addresses: addrList,
|
||||
Topics: make([][]common.Hash, 1),
|
||||
}
|
||||
query.Topics[0] = make([]common.Hash, 7)
|
||||
query.Topics[0][0] = backendabi.L2WithdrawETHSig
|
||||
query.Topics[0][1] = backendabi.L2WithdrawERC20Sig
|
||||
query.Topics[0][2] = backendabi.L2WithdrawERC721Sig
|
||||
query.Topics[0][3] = backendabi.L2WithdrawERC1155Sig
|
||||
query.Topics[0][4] = backendabi.L2SentMessageEventSig
|
||||
query.Topics[0][5] = backendabi.L2RelayedMessageEventSig
|
||||
query.Topics[0][6] = backendabi.L2FailedRelayedMessageEventSig
|
||||
|
||||
logs, err := c.client.FilterLogs(ctx, query)
|
||||
if err != nil {
|
||||
log.Error("Failed to filter L2 event logs", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
l2WithdrawMessages, l2RelayedMessages, err := logic.ParseL2EventLogs(logs, blockTimestampsMap)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L2 event logs", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
l2RelayedMessages = append(l2RelayedMessages, l2RevertedRelayedMessages...)
|
||||
|
||||
if err = c.updateL2WithdrawMessageProofs(ctx, l2WithdrawMessages); err != nil {
|
||||
log.Error("failed to update withdraw message proofs", "err", err)
|
||||
}
|
||||
|
||||
err = c.db.Transaction(func(tx *gorm.DB) error {
|
||||
if txErr := c.crossMessageOrm.InsertOrUpdateL2Messages(ctx, l2WithdrawMessages, tx); txErr != nil {
|
||||
log.Error("failed to insert L2 withdrawal messages", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
if txErr := c.crossMessageOrm.InsertOrUpdateL2RelayedMessagesOfL1Deposits(ctx, l2RelayedMessages, tx); txErr != nil {
|
||||
log.Error("failed to update L2 relayed messages of L1 deposits", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
if txErr := c.crossMessageOrm.InsertFailedGatewayRouterTxs(ctx, l2FailedGatewayRouterTxs, tx); txErr != nil {
|
||||
log.Error("failed to insert L2 failed gateway router transactions", "from", from, "to", to, "err", txErr)
|
||||
return txErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("failed to update db of L2 events", "from", from, "to", to, "err", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *L2MessageFetcher) updateL2WithdrawMessageProofs(ctx context.Context, l2WithdrawMessages []*orm.CrossMessage) error {
|
||||
withdrawTrie := utils.NewWithdrawTrie()
|
||||
message, err := c.crossMessageOrm.GetLatestL2Withdrawal(ctx)
|
||||
if err != nil {
|
||||
log.Error("failed to get latest L2 sent message event", "err", err)
|
||||
return err
|
||||
}
|
||||
if message != nil {
|
||||
withdrawTrie.Initialize(message.MessageNonce, common.HexToHash(message.MessageHash), message.MerkleProof)
|
||||
}
|
||||
messageHashes := make([]common.Hash, len(l2WithdrawMessages))
|
||||
for i, message := range l2WithdrawMessages {
|
||||
messageHashes[i] = common.HexToHash(message.MessageHash)
|
||||
}
|
||||
proofs := withdrawTrie.AppendMessages(messageHashes)
|
||||
if len(l2WithdrawMessages) != len(proofs) {
|
||||
log.Error("invalid proof array length", "L2 withdrawal messages length", len(l2WithdrawMessages), "proofs length", len(proofs))
|
||||
return fmt.Errorf("invalid proof array length: got %d proofs for %d l2WithdrawMessages", len(proofs), len(l2WithdrawMessages))
|
||||
}
|
||||
for i, proof := range proofs {
|
||||
l2WithdrawMessages[i].MerkleProof = proof
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// EventUpdateLogic the logic of insert/update the database
|
||||
type EventUpdateLogic struct {
|
||||
db *gorm.DB
|
||||
crossMessageOrm *orm.CrossMessage
|
||||
batchEventOrm *orm.BatchEvent
|
||||
|
||||
eventUpdateLogicL1FinalizeBatchEventL2BlockUpdateHeight prometheus.Gauge
|
||||
eventUpdateLogicL2MessageNonceUpdateHeight prometheus.Gauge
|
||||
}
|
||||
|
||||
// NewEventUpdateLogic creates a EventUpdateLogic instance
|
||||
func NewEventUpdateLogic(db *gorm.DB, isL1 bool) *EventUpdateLogic {
|
||||
b := &EventUpdateLogic{
|
||||
db: db,
|
||||
crossMessageOrm: orm.NewCrossMessage(db),
|
||||
batchEventOrm: orm.NewBatchEvent(db),
|
||||
}
|
||||
|
||||
if !isL1 {
|
||||
reg := prometheus.DefaultRegisterer
|
||||
b.eventUpdateLogicL1FinalizeBatchEventL2BlockUpdateHeight = promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "event_update_logic_L1_finalize_batch_event_L2_block_update_height",
|
||||
Help: "L2 block height of the latest L1 batch event that has been finalized and updated in the message_table.",
|
||||
})
|
||||
b.eventUpdateLogicL2MessageNonceUpdateHeight = promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "event_update_logic_L2_message_nonce_update_height",
|
||||
Help: "L2 message nonce height in the latest L1 batch event that has been finalized and updated in the message_table.",
|
||||
})
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// GetL1SyncHeight gets the l1 sync height from db
|
||||
func (b *EventUpdateLogic) GetL1SyncHeight(ctx context.Context) (uint64, uint64, error) {
|
||||
messageSyncedHeight, err := b.crossMessageOrm.GetMessageSyncedHeightInDB(ctx, orm.MessageTypeL1SentMessage)
|
||||
if err != nil {
|
||||
log.Error("failed to get L1 cross message synced height", "error", err)
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
batchSyncedHeight, err := b.batchEventOrm.GetBatchEventSyncedHeightInDB(ctx)
|
||||
if err != nil {
|
||||
log.Error("failed to get L1 batch event synced height", "error", err)
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return messageSyncedHeight, batchSyncedHeight, nil
|
||||
}
|
||||
|
||||
// GetL2MessageSyncedHeightInDB gets L2 messages synced height
|
||||
func (b *EventUpdateLogic) GetL2MessageSyncedHeightInDB(ctx context.Context) (uint64, error) {
|
||||
l2SentMessageSyncedHeight, err := b.crossMessageOrm.GetMessageSyncedHeightInDB(ctx, orm.MessageTypeL2SentMessage)
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 cross message processed height", "err", err)
|
||||
return 0, err
|
||||
}
|
||||
return l2SentMessageSyncedHeight, nil
|
||||
}
|
||||
|
||||
// L1InsertOrUpdate inserts or updates l1 messages
|
||||
func (b *EventUpdateLogic) L1InsertOrUpdate(ctx context.Context, l1FetcherResult *L1FilterResult) error {
|
||||
if err := b.crossMessageOrm.InsertOrUpdateL1Messages(ctx, l1FetcherResult.DepositMessages); err != nil {
|
||||
log.Error("failed to insert L1 deposit messages", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.crossMessageOrm.InsertOrUpdateL1RelayedMessagesOfL2Withdrawals(ctx, l1FetcherResult.RelayedMessages); err != nil {
|
||||
log.Error("failed to update L1 relayed messages of L2 withdrawals", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.batchEventOrm.InsertOrUpdateBatchEvents(ctx, l1FetcherResult.BatchEvents); err != nil {
|
||||
log.Error("failed to insert or update batch events", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.crossMessageOrm.UpdateL1MessageQueueEventsInfo(ctx, l1FetcherResult.MessageQueueEvents); err != nil {
|
||||
log.Error("failed to insert L1 message queue events", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.crossMessageOrm.InsertFailedL1GatewayTxs(ctx, l1FetcherResult.RevertedTxs); err != nil {
|
||||
log.Error("failed to insert failed L1 gateway transactions", "err", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *EventUpdateLogic) updateL2WithdrawMessageInfos(ctx context.Context, batchIndex, startBlock, endBlock uint64) error {
|
||||
l2WithdrawMessages, err := b.crossMessageOrm.GetL2WithdrawalsByBlockRange(ctx, startBlock, endBlock)
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 withdrawals by batch index", "batch index", batchIndex, "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(l2WithdrawMessages) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
withdrawTrie := utils.NewWithdrawTrie()
|
||||
lastMessage, err := b.crossMessageOrm.GetL2LatestFinalizedWithdrawal(ctx)
|
||||
if err != nil {
|
||||
log.Error("failed to get latest L2 finalized sent message event", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if lastMessage != nil {
|
||||
withdrawTrie.Initialize(lastMessage.MessageNonce, common.HexToHash(lastMessage.MessageHash), lastMessage.MerkleProof)
|
||||
}
|
||||
|
||||
if withdrawTrie.NextMessageNonce != l2WithdrawMessages[0].MessageNonce {
|
||||
log.Error("nonce mismatch", "expected next message nonce", withdrawTrie.NextMessageNonce, "actuall next message nonce", l2WithdrawMessages[0].MessageNonce)
|
||||
return fmt.Errorf("nonce mismatch")
|
||||
}
|
||||
|
||||
messageHashes := make([]common.Hash, len(l2WithdrawMessages))
|
||||
for i, message := range l2WithdrawMessages {
|
||||
messageHashes[i] = common.HexToHash(message.MessageHash)
|
||||
}
|
||||
|
||||
proofs := withdrawTrie.AppendMessages(messageHashes)
|
||||
|
||||
for i, message := range l2WithdrawMessages {
|
||||
message.MerkleProof = proofs[i]
|
||||
message.RollupStatus = int(orm.RollupStatusTypeFinalized)
|
||||
message.BatchIndex = batchIndex
|
||||
}
|
||||
|
||||
if dbErr := b.crossMessageOrm.UpdateBatchIndexRollupStatusMerkleProofOfL2Messages(ctx, l2WithdrawMessages); dbErr != nil {
|
||||
log.Error("failed to update batch index and rollup status and merkle proof of L2 messages", "err", dbErr)
|
||||
return dbErr
|
||||
}
|
||||
|
||||
b.eventUpdateLogicL2MessageNonceUpdateHeight.Set(float64(withdrawTrie.NextMessageNonce - 1))
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateL1BatchIndexAndStatus updates L1 finalized batch index and status
|
||||
func (b *EventUpdateLogic) UpdateL1BatchIndexAndStatus(ctx context.Context, height uint64) error {
|
||||
finalizedBatches, err := b.batchEventOrm.GetFinalizedBatchesLEBlockHeight(ctx, height)
|
||||
if err != nil {
|
||||
log.Error("failed to get batches >= block height", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, finalizedBatch := range finalizedBatches {
|
||||
log.Info("update finalized batch info of L2 withdrawals", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber)
|
||||
if updateErr := b.updateL2WithdrawMessageInfos(ctx, finalizedBatch.BatchIndex, finalizedBatch.StartBlockNumber, finalizedBatch.EndBlockNumber); updateErr != nil {
|
||||
log.Error("failed to update L2 withdraw message infos", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", updateErr)
|
||||
return updateErr
|
||||
}
|
||||
if dbErr := b.batchEventOrm.UpdateBatchEventStatus(ctx, finalizedBatch.BatchIndex); dbErr != nil {
|
||||
log.Error("failed to update batch event status as updated", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", dbErr)
|
||||
return dbErr
|
||||
}
|
||||
b.eventUpdateLogicL1FinalizeBatchEventL2BlockUpdateHeight.Set(float64(finalizedBatch.EndBlockNumber))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// L2InsertOrUpdate inserts or updates L2 messages
|
||||
func (b *EventUpdateLogic) L2InsertOrUpdate(ctx context.Context, l2FetcherResult *L2FilterResult) error {
|
||||
if err := b.crossMessageOrm.InsertOrUpdateL2Messages(ctx, l2FetcherResult.WithdrawMessages); err != nil {
|
||||
log.Error("failed to insert L2 withdrawal messages", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.crossMessageOrm.InsertOrUpdateL2RelayedMessagesOfL1Deposits(ctx, l2FetcherResult.RelayedMessages); err != nil {
|
||||
log.Error("failed to update L2 relayed messages of L1 deposits", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.crossMessageOrm.InsertFailedL2GatewayTxs(ctx, l2FetcherResult.OtherRevertedTxs); err != nil {
|
||||
log.Error("failed to insert failed L2 gateway transactions", "err", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -16,20 +16,13 @@ import (
|
||||
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/types"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
// cacheKeyPrefixBridgeHistory serves as a specific namespace for all Redis cache keys
|
||||
// associated with the 'bridge-history' user. This prefix is used to enforce access controls
|
||||
// in Redis, allowing permissions to be set such that only users with the appropriate
|
||||
// access rights can read or write to keys starting with "bridge-history".
|
||||
cacheKeyPrefixBridgeHistory = "bridge-history-"
|
||||
|
||||
cacheKeyPrefixL2ClaimableWithdrawalsByAddr = cacheKeyPrefixBridgeHistory + "l2ClaimableWithdrawalsByAddr:"
|
||||
cacheKeyPrefixL2WithdrawalsByAddr = cacheKeyPrefixBridgeHistory + "l2WithdrawalsByAddr:"
|
||||
cacheKeyPrefixTxsByAddr = cacheKeyPrefixBridgeHistory + "txsByAddr:"
|
||||
cacheKeyPrefixQueryTxsByHashes = cacheKeyPrefixBridgeHistory + "queryTxsByHashes:"
|
||||
cacheKeyPrefixL2ClaimableWithdrawalsByAddr = "l2ClaimableWithdrawalsByAddr:"
|
||||
cacheKeyPrefixL2WithdrawalsByAddr = "l2WithdrawalsByAddr:"
|
||||
cacheKeyPrefixTxsByAddr = "txsByAddr:"
|
||||
cacheKeyPrefixQueryTxsByHashes = "queryTxsByHashes:"
|
||||
cacheKeyExpiredTime = 1 * time.Minute
|
||||
)
|
||||
|
||||
@@ -53,8 +46,8 @@ func NewHistoryLogic(db *gorm.DB, redis *redis.Client) *HistoryLogic {
|
||||
return logic
|
||||
}
|
||||
|
||||
// GetL2UnclaimedWithdrawalsByAddress gets all unclaimed withdrawal txs under given address.
|
||||
func (h *HistoryLogic) GetL2UnclaimedWithdrawalsByAddress(ctx context.Context, address string, page, pageSize uint64) ([]*types.TxHistoryInfo, uint64, error) {
|
||||
// GetL2ClaimableWithdrawalsByAddress gets all claimable withdrawal txs under given address.
|
||||
func (h *HistoryLogic) GetL2ClaimableWithdrawalsByAddress(ctx context.Context, address string, page, pageSize uint64) ([]*types.TxHistoryInfo, uint64, error) {
|
||||
cacheKey := cacheKeyPrefixL2ClaimableWithdrawalsByAddr + address
|
||||
pagedTxs, total, isHit, err := h.getCachedTxsInfo(ctx, cacheKey, page, pageSize)
|
||||
if err != nil {
|
||||
@@ -63,24 +56,24 @@ func (h *HistoryLogic) GetL2UnclaimedWithdrawalsByAddress(ctx context.Context, a
|
||||
}
|
||||
|
||||
if isHit {
|
||||
h.cacheMetrics.cacheHits.WithLabelValues("GetL2UnclaimedWithdrawalsByAddress").Inc()
|
||||
h.cacheMetrics.cacheHits.WithLabelValues("GetL2ClaimableWithdrawalsByAddress").Inc()
|
||||
log.Info("cache hit", "cache key", cacheKey)
|
||||
return pagedTxs, total, nil
|
||||
}
|
||||
|
||||
h.cacheMetrics.cacheMisses.WithLabelValues("GetL2UnclaimedWithdrawalsByAddress").Inc()
|
||||
h.cacheMetrics.cacheMisses.WithLabelValues("GetL2ClaimableWithdrawalsByAddress").Inc()
|
||||
log.Info("cache miss", "cache key", cacheKey)
|
||||
|
||||
result, err, _ := h.singleFlight.Do(cacheKey, func() (interface{}, error) {
|
||||
var messages []*orm.CrossMessage
|
||||
messages, err = h.crossMessageOrm.GetL2UnclaimedWithdrawalsByAddress(ctx, address)
|
||||
messages, err = h.crossMessageOrm.GetL2ClaimableWithdrawalsByAddress(ctx, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return messages, nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 claimable withdrawals by address", "address", address, "error", err)
|
||||
log.Error("failed to get l2 claimable withdrawals by address", "address", address, "error", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
@@ -120,7 +113,7 @@ func (h *HistoryLogic) GetL2WithdrawalsByAddress(ctx context.Context, address st
|
||||
return messages, nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 withdrawals by address", "address", address, "error", err)
|
||||
log.Error("failed to get l2 withdrawals by address", "address", address, "error", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
@@ -178,7 +171,6 @@ func (h *HistoryLogic) GetTxsByHashes(ctx context.Context, txHashes []string) ([
|
||||
hashesMap := make(map[string]struct{}, len(txHashes))
|
||||
results := make([]*types.TxHistoryInfo, 0, len(txHashes))
|
||||
uncachedHashes := make([]string, 0, len(txHashes))
|
||||
|
||||
for _, hash := range txHashes {
|
||||
if _, exists := hashesMap[hash]; exists {
|
||||
// Skip duplicate tx hash values.
|
||||
@@ -188,33 +180,28 @@ func (h *HistoryLogic) GetTxsByHashes(ctx context.Context, txHashes []string) ([
|
||||
|
||||
cacheKey := cacheKeyPrefixQueryTxsByHashes + hash
|
||||
cachedData, err := h.redis.Get(ctx, cacheKey).Bytes()
|
||||
if err != nil && errors.Is(err, redis.Nil) {
|
||||
if err == nil {
|
||||
h.cacheMetrics.cacheHits.WithLabelValues("PostQueryTxsByHashes").Inc()
|
||||
log.Info("cache hit", "cache key", cacheKey)
|
||||
if len(cachedData) == 0 {
|
||||
continue
|
||||
} else {
|
||||
var txInfo types.TxHistoryInfo
|
||||
if err = json.Unmarshal(cachedData, &txInfo); err != nil {
|
||||
log.Error("failed to unmarshal cached data", "error", err)
|
||||
uncachedHashes = append(uncachedHashes, hash)
|
||||
} else {
|
||||
results = append(results, &txInfo)
|
||||
}
|
||||
}
|
||||
} else if err == redis.Nil {
|
||||
h.cacheMetrics.cacheMisses.WithLabelValues("PostQueryTxsByHashes").Inc()
|
||||
log.Info("cache miss", "cache key", cacheKey)
|
||||
uncachedHashes = append(uncachedHashes, hash)
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
} else {
|
||||
log.Error("failed to get data from Redis", "error", err)
|
||||
uncachedHashes = append(uncachedHashes, hash)
|
||||
continue
|
||||
}
|
||||
|
||||
h.cacheMetrics.cacheHits.WithLabelValues("PostQueryTxsByHashes").Inc()
|
||||
log.Info("cache hit", "cache key", cacheKey)
|
||||
|
||||
if len(cachedData) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var txInfo types.TxHistoryInfo
|
||||
if unmarshalErr := json.Unmarshal(cachedData, &txInfo); unmarshalErr != nil {
|
||||
log.Error("failed to unmarshal cached data", "error", unmarshalErr)
|
||||
uncachedHashes = append(uncachedHashes, hash)
|
||||
continue
|
||||
}
|
||||
results = append(results, &txInfo)
|
||||
}
|
||||
|
||||
if len(uncachedHashes) > 0 {
|
||||
@@ -238,22 +225,20 @@ func (h *HistoryLogic) GetTxsByHashes(ctx context.Context, txHashes []string) ([
|
||||
for _, hash := range uncachedHashes {
|
||||
cacheKey := cacheKeyPrefixQueryTxsByHashes + hash
|
||||
result, found := resultMap[hash]
|
||||
if !found {
|
||||
// tx hash not found, which is also a valid result, cache empty string.
|
||||
if cacheErr := h.redis.Set(ctx, cacheKey, "", cacheKeyExpiredTime).Err(); cacheErr != nil {
|
||||
log.Error("failed to set data to Redis", "error", cacheErr)
|
||||
if found {
|
||||
jsonData, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
log.Error("failed to marshal data", "error", err)
|
||||
} else {
|
||||
if err := h.redis.Set(ctx, cacheKey, jsonData, cacheKeyExpiredTime).Err(); err != nil {
|
||||
log.Error("failed to set data to Redis", "error", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// tx hash not found, which is also a valid result, cache empty string.
|
||||
if err := h.redis.Set(ctx, cacheKey, "", cacheKeyExpiredTime).Err(); err != nil {
|
||||
log.Error("failed to set data to Redis", "error", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
jsonData, unmarshalErr := json.Marshal(result)
|
||||
if unmarshalErr != nil {
|
||||
log.Error("failed to marshal data", "error", unmarshalErr)
|
||||
continue
|
||||
}
|
||||
|
||||
if cacheErr := h.redis.Set(ctx, cacheKey, jsonData, cacheKeyExpiredTime).Err(); cacheErr != nil {
|
||||
log.Error("failed to set data to Redis", "error", cacheErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,44 +247,37 @@ func (h *HistoryLogic) GetTxsByHashes(ctx context.Context, txHashes []string) ([
|
||||
|
||||
func getTxHistoryInfo(message *orm.CrossMessage) *types.TxHistoryInfo {
|
||||
txHistory := &types.TxHistoryInfo{
|
||||
MessageHash: message.MessageHash,
|
||||
TokenType: orm.TokenType(message.TokenType),
|
||||
TokenIDs: utils.ConvertStringToStringArray(message.TokenIDs),
|
||||
TokenAmounts: utils.ConvertStringToStringArray(message.TokenAmounts),
|
||||
L1TokenAddress: message.L1TokenAddress,
|
||||
L2TokenAddress: message.L2TokenAddress,
|
||||
MessageType: orm.MessageType(message.MessageType),
|
||||
TxStatus: orm.TxStatusType(message.TxStatus),
|
||||
BlockTimestamp: message.BlockTimestamp,
|
||||
MsgHash: message.MessageHash,
|
||||
Amount: message.TokenAmounts,
|
||||
L1Token: message.L1TokenAddress,
|
||||
L2Token: message.L2TokenAddress,
|
||||
IsL1: orm.MessageType(message.MessageType) == orm.MessageTypeL1SentMessage,
|
||||
TxStatus: message.TxStatus,
|
||||
CreatedAt: &message.CreatedAt,
|
||||
}
|
||||
if txHistory.MessageType == orm.MessageTypeL1SentMessage {
|
||||
if txHistory.IsL1 {
|
||||
txHistory.Hash = message.L1TxHash
|
||||
txHistory.ReplayTxHash = message.L1ReplayTxHash
|
||||
txHistory.RefundTxHash = message.L1RefundTxHash
|
||||
txHistory.BlockNumber = message.L1BlockNumber
|
||||
txHistory.CounterpartChainTx = &types.CounterpartChainTx{
|
||||
txHistory.FinalizeTx = &types.Finalized{
|
||||
Hash: message.L2TxHash,
|
||||
BlockNumber: message.L2BlockNumber,
|
||||
}
|
||||
} else {
|
||||
txHistory.Hash = message.L2TxHash
|
||||
txHistory.BlockNumber = message.L2BlockNumber
|
||||
txHistory.CounterpartChainTx = &types.CounterpartChainTx{
|
||||
txHistory.FinalizeTx = &types.Finalized{
|
||||
Hash: message.L1TxHash,
|
||||
BlockNumber: message.L1BlockNumber,
|
||||
}
|
||||
if orm.RollupStatusType(message.RollupStatus) == orm.RollupStatusTypeFinalized {
|
||||
txHistory.ClaimInfo = &types.ClaimInfo{
|
||||
From: message.MessageFrom,
|
||||
To: message.MessageTo,
|
||||
Value: message.MessageValue,
|
||||
Nonce: strconv.FormatUint(message.MessageNonce, 10),
|
||||
Message: message.MessageData,
|
||||
Proof: types.L2MessageProof{
|
||||
BatchIndex: strconv.FormatUint(message.BatchIndex, 10),
|
||||
MerkleProof: "0x" + common.Bytes2Hex(message.MerkleProof),
|
||||
},
|
||||
Claimable: true,
|
||||
txHistory.ClaimInfo = &types.UserClaimInfo{
|
||||
From: message.MessageFrom,
|
||||
To: message.MessageTo,
|
||||
Value: message.MessageValue,
|
||||
Nonce: strconv.FormatUint(message.MessageNonce, 10),
|
||||
Message: message.MessageData,
|
||||
Proof: common.Bytes2Hex(message.MerkleProof),
|
||||
BatchIndex: strconv.FormatUint(message.BatchIndex, 10),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,40 +285,36 @@ func getTxHistoryInfo(message *orm.CrossMessage) *types.TxHistoryInfo {
|
||||
}
|
||||
|
||||
func (h *HistoryLogic) getCachedTxsInfo(ctx context.Context, cacheKey string, pageNum, pageSize uint64) ([]*types.TxHistoryInfo, uint64, bool, error) {
|
||||
start := int64((pageNum - 1) * pageSize)
|
||||
end := start + int64(pageSize) - 1
|
||||
start := int64(pageNum * pageSize)
|
||||
end := int64((pageNum+1)*pageSize - 1)
|
||||
|
||||
total, err := h.redis.ZCard(ctx, cacheKey).Result()
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
// Key does not exist, cache miss.
|
||||
return nil, 0, false, nil
|
||||
}
|
||||
log.Error("failed to get zcard result", "error", err)
|
||||
return nil, 0, false, err
|
||||
}
|
||||
|
||||
if total == 0 {
|
||||
return nil, 0, false, nil
|
||||
}
|
||||
|
||||
values, err := h.redis.ZRange(ctx, cacheKey, start, end).Result()
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
// Key does not exist, cache miss.
|
||||
return nil, 0, false, nil
|
||||
}
|
||||
log.Error("failed to get zrange result", "error", err)
|
||||
return nil, 0, false, err
|
||||
}
|
||||
|
||||
if len(values) == 0 {
|
||||
return nil, 0, false, nil
|
||||
}
|
||||
|
||||
// check if it's empty placeholder.
|
||||
if len(values) == 1 && values[0] == "empty_page" {
|
||||
return nil, 0, true, nil
|
||||
}
|
||||
|
||||
var pagedTxs []*types.TxHistoryInfo
|
||||
for _, v := range values {
|
||||
var tx types.TxHistoryInfo
|
||||
if unmarshalErr := json.Unmarshal([]byte(v), &tx); unmarshalErr != nil {
|
||||
log.Error("failed to unmarshal transaction data", "error", unmarshalErr)
|
||||
return nil, 0, false, unmarshalErr
|
||||
err := json.Unmarshal([]byte(v), &tx)
|
||||
if err != nil {
|
||||
log.Error("failed to unmarshal transaction data", "error", err)
|
||||
return nil, 0, false, err
|
||||
}
|
||||
pagedTxs = append(pagedTxs, &tx)
|
||||
}
|
||||
@@ -349,24 +323,12 @@ func (h *HistoryLogic) getCachedTxsInfo(ctx context.Context, cacheKey string, pa
|
||||
|
||||
func (h *HistoryLogic) cacheTxsInfo(ctx context.Context, cacheKey string, txs []*types.TxHistoryInfo) error {
|
||||
_, err := h.redis.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
|
||||
if len(txs) == 0 {
|
||||
if err := pipe.ZAdd(ctx, cacheKey, &redis.Z{Score: 0, Member: "empty_page"}).Err(); err != nil {
|
||||
log.Error("failed to add empty page indicator to sorted set", "error", err)
|
||||
// The transactions are sorted, thus we set the score as their indices.
|
||||
for i, tx := range txs {
|
||||
if err := pipe.ZAdd(ctx, cacheKey, &redis.Z{Score: float64(i), Member: tx}).Err(); err != nil {
|
||||
log.Error("failed to add transaction to sorted set", "error", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// The transactions are sorted, thus we set the score as their indices.
|
||||
for i, tx := range txs {
|
||||
txBytes, err := json.Marshal(tx)
|
||||
if err != nil {
|
||||
log.Error("failed to marshal transaction to json", "error", err)
|
||||
return err
|
||||
}
|
||||
if err := pipe.ZAdd(ctx, cacheKey, &redis.Z{Score: float64(i), Member: txBytes}).Err(); err != nil {
|
||||
log.Error("failed to add transaction to sorted set", "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := pipe.Expire(ctx, cacheKey, cacheKeyExpiredTime).Err(); err != nil {
|
||||
log.Error("failed to set expiry time", "error", err)
|
||||
@@ -374,6 +336,7 @@ func (h *HistoryLogic) cacheTxsInfo(ctx context.Context, cacheKey string, txs []
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Error("failed to execute transaction", "error", err)
|
||||
return err
|
||||
|
||||
@@ -1,320 +0,0 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
"scroll-tech/bridge-history-api/internal/config"
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// L1EventParser the l1 event parser
|
||||
type L1EventParser struct {
|
||||
cfg *config.FetcherConfig
|
||||
client *ethclient.Client
|
||||
}
|
||||
|
||||
// NewL1EventParser creates l1 event parser
|
||||
func NewL1EventParser(cfg *config.FetcherConfig, client *ethclient.Client) *L1EventParser {
|
||||
return &L1EventParser{
|
||||
cfg: cfg,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseL1CrossChainEventLogs parses L1 watched cross chain events.
|
||||
func (e *L1EventParser) ParseL1CrossChainEventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64) ([]*orm.CrossMessage, []*orm.CrossMessage, error) {
|
||||
var l1DepositMessages []*orm.CrossMessage
|
||||
var l1RelayedMessages []*orm.CrossMessage
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L1DepositETHSig:
|
||||
event := backendabi.ETHMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ETHGatewayABI, &event, "DepositETH", vlog); err != nil {
|
||||
log.Error("Failed to unpack DepositETH event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeETH)
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
case backendabi.L1DepositERC20Sig:
|
||||
event := backendabi.ERC20MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL1ERC20GatewayABI, &event, "DepositERC20", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack DepositERC20 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC20)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
case backendabi.L1DepositERC721Sig:
|
||||
event := backendabi.ERC721MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC721GatewayABI, &event, "DepositERC721", vlog); err != nil {
|
||||
log.Error("Failed to unpack DepositERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
case backendabi.L1BatchDepositERC721Sig:
|
||||
event := backendabi.BatchERC721MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC721GatewayABI, &event, "BatchDepositERC721", vlog); err != nil {
|
||||
log.Error("Failed to unpack BatchDepositERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = utils.ConvertBigIntArrayToString(event.TokenIDs)
|
||||
case backendabi.L1DepositERC1155Sig:
|
||||
event := backendabi.ERC1155MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC1155GatewayABI, &event, "DepositERC1155", vlog); err != nil {
|
||||
log.Error("Failed to unpack DepositERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
case backendabi.L1BatchDepositERC1155Sig:
|
||||
event := backendabi.BatchERC1155MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC1155GatewayABI, &event, "BatchDepositERC1155", vlog); err != nil {
|
||||
log.Error("Failed to unpack BatchDepositERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = utils.ConvertBigIntArrayToString(event.TokenIDs)
|
||||
lastMessage.TokenAmounts = utils.ConvertBigIntArrayToString(event.TokenAmounts)
|
||||
case backendabi.L1SentMessageEventSig:
|
||||
event := backendabi.L1SentMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "SentMessage", vlog); err != nil {
|
||||
log.Error("Failed to unpack SentMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
from, err := getRealFromAddress(ctx, event.Sender, event.Message, e.client, vlog.TxHash, e.cfg.GatewayRouterAddr)
|
||||
if err != nil {
|
||||
log.Error("Failed to get real 'from' address", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l1DepositMessages = append(l1DepositMessages, &orm.CrossMessage{
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
Sender: from,
|
||||
Receiver: event.Target.String(),
|
||||
TokenType: int(orm.TokenTypeETH),
|
||||
L1TxHash: vlog.TxHash.String(),
|
||||
TokenAmounts: event.Value.String(),
|
||||
MessageNonce: event.MessageNonce.Uint64(),
|
||||
MessageType: int(orm.MessageTypeL1SentMessage),
|
||||
TxStatus: int(orm.TxStatusTypeSent),
|
||||
BlockTimestamp: blockTimestampsMap[vlog.BlockNumber],
|
||||
MessageHash: utils.ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message).String(),
|
||||
})
|
||||
case backendabi.L1RelayedMessageEventSig:
|
||||
event := backendabi.L1RelayedMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "RelayedMessage", vlog); err != nil {
|
||||
log.Error("Failed to unpack RelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l1RelayedMessages = append(l1RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
L1TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayed),
|
||||
MessageType: int(orm.MessageTypeL2SentMessage),
|
||||
})
|
||||
case backendabi.L1FailedRelayedMessageEventSig:
|
||||
event := backendabi.L1FailedRelayedMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "FailedRelayedMessage", vlog); err != nil {
|
||||
log.Error("Failed to unpack FailedRelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l1RelayedMessages = append(l1RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
L1TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeFailedRelayed),
|
||||
MessageType: int(orm.MessageTypeL2SentMessage),
|
||||
})
|
||||
}
|
||||
}
|
||||
return l1DepositMessages, l1RelayedMessages, nil
|
||||
}
|
||||
|
||||
// ParseL1BatchEventLogs parses L1 watched batch events.
|
||||
func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types.Log, client *ethclient.Client) ([]*orm.BatchEvent, error) {
|
||||
var l1BatchEvents []*orm.BatchEvent
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L1CommitBatchEventSig:
|
||||
event := backendabi.L1CommitBatchEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "CommitBatch", vlog); err != nil {
|
||||
log.Error("Failed to unpack CommitBatch event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
commitTx, isPending, err := client.TransactionByHash(ctx, vlog.TxHash)
|
||||
if err != nil || isPending {
|
||||
log.Error("Failed to get commit batch tx or the tx is still pending", "err", err, "isPending", isPending)
|
||||
return nil, err
|
||||
}
|
||||
startBlock, endBlock, err := utils.GetBatchRangeFromCalldata(commitTx.Data())
|
||||
if err != nil {
|
||||
log.Error("Failed to get batch range from calldata", "hash", commitTx.Hash().String(), "height", vlog.BlockNumber)
|
||||
return nil, err
|
||||
}
|
||||
l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{
|
||||
BatchStatus: int(orm.BatchStatusTypeCommitted),
|
||||
BatchIndex: event.BatchIndex.Uint64(),
|
||||
BatchHash: event.BatchHash.String(),
|
||||
StartBlockNumber: startBlock,
|
||||
EndBlockNumber: endBlock,
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
})
|
||||
case backendabi.L1RevertBatchEventSig:
|
||||
event := backendabi.L1RevertBatchEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "RevertBatch", vlog); err != nil {
|
||||
log.Error("Failed to unpack RevertBatch event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{
|
||||
BatchStatus: int(orm.BatchStatusTypeReverted),
|
||||
BatchIndex: event.BatchIndex.Uint64(),
|
||||
BatchHash: event.BatchHash.String(),
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
})
|
||||
case backendabi.L1FinalizeBatchEventSig:
|
||||
event := backendabi.L1FinalizeBatchEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "FinalizeBatch", vlog); err != nil {
|
||||
log.Error("Failed to unpack FinalizeBatch event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{
|
||||
BatchStatus: int(orm.BatchStatusTypeFinalized),
|
||||
BatchIndex: event.BatchIndex.Uint64(),
|
||||
BatchHash: event.BatchHash.String(),
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
})
|
||||
}
|
||||
}
|
||||
return l1BatchEvents, nil
|
||||
}
|
||||
|
||||
// ParseL1MessageQueueEventLogs parses L1 watched message queue events.
|
||||
func (e *L1EventParser) ParseL1MessageQueueEventLogs(logs []types.Log, l1DepositMessages []*orm.CrossMessage) ([]*orm.MessageQueueEvent, error) {
|
||||
messageHashes := make(map[common.Hash]struct{})
|
||||
for _, msg := range l1DepositMessages {
|
||||
messageHashes[common.HexToHash(msg.MessageHash)] = struct{}{}
|
||||
}
|
||||
|
||||
var l1MessageQueueEvents []*orm.MessageQueueEvent
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L1QueueTransactionEventSig:
|
||||
event := backendabi.L1QueueTransactionEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "QueueTransaction", vlog); err != nil {
|
||||
log.Error("Failed to unpack QueueTransaction event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
messageHash := common.BytesToHash(crypto.Keccak256(event.Data))
|
||||
// If the message hash is not found in the map, it's not a replayMessage or enforced tx (omitted); add it to the events.
|
||||
if _, exists := messageHashes[messageHash]; !exists {
|
||||
l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{
|
||||
EventType: orm.MessageQueueEventTypeQueueTransaction,
|
||||
QueueIndex: event.QueueIndex,
|
||||
MessageHash: messageHash,
|
||||
TxHash: vlog.TxHash,
|
||||
})
|
||||
}
|
||||
case backendabi.L1DequeueTransactionEventSig:
|
||||
event := backendabi.L1DequeueTransactionEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "DequeueTransaction", vlog); err != nil {
|
||||
log.Error("Failed to unpack DequeueTransaction event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
skippedIndices := utils.GetSkippedQueueIndices(event.StartIndex.Uint64(), event.SkippedBitmap)
|
||||
for _, index := range skippedIndices {
|
||||
l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{
|
||||
EventType: orm.MessageQueueEventTypeDequeueTransaction,
|
||||
QueueIndex: index,
|
||||
})
|
||||
}
|
||||
case backendabi.L1DropTransactionEventSig:
|
||||
event := backendabi.L1DropTransactionEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "DropTransaction", vlog); err != nil {
|
||||
log.Error("Failed to unpack DropTransaction event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{
|
||||
EventType: orm.MessageQueueEventTypeDropTransaction,
|
||||
QueueIndex: event.Index.Uint64(),
|
||||
TxHash: vlog.TxHash,
|
||||
})
|
||||
}
|
||||
}
|
||||
return l1MessageQueueEvents, nil
|
||||
}
|
||||
|
||||
func getRealFromAddress(ctx context.Context, eventSender common.Address, eventMessage []byte, client *ethclient.Client, txHash common.Hash, gatewayRouterAddr string) (string, error) {
|
||||
if eventSender != common.HexToAddress(gatewayRouterAddr) {
|
||||
return eventSender.String(), nil
|
||||
}
|
||||
|
||||
// deposit/withdraw ETH: EOA -> contract 1 -> ... -> contract n -> gateway router -> messenger.
|
||||
if len(eventMessage) >= 32 {
|
||||
addressBytes := eventMessage[32-common.AddressLength : 32]
|
||||
var address common.Address
|
||||
address.SetBytes(addressBytes)
|
||||
|
||||
return address.Hex(), nil
|
||||
}
|
||||
|
||||
log.Warn("event message data too short to contain an address", "length", len(eventMessage))
|
||||
|
||||
// Legacy handling logic if length of message < 32, for backward compatibility before the next contract upgrade.
|
||||
tx, isPending, rpcErr := client.TransactionByHash(ctx, txHash)
|
||||
if rpcErr != nil || isPending {
|
||||
log.Error("Failed to get transaction or the transaction is still pending", "rpcErr", rpcErr, "isPending", isPending)
|
||||
return "", rpcErr
|
||||
}
|
||||
// Case 1: deposit/withdraw ETH: EOA -> multisig -> gateway router -> messenger.
|
||||
if tx.To() != nil && (*tx.To()).String() != gatewayRouterAddr {
|
||||
return (*tx.To()).String(), nil
|
||||
}
|
||||
// Case 2: deposit/withdraw ETH: EOA -> gateway router -> messenger.
|
||||
signer := types.LatestSignerForChainID(new(big.Int).SetUint64(tx.ChainId().Uint64()))
|
||||
sender, err := signer.Sender(tx)
|
||||
if err != nil {
|
||||
log.Error("Get sender failed", "chain id", tx.ChainId().Uint64(), "tx hash", tx.Hash().String(), "err", err)
|
||||
return "", err
|
||||
}
|
||||
return sender.String(), nil
|
||||
}
|
||||
@@ -1,335 +0,0 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/scroll-tech/go-ethereum"
|
||||
"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"
|
||||
"gorm.io/gorm"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
"scroll-tech/bridge-history-api/internal/config"
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// L1ReorgSafeDepth represents the number of block confirmations considered safe against L1 chain reorganizations.
|
||||
// Reorganizations at this depth under normal cases are extremely unlikely.
|
||||
const L1ReorgSafeDepth = 64
|
||||
|
||||
// L1FilterResult L1 fetcher result
|
||||
type L1FilterResult struct {
|
||||
DepositMessages []*orm.CrossMessage
|
||||
RelayedMessages []*orm.CrossMessage
|
||||
BatchEvents []*orm.BatchEvent
|
||||
MessageQueueEvents []*orm.MessageQueueEvent
|
||||
RevertedTxs []*orm.CrossMessage
|
||||
}
|
||||
|
||||
// L1FetcherLogic the L1 fetcher logic
|
||||
type L1FetcherLogic struct {
|
||||
cfg *config.FetcherConfig
|
||||
client *ethclient.Client
|
||||
addressList []common.Address
|
||||
gatewayList []common.Address
|
||||
parser *L1EventParser
|
||||
db *gorm.DB
|
||||
crossMessageOrm *orm.CrossMessage
|
||||
batchEventOrm *orm.BatchEvent
|
||||
|
||||
l1FetcherLogicFetchedTotal *prometheus.CounterVec
|
||||
}
|
||||
|
||||
// NewL1FetcherLogic creates L1 fetcher logic
|
||||
func NewL1FetcherLogic(cfg *config.FetcherConfig, db *gorm.DB, client *ethclient.Client) *L1FetcherLogic {
|
||||
addressList := []common.Address{
|
||||
common.HexToAddress(cfg.ETHGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.StandardERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.CustomERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.WETHGatewayAddr),
|
||||
common.HexToAddress(cfg.DAIGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.ERC721GatewayAddr),
|
||||
common.HexToAddress(cfg.ERC1155GatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessengerAddr),
|
||||
|
||||
common.HexToAddress(cfg.ScrollChainAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessageQueueAddr),
|
||||
}
|
||||
|
||||
gatewayList := []common.Address{
|
||||
common.HexToAddress(cfg.ETHGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.StandardERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.CustomERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.WETHGatewayAddr),
|
||||
common.HexToAddress(cfg.DAIGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.ERC721GatewayAddr),
|
||||
common.HexToAddress(cfg.ERC1155GatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessengerAddr),
|
||||
|
||||
common.HexToAddress(cfg.GatewayRouterAddr),
|
||||
}
|
||||
|
||||
// Optional erc20 gateways.
|
||||
if common.HexToAddress(cfg.USDCGatewayAddr) != (common.Address{}) {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.USDCGatewayAddr))
|
||||
gatewayList = append(gatewayList, common.HexToAddress(cfg.USDCGatewayAddr))
|
||||
}
|
||||
|
||||
if common.HexToAddress(cfg.LIDOGatewayAddr) != (common.Address{}) {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.LIDOGatewayAddr))
|
||||
gatewayList = append(gatewayList, common.HexToAddress(cfg.LIDOGatewayAddr))
|
||||
}
|
||||
|
||||
if common.HexToAddress(cfg.PufferGatewayAddr) != (common.Address{}) {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.PufferGatewayAddr))
|
||||
gatewayList = append(gatewayList, common.HexToAddress(cfg.PufferGatewayAddr))
|
||||
}
|
||||
|
||||
log.Info("L1 Fetcher configured with the following address list", "addresses", addressList, "gateways", gatewayList)
|
||||
|
||||
f := &L1FetcherLogic{
|
||||
db: db,
|
||||
crossMessageOrm: orm.NewCrossMessage(db),
|
||||
batchEventOrm: orm.NewBatchEvent(db),
|
||||
cfg: cfg,
|
||||
client: client,
|
||||
addressList: addressList,
|
||||
gatewayList: gatewayList,
|
||||
parser: NewL1EventParser(cfg, client),
|
||||
}
|
||||
|
||||
reg := prometheus.DefaultRegisterer
|
||||
f.l1FetcherLogicFetchedTotal = promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "L1_fetcher_logic_fetched_total",
|
||||
Help: "The total number of events or failed txs fetched in L1 fetcher logic.",
|
||||
}, []string{"type"})
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *L1FetcherLogic) getBlocksAndDetectReorg(ctx context.Context, from, to uint64, lastBlockHash common.Hash) (bool, uint64, common.Hash, []*types.Block, error) {
|
||||
blocks, err := utils.GetBlocksInRange(ctx, f.client, from, to)
|
||||
if err != nil {
|
||||
log.Error("failed to get L1 blocks in range", "from", from, "to", to, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
for _, block := range blocks {
|
||||
if block.ParentHash() != lastBlockHash {
|
||||
log.Warn("L1 reorg detected", "reorg height", block.NumberU64()-1, "expected hash", block.ParentHash().String(), "local hash", lastBlockHash.String())
|
||||
var resyncHeight uint64
|
||||
if block.NumberU64() > L1ReorgSafeDepth+1 {
|
||||
resyncHeight = block.NumberU64() - L1ReorgSafeDepth - 1
|
||||
}
|
||||
header, err := f.client.HeaderByNumber(ctx, new(big.Int).SetUint64(resyncHeight))
|
||||
if err != nil {
|
||||
log.Error("failed to get L1 header by number", "block number", resyncHeight, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
return true, resyncHeight, header.Hash(), nil, nil
|
||||
}
|
||||
lastBlockHash = block.Hash()
|
||||
}
|
||||
|
||||
return false, 0, lastBlockHash, blocks, nil
|
||||
}
|
||||
|
||||
func (f *L1FetcherLogic) getRevertedTxs(ctx context.Context, from, to uint64, blocks []*types.Block) (map[uint64]uint64, []*orm.CrossMessage, error) {
|
||||
var l1RevertedTxs []*orm.CrossMessage
|
||||
blockTimestampsMap := make(map[uint64]uint64)
|
||||
|
||||
for i := from; i <= to; i++ {
|
||||
block := blocks[i-from]
|
||||
blockTimestampsMap[block.NumberU64()] = block.Time()
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
// Gateways: L1 deposit.
|
||||
// Messenger: L1 deposit retry (replayMessage), L1 deposit refund (dropMessage), L2 withdrawal's claim (relayMessageWithProof).
|
||||
if !isTransactionToGateway(tx, f.gatewayList) {
|
||||
continue
|
||||
}
|
||||
|
||||
var receipt *types.Receipt
|
||||
receipt, receiptErr := f.client.TransactionReceipt(ctx, tx.Hash())
|
||||
if receiptErr != nil {
|
||||
log.Error("Failed to get transaction receipt", "txHash", tx.Hash().String(), "err", receiptErr)
|
||||
return nil, nil, receiptErr
|
||||
}
|
||||
|
||||
// Check if the transaction is failed
|
||||
if receipt.Status != types.ReceiptStatusFailed {
|
||||
continue
|
||||
}
|
||||
|
||||
signer := types.LatestSignerForChainID(new(big.Int).SetUint64(tx.ChainId().Uint64()))
|
||||
sender, senderErr := signer.Sender(tx)
|
||||
if senderErr != nil {
|
||||
log.Error("get sender failed", "chain id", tx.ChainId().Uint64(), "tx hash", tx.Hash().String(), "err", senderErr)
|
||||
return nil, nil, senderErr
|
||||
}
|
||||
|
||||
l1RevertedTxs = append(l1RevertedTxs, &orm.CrossMessage{
|
||||
L1TxHash: tx.Hash().String(),
|
||||
MessageType: int(orm.MessageTypeL1SentMessage),
|
||||
Sender: sender.String(),
|
||||
Receiver: (*tx.To()).String(),
|
||||
L1BlockNumber: receipt.BlockNumber.Uint64(),
|
||||
BlockTimestamp: block.Time(),
|
||||
TxStatus: int(orm.TxStatusTypeSentTxReverted),
|
||||
})
|
||||
}
|
||||
}
|
||||
return blockTimestampsMap, l1RevertedTxs, nil
|
||||
}
|
||||
|
||||
func (f *L1FetcherLogic) l1FetcherLogs(ctx context.Context, from, to uint64) ([]types.Log, error) {
|
||||
query := ethereum.FilterQuery{
|
||||
FromBlock: new(big.Int).SetUint64(from), // inclusive
|
||||
ToBlock: new(big.Int).SetUint64(to), // inclusive
|
||||
Addresses: f.addressList,
|
||||
Topics: make([][]common.Hash, 1),
|
||||
}
|
||||
|
||||
query.Topics[0] = make([]common.Hash, 13)
|
||||
query.Topics[0][0] = backendabi.L1DepositETHSig
|
||||
query.Topics[0][1] = backendabi.L1DepositERC20Sig
|
||||
query.Topics[0][2] = backendabi.L1DepositERC721Sig
|
||||
query.Topics[0][3] = backendabi.L1DepositERC1155Sig
|
||||
query.Topics[0][4] = backendabi.L1SentMessageEventSig
|
||||
query.Topics[0][5] = backendabi.L1RelayedMessageEventSig
|
||||
query.Topics[0][6] = backendabi.L1FailedRelayedMessageEventSig
|
||||
query.Topics[0][7] = backendabi.L1CommitBatchEventSig
|
||||
query.Topics[0][8] = backendabi.L1RevertBatchEventSig
|
||||
query.Topics[0][9] = backendabi.L1FinalizeBatchEventSig
|
||||
query.Topics[0][10] = backendabi.L1QueueTransactionEventSig
|
||||
query.Topics[0][11] = backendabi.L1DequeueTransactionEventSig
|
||||
query.Topics[0][12] = backendabi.L1DropTransactionEventSig
|
||||
|
||||
eventLogs, err := f.client.FilterLogs(ctx, query)
|
||||
if err != nil {
|
||||
log.Error("failed to filter L1 event logs", "from", from, "to", to, "err", err)
|
||||
return nil, err
|
||||
}
|
||||
return eventLogs, nil
|
||||
}
|
||||
|
||||
// L1Fetcher L1 fetcher
|
||||
func (f *L1FetcherLogic) L1Fetcher(ctx context.Context, from, to uint64, lastBlockHash common.Hash) (bool, uint64, common.Hash, *L1FilterResult, error) {
|
||||
log.Info("fetch and save L1 events", "from", from, "to", to)
|
||||
|
||||
isReorg, reorgHeight, blockHash, blocks, getErr := f.getBlocksAndDetectReorg(ctx, from, to, lastBlockHash)
|
||||
if getErr != nil {
|
||||
log.Error("L1Fetcher getBlocksAndDetectReorg failed", "from", from, "to", to, "error", getErr)
|
||||
return false, 0, common.Hash{}, nil, getErr
|
||||
}
|
||||
|
||||
if isReorg {
|
||||
return isReorg, reorgHeight, blockHash, nil, nil
|
||||
}
|
||||
|
||||
blockTimestampsMap, l1RevertedTxs, err := f.getRevertedTxs(ctx, from, to, blocks)
|
||||
if err != nil {
|
||||
log.Error("L1Fetcher getRevertedTxs failed", "from", from, "to", to, "error", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
eventLogs, err := f.l1FetcherLogs(ctx, from, to)
|
||||
if err != nil {
|
||||
log.Error("L1Fetcher l1FetcherLogs failed", "from", from, "to", to, "error", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
l1DepositMessages, l1RelayedMessages, err := f.parser.ParseL1CrossChainEventLogs(ctx, eventLogs, blockTimestampsMap)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L1 cross chain event logs", "from", from, "to", to, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
l1BatchEvents, err := f.parser.ParseL1BatchEventLogs(ctx, eventLogs, f.client)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L1 batch event logs", "from", from, "to", to, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
l1MessageQueueEvents, err := f.parser.ParseL1MessageQueueEventLogs(eventLogs, l1DepositMessages)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L1 message queue event logs", "from", from, "to", to, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
res := L1FilterResult{
|
||||
DepositMessages: l1DepositMessages,
|
||||
RelayedMessages: l1RelayedMessages,
|
||||
BatchEvents: l1BatchEvents,
|
||||
MessageQueueEvents: l1MessageQueueEvents,
|
||||
RevertedTxs: l1RevertedTxs,
|
||||
}
|
||||
|
||||
f.updateMetrics(res)
|
||||
|
||||
return false, 0, blockHash, &res, nil
|
||||
}
|
||||
|
||||
func (f *L1FetcherLogic) updateMetrics(res L1FilterResult) {
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_failed_gateway_router_transaction").Add(float64(len(res.RevertedTxs)))
|
||||
|
||||
for _, depositMessage := range res.DepositMessages {
|
||||
switch orm.TokenType(depositMessage.TokenType) {
|
||||
case orm.TokenTypeETH:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_deposit_eth").Add(1)
|
||||
case orm.TokenTypeERC20:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_deposit_erc20").Add(1)
|
||||
case orm.TokenTypeERC721:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_deposit_erc721").Add(1)
|
||||
case orm.TokenTypeERC1155:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_deposit_erc1155").Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
for _, relayedMessage := range res.RelayedMessages {
|
||||
switch orm.TxStatusType(relayedMessage.TxStatus) {
|
||||
case orm.TxStatusTypeRelayed:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_relayed_message").Add(1)
|
||||
case orm.TxStatusTypeFailedRelayed:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_failed_relayed_message").Add(1)
|
||||
}
|
||||
// Have not tracked L1 relayed message reverted transaction yet.
|
||||
// 1. need to parse calldata of tx.
|
||||
// 2. hard to track internal tx.
|
||||
}
|
||||
|
||||
for _, batchEvent := range res.BatchEvents {
|
||||
switch orm.BatchStatusType(batchEvent.BatchStatus) {
|
||||
case orm.BatchStatusTypeCommitted:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_commit_batch_event").Add(1)
|
||||
case orm.BatchStatusTypeReverted:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_revert_batch_event").Add(1)
|
||||
case orm.BatchStatusTypeFinalized:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_finalize_batch_event").Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
for _, messageQueueEvent := range res.MessageQueueEvents {
|
||||
switch messageQueueEvent.EventType {
|
||||
case orm.MessageQueueEventTypeQueueTransaction: // sendMessage is filtered out, only leaving replayMessage or appendEnforcedTransaction.
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_replay_message_or_enforced_transaction").Add(1)
|
||||
case orm.MessageQueueEventTypeDequeueTransaction:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_skip_message").Add(1)
|
||||
case orm.MessageQueueEventTypeDropTransaction:
|
||||
f.l1FetcherLogicFetchedTotal.WithLabelValues("L1_drop_message").Add(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
"scroll-tech/bridge-history-api/internal/config"
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// L2EventParser the L2 event parser
|
||||
type L2EventParser struct {
|
||||
cfg *config.FetcherConfig
|
||||
client *ethclient.Client
|
||||
}
|
||||
|
||||
// NewL2EventParser creates the L2 event parser
|
||||
func NewL2EventParser(cfg *config.FetcherConfig, client *ethclient.Client) *L2EventParser {
|
||||
return &L2EventParser{
|
||||
cfg: cfg,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseL2EventLogs parses L2 watched events
|
||||
func (e *L2EventParser) ParseL2EventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64) ([]*orm.CrossMessage, []*orm.CrossMessage, error) {
|
||||
var l2WithdrawMessages []*orm.CrossMessage
|
||||
var l2RelayedMessages []*orm.CrossMessage
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L2WithdrawETHSig:
|
||||
event := backendabi.ETHMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ETHGatewayABI, &event, "WithdrawETH", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack WithdrawETH event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeETH)
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
case backendabi.L2WithdrawERC20Sig:
|
||||
event := backendabi.ERC20MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC20GatewayABI, &event, "WithdrawERC20", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack WithdrawERC20 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC20)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
case backendabi.L2WithdrawERC721Sig:
|
||||
event := backendabi.ERC721MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC721GatewayABI, &event, "WithdrawERC721", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack WithdrawERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
case backendabi.L2BatchWithdrawERC721Sig:
|
||||
event := backendabi.BatchERC721MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC721GatewayABI, &event, "BatchWithdrawERC721", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack BatchWithdrawERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = utils.ConvertBigIntArrayToString(event.TokenIDs)
|
||||
case backendabi.L2WithdrawERC1155Sig:
|
||||
event := backendabi.ERC1155MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC1155GatewayABI, &event, "WithdrawERC1155", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack WithdrawERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
case backendabi.L2BatchWithdrawERC1155Sig:
|
||||
event := backendabi.BatchERC1155MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC1155GatewayABI, &event, "BatchWithdrawERC1155", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack BatchWithdrawERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = utils.ConvertBigIntArrayToString(event.TokenIDs)
|
||||
lastMessage.TokenAmounts = utils.ConvertBigIntArrayToString(event.TokenAmounts)
|
||||
case backendabi.L2SentMessageEventSig:
|
||||
event := backendabi.L2SentMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "SentMessage", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack SentMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
from, err := getRealFromAddress(ctx, event.Sender, event.Message, e.client, vlog.TxHash, e.cfg.GatewayRouterAddr)
|
||||
if err != nil {
|
||||
log.Error("Failed to get real 'from' address", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l2WithdrawMessages = append(l2WithdrawMessages, &orm.CrossMessage{
|
||||
MessageHash: utils.ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message).String(),
|
||||
Sender: from,
|
||||
Receiver: event.Target.String(),
|
||||
TokenType: int(orm.TokenTypeETH),
|
||||
L2TxHash: vlog.TxHash.String(),
|
||||
TokenAmounts: event.Value.String(),
|
||||
MessageFrom: event.Sender.String(),
|
||||
MessageTo: event.Target.String(),
|
||||
MessageValue: event.Value.String(),
|
||||
MessageNonce: event.MessageNonce.Uint64(),
|
||||
MessageData: hexutil.Encode(event.Message),
|
||||
MessageType: int(orm.MessageTypeL2SentMessage),
|
||||
TxStatus: int(orm.TxStatusTypeSent),
|
||||
BlockTimestamp: blockTimestampsMap[vlog.BlockNumber],
|
||||
L2BlockNumber: vlog.BlockNumber,
|
||||
})
|
||||
case backendabi.L2RelayedMessageEventSig:
|
||||
event := backendabi.L2RelayedMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "RelayedMessage", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack RelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l2RelayedMessages = append(l2RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L2BlockNumber: vlog.BlockNumber,
|
||||
L2TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayed),
|
||||
MessageType: int(orm.MessageTypeL1SentMessage),
|
||||
})
|
||||
case backendabi.L2FailedRelayedMessageEventSig:
|
||||
event := backendabi.L2RelayedMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "FailedRelayedMessage", vlog)
|
||||
if err != nil {
|
||||
log.Error("Failed to unpack FailedRelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l2RelayedMessages = append(l2RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L2BlockNumber: vlog.BlockNumber,
|
||||
L2TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeFailedRelayed),
|
||||
MessageType: int(orm.MessageTypeL1SentMessage),
|
||||
})
|
||||
}
|
||||
}
|
||||
return l2WithdrawMessages, l2RelayedMessages, nil
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/scroll-tech/go-ethereum"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"gorm.io/gorm"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
"scroll-tech/bridge-history-api/internal/config"
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// L2ReorgSafeDepth represents the number of block confirmations considered safe against L2 chain reorganizations.
|
||||
// Reorganizations at this depth under normal cases are extremely unlikely.
|
||||
const L2ReorgSafeDepth = 256
|
||||
|
||||
// L2FilterResult the L2 filter result
|
||||
type L2FilterResult struct {
|
||||
WithdrawMessages []*orm.CrossMessage
|
||||
RelayedMessages []*orm.CrossMessage // relayed, failed relayed, relay tx reverted.
|
||||
OtherRevertedTxs []*orm.CrossMessage // reverted txs except relay tx reverted.
|
||||
}
|
||||
|
||||
// L2FetcherLogic the L2 fetcher logic
|
||||
type L2FetcherLogic struct {
|
||||
cfg *config.FetcherConfig
|
||||
client *ethclient.Client
|
||||
addressList []common.Address
|
||||
gatewayList []common.Address
|
||||
parser *L2EventParser
|
||||
db *gorm.DB
|
||||
crossMessageOrm *orm.CrossMessage
|
||||
batchEventOrm *orm.BatchEvent
|
||||
|
||||
l2FetcherLogicFetchedTotal *prometheus.CounterVec
|
||||
}
|
||||
|
||||
// NewL2FetcherLogic create L2 fetcher logic
|
||||
func NewL2FetcherLogic(cfg *config.FetcherConfig, db *gorm.DB, client *ethclient.Client) *L2FetcherLogic {
|
||||
addressList := []common.Address{
|
||||
common.HexToAddress(cfg.ETHGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.StandardERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.CustomERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.WETHGatewayAddr),
|
||||
common.HexToAddress(cfg.DAIGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.ERC721GatewayAddr),
|
||||
common.HexToAddress(cfg.ERC1155GatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessengerAddr),
|
||||
}
|
||||
|
||||
gatewayList := []common.Address{
|
||||
common.HexToAddress(cfg.ETHGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.StandardERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.CustomERC20GatewayAddr),
|
||||
common.HexToAddress(cfg.WETHGatewayAddr),
|
||||
common.HexToAddress(cfg.DAIGatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.ERC721GatewayAddr),
|
||||
common.HexToAddress(cfg.ERC1155GatewayAddr),
|
||||
|
||||
common.HexToAddress(cfg.MessengerAddr),
|
||||
|
||||
common.HexToAddress(cfg.GatewayRouterAddr),
|
||||
}
|
||||
|
||||
// Optional erc20 gateways.
|
||||
if common.HexToAddress(cfg.USDCGatewayAddr) != (common.Address{}) {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.USDCGatewayAddr))
|
||||
gatewayList = append(gatewayList, common.HexToAddress(cfg.USDCGatewayAddr))
|
||||
}
|
||||
|
||||
if common.HexToAddress(cfg.LIDOGatewayAddr) != (common.Address{}) {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.LIDOGatewayAddr))
|
||||
gatewayList = append(gatewayList, common.HexToAddress(cfg.LIDOGatewayAddr))
|
||||
}
|
||||
|
||||
if common.HexToAddress(cfg.PufferGatewayAddr) != (common.Address{}) {
|
||||
addressList = append(addressList, common.HexToAddress(cfg.PufferGatewayAddr))
|
||||
gatewayList = append(gatewayList, common.HexToAddress(cfg.PufferGatewayAddr))
|
||||
}
|
||||
|
||||
log.Info("L2 Fetcher configured with the following address list", "addresses", addressList, "gateways", gatewayList)
|
||||
|
||||
f := &L2FetcherLogic{
|
||||
db: db,
|
||||
crossMessageOrm: orm.NewCrossMessage(db),
|
||||
batchEventOrm: orm.NewBatchEvent(db),
|
||||
cfg: cfg,
|
||||
client: client,
|
||||
addressList: addressList,
|
||||
gatewayList: gatewayList,
|
||||
parser: NewL2EventParser(cfg, client),
|
||||
}
|
||||
|
||||
reg := prometheus.DefaultRegisterer
|
||||
f.l2FetcherLogicFetchedTotal = promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "L2_fetcher_logic_fetched_total",
|
||||
Help: "The total number of events or failed txs fetched in L2 fetcher logic.",
|
||||
}, []string{"type"})
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *L2FetcherLogic) getBlocksAndDetectReorg(ctx context.Context, from, to uint64, lastBlockHash common.Hash) (bool, uint64, common.Hash, []*types.Block, error) {
|
||||
blocks, err := utils.GetBlocksInRange(ctx, f.client, from, to)
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 blocks in range", "from", from, "to", to, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
for _, block := range blocks {
|
||||
if block.ParentHash() != lastBlockHash {
|
||||
log.Warn("L2 reorg detected", "reorg height", block.NumberU64()-1, "expected hash", block.ParentHash().String(), "local hash", lastBlockHash.String())
|
||||
var resyncHeight uint64
|
||||
if block.NumberU64() > L2ReorgSafeDepth+1 {
|
||||
resyncHeight = block.NumberU64() - L2ReorgSafeDepth - 1
|
||||
}
|
||||
header, err := f.client.HeaderByNumber(ctx, new(big.Int).SetUint64(resyncHeight))
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 header by number", "block number", resyncHeight, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
return true, resyncHeight, header.Hash(), nil, nil
|
||||
}
|
||||
lastBlockHash = block.Hash()
|
||||
}
|
||||
|
||||
return false, 0, lastBlockHash, blocks, nil
|
||||
}
|
||||
|
||||
func (f *L2FetcherLogic) getRevertedTxs(ctx context.Context, from, to uint64, blocks []*types.Block) (map[uint64]uint64, []*orm.CrossMessage, []*orm.CrossMessage, error) {
|
||||
var l2RevertedUserTxs []*orm.CrossMessage
|
||||
var l2RevertedRelayedMessageTxs []*orm.CrossMessage
|
||||
blockTimestampsMap := make(map[uint64]uint64)
|
||||
|
||||
for i := from; i <= to; i++ {
|
||||
block := blocks[i-from]
|
||||
blockTimestampsMap[block.NumberU64()] = block.Time()
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
if tx.IsL1MessageTx() {
|
||||
receipt, receiptErr := f.client.TransactionReceipt(ctx, tx.Hash())
|
||||
if receiptErr != nil {
|
||||
log.Error("Failed to get transaction receipt", "txHash", tx.Hash().String(), "err", receiptErr)
|
||||
return nil, nil, nil, receiptErr
|
||||
}
|
||||
|
||||
// Check if the transaction is failed
|
||||
if receipt.Status == types.ReceiptStatusFailed {
|
||||
l2RevertedRelayedMessageTxs = append(l2RevertedRelayedMessageTxs, &orm.CrossMessage{
|
||||
MessageHash: common.BytesToHash(crypto.Keccak256(tx.AsL1MessageTx().Data)).String(),
|
||||
L2TxHash: tx.Hash().String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayTxReverted),
|
||||
L2BlockNumber: receipt.BlockNumber.Uint64(),
|
||||
MessageType: int(orm.MessageTypeL1SentMessage),
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Gateways: L2 withdrawal.
|
||||
if !isTransactionToGateway(tx, f.gatewayList) {
|
||||
continue
|
||||
}
|
||||
|
||||
receipt, receiptErr := f.client.TransactionReceipt(ctx, tx.Hash())
|
||||
if receiptErr != nil {
|
||||
log.Error("Failed to get transaction receipt", "txHash", tx.Hash().String(), "err", receiptErr)
|
||||
return nil, nil, nil, receiptErr
|
||||
}
|
||||
|
||||
// Check if the transaction is failed
|
||||
if receipt.Status == types.ReceiptStatusFailed {
|
||||
signer := types.LatestSignerForChainID(new(big.Int).SetUint64(tx.ChainId().Uint64()))
|
||||
sender, signerErr := signer.Sender(tx)
|
||||
if signerErr != nil {
|
||||
log.Error("get sender failed", "chain id", tx.ChainId().Uint64(), "tx hash", tx.Hash().String(), "err", signerErr)
|
||||
return nil, nil, nil, signerErr
|
||||
}
|
||||
|
||||
l2RevertedUserTxs = append(l2RevertedUserTxs, &orm.CrossMessage{
|
||||
L2TxHash: tx.Hash().String(),
|
||||
MessageType: int(orm.MessageTypeL2SentMessage),
|
||||
Sender: sender.String(),
|
||||
Receiver: (*tx.To()).String(),
|
||||
L2BlockNumber: receipt.BlockNumber.Uint64(),
|
||||
BlockTimestamp: block.Time(),
|
||||
TxStatus: int(orm.TxStatusTypeSentTxReverted),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return blockTimestampsMap, l2RevertedUserTxs, l2RevertedRelayedMessageTxs, nil
|
||||
}
|
||||
|
||||
func (f *L2FetcherLogic) l2FetcherLogs(ctx context.Context, from, to uint64) ([]types.Log, error) {
|
||||
query := ethereum.FilterQuery{
|
||||
FromBlock: new(big.Int).SetUint64(from), // inclusive
|
||||
ToBlock: new(big.Int).SetUint64(to), // inclusive
|
||||
Addresses: f.addressList,
|
||||
Topics: make([][]common.Hash, 1),
|
||||
}
|
||||
query.Topics[0] = make([]common.Hash, 7)
|
||||
query.Topics[0][0] = backendabi.L2WithdrawETHSig
|
||||
query.Topics[0][1] = backendabi.L2WithdrawERC20Sig
|
||||
query.Topics[0][2] = backendabi.L2WithdrawERC721Sig
|
||||
query.Topics[0][3] = backendabi.L2WithdrawERC1155Sig
|
||||
query.Topics[0][4] = backendabi.L2SentMessageEventSig
|
||||
query.Topics[0][5] = backendabi.L2RelayedMessageEventSig
|
||||
query.Topics[0][6] = backendabi.L2FailedRelayedMessageEventSig
|
||||
|
||||
eventLogs, err := f.client.FilterLogs(ctx, query)
|
||||
if err != nil {
|
||||
log.Error("Failed to filter L2 event logs", "from", from, "to", to, "err", err)
|
||||
return nil, err
|
||||
}
|
||||
return eventLogs, nil
|
||||
}
|
||||
|
||||
// L2Fetcher L2 fetcher
|
||||
func (f *L2FetcherLogic) L2Fetcher(ctx context.Context, from, to uint64, lastBlockHash common.Hash) (bool, uint64, common.Hash, *L2FilterResult, error) {
|
||||
log.Info("fetch and save L2 events", "from", from, "to", to)
|
||||
|
||||
isReorg, reorgHeight, blockHash, blocks, getErr := f.getBlocksAndDetectReorg(ctx, from, to, lastBlockHash)
|
||||
if getErr != nil {
|
||||
log.Error("L2Fetcher getBlocksAndDetectReorg failed", "from", from, "to", to, "error", getErr)
|
||||
return false, 0, common.Hash{}, nil, getErr
|
||||
}
|
||||
|
||||
if isReorg {
|
||||
return isReorg, reorgHeight, blockHash, nil, nil
|
||||
}
|
||||
|
||||
blockTimestampsMap, revertedUserTxs, revertedRelayMsgs, routerErr := f.getRevertedTxs(ctx, from, to, blocks)
|
||||
if routerErr != nil {
|
||||
log.Error("L2Fetcher getRevertedTxs failed", "from", from, "to", to, "error", routerErr)
|
||||
return false, 0, common.Hash{}, nil, routerErr
|
||||
}
|
||||
|
||||
eventLogs, err := f.l2FetcherLogs(ctx, from, to)
|
||||
if err != nil {
|
||||
log.Error("L2Fetcher l2FetcherLogs failed", "from", from, "to", to, "error", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
l2WithdrawMessages, l2RelayedMessages, err := f.parser.ParseL2EventLogs(ctx, eventLogs, blockTimestampsMap)
|
||||
if err != nil {
|
||||
log.Error("failed to parse L2 event logs", "from", from, "to", to, "err", err)
|
||||
return false, 0, common.Hash{}, nil, err
|
||||
}
|
||||
|
||||
res := L2FilterResult{
|
||||
WithdrawMessages: l2WithdrawMessages,
|
||||
RelayedMessages: append(l2RelayedMessages, revertedRelayMsgs...),
|
||||
OtherRevertedTxs: revertedUserTxs,
|
||||
}
|
||||
|
||||
f.updateMetrics(res)
|
||||
|
||||
return false, 0, blockHash, &res, nil
|
||||
}
|
||||
|
||||
func (f *L2FetcherLogic) updateMetrics(res L2FilterResult) {
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_failed_gateway_router_transaction").Add(float64(len(res.OtherRevertedTxs)))
|
||||
|
||||
for _, withdrawMessage := range res.WithdrawMessages {
|
||||
switch orm.TokenType(withdrawMessage.TokenType) {
|
||||
case orm.TokenTypeETH:
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_withdraw_eth").Add(1)
|
||||
case orm.TokenTypeERC20:
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_withdraw_erc20").Add(1)
|
||||
case orm.TokenTypeERC721:
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_withdraw_erc721").Add(1)
|
||||
case orm.TokenTypeERC1155:
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_withdraw_erc1155").Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
for _, relayedMessage := range res.RelayedMessages {
|
||||
switch orm.TxStatusType(relayedMessage.TxStatus) {
|
||||
case orm.TxStatusTypeRelayed:
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_relayed_message").Add(1)
|
||||
case orm.TxStatusTypeFailedRelayed:
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_failed_relayed_message").Add(1)
|
||||
case orm.TxStatusTypeRelayTxReverted:
|
||||
f.l2FetcherLogicFetchedTotal.WithLabelValues("L2_reverted_relayed_message_transaction").Add(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isTransactionToGateway(tx *types.Transaction, gatewayList []common.Address) bool {
|
||||
if tx.To() == nil {
|
||||
return false
|
||||
}
|
||||
for _, gateway := range gatewayList {
|
||||
if *tx.To() == gateway {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
476
bridge-history-api/internal/logic/watcher_event_parser.go
Normal file
476
bridge-history-api/internal/logic/watcher_event_parser.go
Normal file
@@ -0,0 +1,476 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
"scroll-tech/bridge-history-api/internal/utils"
|
||||
)
|
||||
|
||||
// ParseL1CrossChainEventLogs parses L1 watched cross chain events.
|
||||
func ParseL1CrossChainEventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64, client *ethclient.Client) ([]*orm.CrossMessage, []*orm.CrossMessage, error) {
|
||||
var l1DepositMessages []*orm.CrossMessage
|
||||
var l1RelayedMessages []*orm.CrossMessage
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L1DepositETHSig:
|
||||
event := backendabi.ETHMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ETHGatewayABI, &event, "DepositETH", vlog); err != nil {
|
||||
log.Warn("Failed to unpack DepositETH event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.L1BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeETH)
|
||||
lastMessage.L1TxHash = vlog.TxHash.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL1SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L1DepositERC20Sig:
|
||||
event := backendabi.ERC20MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL1ERC20GatewayABI, &event, "DepositERC20", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack DepositERC20 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.L1BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC20)
|
||||
lastMessage.L1TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL1SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L1DepositERC721Sig:
|
||||
event := backendabi.ERC721MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC721GatewayABI, &event, "DepositERC721", vlog); err != nil {
|
||||
log.Warn("Failed to unpack DepositERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.L1BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L1TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL1SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L1BatchDepositERC721Sig:
|
||||
event := backendabi.BatchERC721MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC721GatewayABI, &event, "BatchDepositERC721", vlog); err != nil {
|
||||
log.Warn("Failed to unpack BatchDepositERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.L1BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L1TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs)
|
||||
lastMessage.MessageType = int(orm.MessageTypeL1SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L1DepositERC1155Sig:
|
||||
event := backendabi.ERC1155MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC1155GatewayABI, &event, "DepositERC1155", vlog); err != nil {
|
||||
log.Warn("Failed to unpack DepositERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.L1BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L1TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL1SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L1BatchDepositERC1155Sig:
|
||||
event := backendabi.BatchERC1155MessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ERC1155GatewayABI, &event, "BatchDepositERC1155", vlog); err != nil {
|
||||
log.Warn("Failed to unpack BatchDepositERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l1DepositMessages[len(l1DepositMessages)-1]
|
||||
lastMessage.L1BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L1TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs)
|
||||
lastMessage.TokenAmounts = convertBigIntArrayToString(event.TokenAmounts)
|
||||
lastMessage.MessageType = int(orm.MessageTypeL1SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L1SentMessageEventSig:
|
||||
event := backendabi.L1SentMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "SentMessage", vlog); err != nil {
|
||||
log.Warn("Failed to unpack SentMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
// Use this messageHash as next deposit event's messageHash
|
||||
messageHash := utils.ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message).String()
|
||||
l1DepositMessages = append(l1DepositMessages, &orm.CrossMessage{
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
Sender: event.Sender.String(),
|
||||
Receiver: event.Target.String(),
|
||||
TokenType: int(orm.TokenTypeETH),
|
||||
L1TxHash: vlog.TxHash.String(),
|
||||
TokenAmounts: event.Value.String(),
|
||||
MessageNonce: event.MessageNonce.Uint64(),
|
||||
MessageType: int(orm.MessageTypeL1SentMessage),
|
||||
MessageHash: messageHash,
|
||||
})
|
||||
case backendabi.L1RelayedMessageEventSig:
|
||||
event := backendabi.L1RelayedMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "RelayedMessage", vlog); err != nil {
|
||||
log.Warn("Failed to unpack RelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l1RelayedMessages = append(l1RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
L1TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayed),
|
||||
})
|
||||
case backendabi.L1FailedRelayedMessageEventSig:
|
||||
event := backendabi.L1FailedRelayedMessageEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "FailedRelayedMessage", vlog); err != nil {
|
||||
log.Warn("Failed to unpack FailedRelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l1RelayedMessages = append(l1RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L1BlockNumber: vlog.BlockNumber,
|
||||
L1TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayedFailed),
|
||||
})
|
||||
}
|
||||
}
|
||||
return l1DepositMessages, l1RelayedMessages, nil
|
||||
}
|
||||
|
||||
// ParseL1BatchEventLogs parses L1 watched batch events.
|
||||
func ParseL1BatchEventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64, client *ethclient.Client) ([]*orm.BatchEvent, error) {
|
||||
var l1BatchEvents []*orm.BatchEvent
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L1CommitBatchEventSig:
|
||||
event := backendabi.L1CommitBatchEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "CommitBatch", vlog); err != nil {
|
||||
log.Warn("Failed to unpack CommitBatch event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
commitTx, isPending, err := client.TransactionByHash(ctx, vlog.TxHash)
|
||||
if err != nil || isPending {
|
||||
log.Warn("Failed to get commit Batch tx receipt or the tx is still pending", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
startBlock, endBlock, err := utils.GetBatchRangeFromCalldata(commitTx.Data())
|
||||
if err != nil {
|
||||
log.Warn("Failed to get batch range from calldata", "hash", commitTx.Hash().String(), "height", vlog.BlockNumber)
|
||||
return nil, err
|
||||
}
|
||||
l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{
|
||||
BatchStatus: int(orm.BatchStatusTypeCommitted),
|
||||
BatchIndex: event.BatchIndex.Uint64(),
|
||||
BatchHash: event.BatchHash.String(),
|
||||
StartBlockNumber: startBlock,
|
||||
EndBlockNumber: endBlock,
|
||||
})
|
||||
case backendabi.L1RevertBatchEventSig:
|
||||
event := backendabi.L1RevertBatchEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "RevertBatch", vlog); err != nil {
|
||||
log.Warn("Failed to unpack RevertBatch event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{
|
||||
BatchStatus: int(orm.BatchStatusTypeReverted),
|
||||
BatchIndex: event.BatchIndex.Uint64(),
|
||||
BatchHash: event.BatchHash.String(),
|
||||
})
|
||||
case backendabi.L1FinalizeBatchEventSig:
|
||||
event := backendabi.L1FinalizeBatchEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "FinalizeBatch", vlog); err != nil {
|
||||
log.Warn("Failed to unpack FinalizeBatch event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{
|
||||
BatchStatus: int(orm.BatchStatusTypeFinalized),
|
||||
BatchIndex: event.BatchIndex.Uint64(),
|
||||
BatchHash: event.BatchHash.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return l1BatchEvents, nil
|
||||
}
|
||||
|
||||
// ParseL1MessageQueueEventLogs parses L1 watched message queue events.
|
||||
func ParseL1MessageQueueEventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64, client *ethclient.Client) ([]*orm.MessageQueueEvent, error) {
|
||||
var l1MessageQueueEvents []*orm.MessageQueueEvent
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L1QueueTransactionEventSig:
|
||||
event := backendabi.L1QueueTransactionEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "QueueTransaction", vlog); err != nil {
|
||||
log.Warn("Failed to unpack QueueTransaction event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
// 1. Update queue index of both sent message and replay message.
|
||||
// 2. Update tx hash of replay message.
|
||||
l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{
|
||||
EventType: orm.MessageQueueEventTypeQueueTransaction,
|
||||
QueueIndex: event.QueueIndex,
|
||||
TxHash: vlog.TxHash,
|
||||
})
|
||||
case backendabi.L1DequeueTransactionEventSig:
|
||||
event := backendabi.L1DequeueTransactionEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "DequeueTransaction", vlog); err != nil {
|
||||
log.Warn("Failed to unpack DequeueTransaction event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
skippedIndices := getSkippedQueueIndices(event.StartIndex.Uint64(), event.SkippedBitmap)
|
||||
for _, index := range skippedIndices {
|
||||
l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{
|
||||
EventType: orm.MessageQueueEventTypeDequeueTransaction,
|
||||
QueueIndex: index,
|
||||
})
|
||||
}
|
||||
case backendabi.L1DropTransactionEventSig:
|
||||
event := backendabi.L1DropTransactionEvent{}
|
||||
if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "DropTransaction", vlog); err != nil {
|
||||
log.Warn("Failed to unpack DropTransaction event", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{
|
||||
EventType: orm.MessageQueueEventTypeDropTransaction,
|
||||
QueueIndex: event.Index.Uint64(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return l1MessageQueueEvents, nil
|
||||
}
|
||||
|
||||
// ParseL2EventLogs parses L2 watched events
|
||||
func ParseL2EventLogs(logs []types.Log, blockTimestampsMap map[uint64]uint64) ([]*orm.CrossMessage, []*orm.CrossMessage, error) {
|
||||
var l2WithdrawMessages []*orm.CrossMessage
|
||||
var l2RelayedMessages []*orm.CrossMessage
|
||||
for _, vlog := range logs {
|
||||
switch vlog.Topics[0] {
|
||||
case backendabi.L2WithdrawETHSig:
|
||||
event := backendabi.ETHMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ETHGatewayABI, &event, "WithdrawETH", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack WithdrawETH event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.L2BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeETH)
|
||||
lastMessage.L2TxHash = vlog.TxHash.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL2SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L2WithdrawERC20Sig:
|
||||
event := backendabi.ERC20MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC20GatewayABI, &event, "WithdrawERC20", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack WithdrawERC20 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.L2BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC20)
|
||||
lastMessage.L2TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL2SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L2WithdrawERC721Sig:
|
||||
event := backendabi.ERC721MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC721GatewayABI, &event, "WithdrawERC721", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack WithdrawERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.L2BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L2TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL2SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L2BatchWithdrawERC721Sig:
|
||||
event := backendabi.BatchERC721MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC721GatewayABI, &event, "BatchWithdrawERC721", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack BatchWithdrawERC721 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.L2BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC721)
|
||||
lastMessage.L2TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs)
|
||||
lastMessage.MessageType = int(orm.MessageTypeL2SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L2WithdrawERC1155Sig:
|
||||
event := backendabi.ERC1155MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC1155GatewayABI, &event, "WithdrawERC1155", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack WithdrawERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.L2BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L2TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = event.TokenID.String()
|
||||
lastMessage.TokenAmounts = event.Amount.String()
|
||||
lastMessage.MessageType = int(orm.MessageTypeL2SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L2BatchWithdrawERC1155Sig:
|
||||
event := backendabi.BatchERC1155MessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ERC1155GatewayABI, &event, "BatchWithdrawERC1155", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack BatchWithdrawERC1155 event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1]
|
||||
lastMessage.L2BlockNumber = vlog.BlockNumber
|
||||
lastMessage.Sender = event.From.String()
|
||||
lastMessage.Receiver = event.To.String()
|
||||
lastMessage.TokenType = int(orm.TokenTypeERC1155)
|
||||
lastMessage.L2TxHash = vlog.TxHash.String()
|
||||
lastMessage.L1TokenAddress = event.L1Token.String()
|
||||
lastMessage.L2TokenAddress = event.L2Token.String()
|
||||
lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs)
|
||||
lastMessage.TokenAmounts = convertBigIntArrayToString(event.TokenAmounts)
|
||||
lastMessage.MessageType = int(orm.MessageTypeL2SentMessage)
|
||||
lastMessage.TxStatus = int(orm.TxStatusTypeSent)
|
||||
lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber]
|
||||
case backendabi.L2SentMessageEventSig:
|
||||
event := backendabi.L2SentMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "SentMessage", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack SentMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
// Use this messageHash as next deposit event's messageHash
|
||||
messageHash := utils.ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message)
|
||||
l2WithdrawMessages = append(l2WithdrawMessages, &orm.CrossMessage{
|
||||
MessageHash: messageHash.String(),
|
||||
Sender: event.Sender.String(),
|
||||
Receiver: event.Target.String(),
|
||||
TokenType: int(orm.TokenTypeETH),
|
||||
L2TxHash: vlog.TxHash.String(),
|
||||
TokenAmounts: event.Value.String(),
|
||||
MessageFrom: event.Sender.String(),
|
||||
MessageTo: event.Target.String(),
|
||||
MessageValue: event.Value.String(),
|
||||
MessageNonce: event.MessageNonce.Uint64(),
|
||||
MessageData: hexutil.Encode(event.Message),
|
||||
})
|
||||
case backendabi.L2RelayedMessageEventSig:
|
||||
event := backendabi.L2RelayedMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "RelayedMessage", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack RelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l2RelayedMessages = append(l2RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L2BlockNumber: vlog.BlockNumber,
|
||||
L2TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayed),
|
||||
})
|
||||
case backendabi.L2FailedRelayedMessageEventSig:
|
||||
event := backendabi.L2RelayedMessageEvent{}
|
||||
err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "FailedRelayedMessage", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack FailedRelayedMessage event", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
l2RelayedMessages = append(l2RelayedMessages, &orm.CrossMessage{
|
||||
MessageHash: event.MessageHash.String(),
|
||||
L2BlockNumber: vlog.BlockNumber,
|
||||
L2TxHash: vlog.TxHash.String(),
|
||||
TxStatus: int(orm.TxStatusTypeRelayedFailed),
|
||||
})
|
||||
}
|
||||
}
|
||||
return l2WithdrawMessages, l2RelayedMessages, nil
|
||||
}
|
||||
|
||||
func convertBigIntArrayToString(array []*big.Int) string {
|
||||
stringArray := make([]string, len(array))
|
||||
for i, num := range array {
|
||||
stringArray[i] = num.String()
|
||||
}
|
||||
|
||||
result := strings.Join(stringArray, ", ")
|
||||
return result
|
||||
}
|
||||
|
||||
func getSkippedQueueIndices(startIndex uint64, skippedBitmap *big.Int) []uint64 {
|
||||
var indices []uint64
|
||||
for i := 0; i < 256; i++ {
|
||||
index := startIndex + uint64(i)
|
||||
bit := new(big.Int).Rsh(skippedBitmap, uint(i))
|
||||
if bit.Bit(0) == 0 {
|
||||
continue
|
||||
}
|
||||
indices = append(indices, index)
|
||||
}
|
||||
return indices
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// BatchStatusType represents the type of batch status.
|
||||
@@ -20,27 +19,16 @@ const (
|
||||
BatchStatusTypeFinalized
|
||||
)
|
||||
|
||||
// UpdateStatusType represents the whether batch info is updated in message table.
|
||||
type UpdateStatusType int
|
||||
|
||||
// Constants for UpdateStatusType.
|
||||
const (
|
||||
UpdateStatusTypeUnupdated UpdateStatusType = iota
|
||||
UpdateStatusTypeUpdated
|
||||
)
|
||||
|
||||
// BatchEvent represents a batch event.
|
||||
type BatchEvent struct {
|
||||
db *gorm.DB `gorm:"column:-"`
|
||||
|
||||
ID uint64 `json:"id" gorm:"column:id;primary_key"`
|
||||
L1BlockNumber uint64 `json:"l1_block_number" gorm:"column:l1_block_number"`
|
||||
BatchStatus int `json:"batch_status" gorm:"column:batch_status"`
|
||||
BatchIndex uint64 `json:"batch_index" gorm:"column:batch_index"`
|
||||
BatchHash string `json:"batch_hash" gorm:"column:batch_hash"`
|
||||
StartBlockNumber uint64 `json:"start_block_number" gorm:"column:start_block_number"`
|
||||
EndBlockNumber uint64 `json:"end_block_number" gorm:"column:end_block_number"`
|
||||
UpdateStatus int `json:"update_status" gorm:"column:update_status"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
|
||||
DeletedAt *time.Time `json:"deleted_at" gorm:"column:deleted_at"`
|
||||
@@ -48,7 +36,7 @@ type BatchEvent struct {
|
||||
|
||||
// TableName returns the table name for the BatchEvent model.
|
||||
func (*BatchEvent) TableName() string {
|
||||
return "batch_event_v2"
|
||||
return "batch_event"
|
||||
}
|
||||
|
||||
// NewBatchEvent returns a new instance of BatchEvent.
|
||||
@@ -56,29 +44,12 @@ func NewBatchEvent(db *gorm.DB) *BatchEvent {
|
||||
return &BatchEvent{db: db}
|
||||
}
|
||||
|
||||
// GetBatchEventSyncedHeightInDB returns the maximum l1_block_number from the batch_event_v2 table.
|
||||
func (c *BatchEvent) GetBatchEventSyncedHeightInDB(ctx context.Context) (uint64, error) {
|
||||
var batch BatchEvent
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&BatchEvent{})
|
||||
db = db.Order("l1_block_number desc")
|
||||
if err := db.First(&batch).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return 0, nil
|
||||
}
|
||||
return 0, fmt.Errorf("failed to get batch synced height in db, error: %w", err)
|
||||
}
|
||||
return batch.L1BlockNumber, nil
|
||||
}
|
||||
|
||||
// GetFinalizedBatchesLEBlockHeight returns the finalized batches with end block <= given block height in db.
|
||||
func (c *BatchEvent) GetFinalizedBatchesLEBlockHeight(ctx context.Context, blockHeight uint64) ([]*BatchEvent, error) {
|
||||
// GetBatchesGEBlockHeight returns the batches with end block >= given block height in db.
|
||||
func (c *BatchEvent) GetBatchesGEBlockHeight(ctx context.Context, blockHeight uint64) ([]*BatchEvent, error) {
|
||||
var batches []*BatchEvent
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&BatchEvent{})
|
||||
db = db.Where("end_block_number <= ?", blockHeight)
|
||||
db = db.Where("batch_status = ?", BatchStatusTypeFinalized)
|
||||
db = db.Where("update_status = ?", UpdateStatusTypeUnupdated)
|
||||
db = db.Where("end_block_number >= ?", blockHeight)
|
||||
db = db.Order("batch_index asc")
|
||||
if err := db.Find(&batches).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
@@ -90,55 +61,39 @@ func (c *BatchEvent) GetFinalizedBatchesLEBlockHeight(ctx context.Context, block
|
||||
}
|
||||
|
||||
// InsertOrUpdateBatchEvents inserts a new batch event or updates an existing one based on the BatchStatusType.
|
||||
func (c *BatchEvent) InsertOrUpdateBatchEvents(ctx context.Context, l1BatchEvents []*BatchEvent) error {
|
||||
func (c *BatchEvent) InsertOrUpdateBatchEvents(ctx context.Context, l1BatchEvents []*BatchEvent, dbTX ...*gorm.DB) error {
|
||||
for _, l1BatchEvent := range l1BatchEvents {
|
||||
db := c.db
|
||||
if len(dbTX) > 0 && dbTX[0] != nil {
|
||||
db = dbTX[0]
|
||||
}
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&BatchEvent{})
|
||||
updateFields := make(map[string]interface{})
|
||||
switch BatchStatusType(l1BatchEvent.BatchStatus) {
|
||||
case BatchStatusTypeCommitted:
|
||||
// Use the clause to either insert or ignore on conflict
|
||||
db = db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "batch_hash"}},
|
||||
DoNothing: true,
|
||||
})
|
||||
if err := db.Create(l1BatchEvent).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert or ignore batch event, error: %w", err)
|
||||
return fmt.Errorf("failed to insert batch event, batch: %+v, error: %w", l1BatchEvent, err)
|
||||
}
|
||||
case BatchStatusTypeFinalized:
|
||||
db = db.Where("batch_index = ?", l1BatchEvent.BatchIndex)
|
||||
db = db.Where("batch_hash = ?", l1BatchEvent.BatchHash)
|
||||
updateFields["batch_status"] = BatchStatusTypeFinalized
|
||||
if err := db.Updates(updateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update batch event, error: %w", err)
|
||||
return fmt.Errorf("failed to update batch event, batch: %+v, error: %w", l1BatchEvent, err)
|
||||
}
|
||||
case BatchStatusTypeReverted:
|
||||
db = db.Where("batch_index = ?", l1BatchEvent.BatchIndex)
|
||||
db = db.Where("batch_hash = ?", l1BatchEvent.BatchHash)
|
||||
updateFields["batch_status"] = BatchStatusTypeReverted
|
||||
if err := db.Updates(updateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update batch event, error: %w", err)
|
||||
return fmt.Errorf("failed to update batch event, batch: %+v, error: %w", l1BatchEvent, err)
|
||||
}
|
||||
// Soft delete the batch event.
|
||||
// Soft delete the batch event
|
||||
if err := db.Delete(l1BatchEvent).Error; err != nil {
|
||||
return fmt.Errorf("failed to soft delete batch event, error: %w", err)
|
||||
return fmt.Errorf("failed to soft delete batch event, batch: %+v, error: %w", l1BatchEvent, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateBatchEventStatus updates the UpdateStatusType of a BatchEvent given its batch index.
|
||||
func (c *BatchEvent) UpdateBatchEventStatus(ctx context.Context, batchIndex uint64) error {
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&BatchEvent{})
|
||||
db = db.Where("batch_index = ?", batchIndex)
|
||||
updateFields := map[string]interface{}{
|
||||
"update_status": UpdateStatusTypeUpdated,
|
||||
}
|
||||
if err := db.Updates(updateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update batch event status, batchIndex: %d, error: %w", batchIndex, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
@@ -37,21 +38,13 @@ type TxStatusType int
|
||||
|
||||
// Constants for TxStatusType.
|
||||
const (
|
||||
// TxStatusTypeSent is one of the initial statuses for cross-chain messages.
|
||||
// It is used as the default value to prevent overwriting the transaction status in scenarios where the message status might change
|
||||
// from a later status (e.g., relayed) back to "sent".
|
||||
// Example flow (L1 -> L2 message, and L1 fetcher is slower than L2 fetcher):
|
||||
// 1. The relayed message is first tracked and processed, setting tx_status to TxStatusTypeRelayed.
|
||||
// 2. The sent message is later processed (same cross-chain message), the tx_status should not over-write TxStatusTypeRelayed.
|
||||
TxStatusTypeSent TxStatusType = iota
|
||||
TxStatusTypeSentTxReverted // Not track message hash, thus will not be processed again anymore.
|
||||
TxStatusTypeRelayed // Terminal status.
|
||||
// Retry: this often occurs due to an out of gas (OOG) issue if the transaction was initiated via the frontend.
|
||||
TxStatusTypeFailedRelayed
|
||||
// Retry: this often occurs due to an out of gas (OOG) issue if the transaction was initiated via the frontend.
|
||||
TxStatusTypeRelayTxReverted
|
||||
TxStatusTypeUnknown TxStatusType = iota
|
||||
TxStatusTypeSent
|
||||
TxStatusTypeSentFailed
|
||||
TxStatusTypeRelayed
|
||||
TxStatusTypeRelayedFailed
|
||||
TxStatusTypeSkipped
|
||||
TxStatusTypeDropped // Terminal status.
|
||||
TxStatusTypeDropped
|
||||
)
|
||||
|
||||
// RollupStatusType represents the status of a rollup.
|
||||
@@ -78,12 +71,7 @@ const (
|
||||
type MessageQueueEvent struct {
|
||||
EventType MessageQueueEventType
|
||||
QueueIndex uint64
|
||||
|
||||
// Track replay tx hash and refund tx hash.
|
||||
TxHash common.Hash
|
||||
|
||||
// QueueTransaction only in replayMessage, to track which message is replayed.
|
||||
MessageHash common.Hash
|
||||
TxHash common.Hash
|
||||
}
|
||||
|
||||
// CrossMessage represents a cross message.
|
||||
@@ -98,10 +86,8 @@ type CrossMessage struct {
|
||||
Sender string `json:"sender" gorm:"column:sender"`
|
||||
Receiver string `json:"receiver" gorm:"column:receiver"`
|
||||
MessageHash string `json:"message_hash" gorm:"column:message_hash"`
|
||||
L1TxHash string `json:"l1_tx_hash" gorm:"column:l1_tx_hash"` // initial tx hash, if MessageType is MessageTypeL1SentMessage.
|
||||
L1ReplayTxHash string `json:"l1_replay_tx_hash" gorm:"column:l1_replay_tx_hash"`
|
||||
L1RefundTxHash string `json:"l1_refund_tx_hash" gorm:"column:l1_refund_tx_hash"`
|
||||
L2TxHash string `json:"l2_tx_hash" gorm:"column:l2_tx_hash"` // initial tx hash, if MessageType is MessageTypeL2SentMessage.
|
||||
L1TxHash string `json:"l1_tx_hash" gorm:"column:l1_tx_hash"`
|
||||
L2TxHash string `json:"l2_tx_hash" gorm:"column:l2_tx_hash"`
|
||||
L1BlockNumber uint64 `json:"l1_block_number" gorm:"column:l1_block_number"`
|
||||
L2BlockNumber uint64 `json:"l2_block_number" gorm:"column:l2_block_number"`
|
||||
L1TokenAddress string `json:"l1_token_address" gorm:"column:l1_token_address"`
|
||||
@@ -123,7 +109,7 @@ type CrossMessage struct {
|
||||
|
||||
// TableName returns the table name for the CrossMessage model.
|
||||
func (*CrossMessage) TableName() string {
|
||||
return "cross_message_v2"
|
||||
return "cross_message"
|
||||
}
|
||||
|
||||
// NewCrossMessage returns a new instance of CrossMessage.
|
||||
@@ -131,8 +117,8 @@ func NewCrossMessage(db *gorm.DB) *CrossMessage {
|
||||
return &CrossMessage{db: db}
|
||||
}
|
||||
|
||||
// GetMessageSyncedHeightInDB returns the latest synced cross message height from the database for a given message type.
|
||||
func (c *CrossMessage) GetMessageSyncedHeightInDB(ctx context.Context, messageType MessageType) (uint64, error) {
|
||||
// GetMessageProcessedHeightInDB returns the latest processed cross message height from the database for a given message type.
|
||||
func (c *CrossMessage) GetMessageProcessedHeightInDB(ctx context.Context, messageType MessageType) (uint64, error) {
|
||||
var message CrossMessage
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
@@ -159,40 +145,39 @@ func (c *CrossMessage) GetMessageSyncedHeightInDB(ctx context.Context, messageTy
|
||||
}
|
||||
}
|
||||
|
||||
// GetL2LatestFinalizedWithdrawal returns the latest finalized L2 withdrawal from the database.
|
||||
func (c *CrossMessage) GetL2LatestFinalizedWithdrawal(ctx context.Context) (*CrossMessage, error) {
|
||||
// GetLatestL2Withdrawal returns the latest processed L2 withdrawal from the database.
|
||||
func (c *CrossMessage) GetLatestL2Withdrawal(ctx context.Context) (*CrossMessage, error) {
|
||||
var message CrossMessage
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Where("message_type = ?", MessageTypeL2SentMessage)
|
||||
db = db.Where("rollup_status = ?", RollupStatusTypeFinalized)
|
||||
db = db.Where("tx_status != ?", TxStatusTypeSentFailed)
|
||||
db = db.Order("message_nonce desc")
|
||||
if err := db.First(&message).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get latest L2 finalized sent message event, error: %w", err)
|
||||
return nil, fmt.Errorf("failed to get latest L2 sent message event, error: %w", err)
|
||||
}
|
||||
return &message, nil
|
||||
}
|
||||
|
||||
// GetL2WithdrawalsByBlockRange returns the L2 withdrawals by block range from the database.
|
||||
func (c *CrossMessage) GetL2WithdrawalsByBlockRange(ctx context.Context, startBlock, endBlock uint64) ([]*CrossMessage, error) {
|
||||
var messages []*CrossMessage
|
||||
// GetLatestFinalizedL2WithdrawalBlockHeight returns the latest finalized L2 sent message block height from the database.
|
||||
func (c *CrossMessage) GetLatestFinalizedL2WithdrawalBlockHeight(ctx context.Context) (uint64, error) {
|
||||
var message CrossMessage
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Where("l2_block_number >= ?", startBlock)
|
||||
db = db.Where("l2_block_number <= ?", endBlock)
|
||||
db = db.Where("tx_status != ?", TxStatusTypeSentTxReverted)
|
||||
db = db.Where("message_type = ?", MessageTypeL2SentMessage)
|
||||
db = db.Order("message_nonce asc")
|
||||
if err := db.Find(&messages).Error; err != nil {
|
||||
db = db.Where("rollup_status", RollupStatusTypeFinalized)
|
||||
db = db.Where("tx_status != ?", TxStatusTypeSentFailed)
|
||||
db = db.Order("message_nonce desc")
|
||||
if err := db.First(&message).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
return 0, nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get latest L2 finalized sent message event, error: %w", err)
|
||||
return 0, fmt.Errorf("failed to get latest L2 sent message event, error: %w", err)
|
||||
}
|
||||
return messages, nil
|
||||
return message.L2BlockNumber, nil
|
||||
}
|
||||
|
||||
// GetMessagesByTxHashes retrieves all cross messages from the database that match the provided transaction hashes.
|
||||
@@ -200,22 +185,23 @@ func (c *CrossMessage) GetMessagesByTxHashes(ctx context.Context, txHashes []str
|
||||
var messages []*CrossMessage
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Where("l1_tx_hash in (?) or l2_tx_hash in (?)", txHashes, txHashes)
|
||||
db = db.Where("l1_tx_hash IN (?) OR l2_tx_hash IN (?)", txHashes, txHashes)
|
||||
if err := db.Find(&messages).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to get L2 messages by tx hashes, tx hashes: %v, error: %w", txHashes, err)
|
||||
}
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
// GetL2UnclaimedWithdrawalsByAddress retrieves all L2 unclaimed withdrawal messages for a given sender address.
|
||||
func (c *CrossMessage) GetL2UnclaimedWithdrawalsByAddress(ctx context.Context, sender string) ([]*CrossMessage, error) {
|
||||
// GetL2ClaimableWithdrawalsByAddress retrieves all L2 claimable withdrawal messages for a given sender address.
|
||||
func (c *CrossMessage) GetL2ClaimableWithdrawalsByAddress(ctx context.Context, sender string) ([]*CrossMessage, error) {
|
||||
var messages []*CrossMessage
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Where("message_type = ?", MessageTypeL2SentMessage)
|
||||
db = db.Where("tx_status = ?", TxStatusTypeSent)
|
||||
db = db.Where("rollup_status = ?", RollupStatusTypeFinalized)
|
||||
db = db.Where("sender = ?", sender)
|
||||
db = db.Order("block_timestamp desc")
|
||||
db = db.Order("block_timestamp DESC")
|
||||
db = db.Limit(500)
|
||||
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)
|
||||
@@ -230,7 +216,7 @@ func (c *CrossMessage) GetL2WithdrawalsByAddress(ctx context.Context, sender str
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Where("message_type = ?", MessageTypeL2SentMessage)
|
||||
db = db.Where("sender = ?", sender)
|
||||
db = db.Order("block_timestamp desc")
|
||||
db = db.Order("block_timestamp DESC")
|
||||
db = db.Limit(500)
|
||||
if err := db.Find(&messages).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to get L2 withdrawal messages by sender address, sender: %v, error: %w", sender, err)
|
||||
@@ -244,7 +230,7 @@ func (c *CrossMessage) GetTxsByAddress(ctx context.Context, sender string) ([]*C
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Where("sender = ?", sender)
|
||||
db = db.Order("block_timestamp desc")
|
||||
db = db.Order("block_timestamp DESC")
|
||||
db = db.Limit(500)
|
||||
if err := db.Find(&messages).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to get all txs by sender address, sender: %v, error: %w", sender, err)
|
||||
@@ -253,64 +239,28 @@ func (c *CrossMessage) GetTxsByAddress(ctx context.Context, sender string) ([]*C
|
||||
}
|
||||
|
||||
// UpdateL1MessageQueueEventsInfo updates the information about L1 message queue events in the database.
|
||||
func (c *CrossMessage) UpdateL1MessageQueueEventsInfo(ctx context.Context, l1MessageQueueEvents []*MessageQueueEvent) error {
|
||||
// update tx statuses.
|
||||
func (c *CrossMessage) UpdateL1MessageQueueEventsInfo(ctx context.Context, l1MessageQueueEvents []*MessageQueueEvent, dbTX ...*gorm.DB) error {
|
||||
for _, l1MessageQueueEvent := range l1MessageQueueEvents {
|
||||
db := c.db
|
||||
if len(dbTX) > 0 && dbTX[0] != nil {
|
||||
db = dbTX[0]
|
||||
}
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
txStatusUpdateFields := make(map[string]interface{})
|
||||
db = db.Where("message_type = ?", MessageTypeL1SentMessage)
|
||||
db = db.Where("message_nonce = ?", l1MessageQueueEvent.QueueIndex)
|
||||
updateFields := make(map[string]interface{})
|
||||
switch l1MessageQueueEvent.EventType {
|
||||
case MessageQueueEventTypeQueueTransaction:
|
||||
continue
|
||||
// Update l1_tx_hash if the user calls replayMessage.
|
||||
updateFields["l1_tx_hash"] = l1MessageQueueEvent.TxHash.String()
|
||||
case MessageQueueEventTypeDequeueTransaction:
|
||||
// do not over-write terminal statuses.
|
||||
db = db.Where("tx_status != ?", TxStatusTypeRelayed)
|
||||
db = db.Where("tx_status != ?", TxStatusTypeDropped)
|
||||
db = db.Where("message_nonce = ?", l1MessageQueueEvent.QueueIndex)
|
||||
db = db.Where("message_type = ?", MessageTypeL1SentMessage)
|
||||
txStatusUpdateFields["tx_status"] = TxStatusTypeSkipped
|
||||
updateFields["tx_status"] = TxStatusTypeSkipped
|
||||
case MessageQueueEventTypeDropTransaction:
|
||||
// do not over-write terminal statuses.
|
||||
db = db.Where("tx_status != ?", TxStatusTypeRelayed)
|
||||
db = db.Where("tx_status != ?", TxStatusTypeDropped)
|
||||
db = db.Where("message_nonce = ?", l1MessageQueueEvent.QueueIndex)
|
||||
db = db.Where("message_type = ?", MessageTypeL1SentMessage)
|
||||
txStatusUpdateFields["tx_status"] = TxStatusTypeDropped
|
||||
updateFields["tx_status"] = TxStatusTypeDropped
|
||||
}
|
||||
if err := db.Updates(txStatusUpdateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update tx statuses of L1 message queue events, update fields: %v, error: %w", txStatusUpdateFields, err)
|
||||
}
|
||||
}
|
||||
|
||||
// update tx hashes of replay and refund.
|
||||
for _, l1MessageQueueEvent := range l1MessageQueueEvents {
|
||||
db := c.db
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
txHashUpdateFields := make(map[string]interface{})
|
||||
switch l1MessageQueueEvent.EventType {
|
||||
case MessageQueueEventTypeDequeueTransaction:
|
||||
continue
|
||||
case MessageQueueEventTypeQueueTransaction:
|
||||
// only replayMessages or enforced txs (whose message hashes would not be found), sendMessages have been filtered out.
|
||||
// replayMessage case:
|
||||
// First SentMessage in L1: https://sepolia.etherscan.io/tx/0xbee4b631312448fcc2caac86e4dccf0a2ae0a88acd6c5fd8764d39d746e472eb
|
||||
// Transaction reverted in L2: https://sepolia.scrollscan.com/tx/0xde6ef307a7da255888aad7a4c40a6b8c886e46a8a05883070bbf18b736cbfb8c
|
||||
// replayMessage: https://sepolia.etherscan.io/tx/0xa5392891232bb32d98fcdbaca0d91b4d22ef2755380d07d982eebd47b147ce28
|
||||
//
|
||||
// Note: update l1_tx_hash if the user calls replayMessage, cannot use queue index here,
|
||||
// because in replayMessage, queue index != message nonce.
|
||||
// Ref: https://github.com/scroll-tech/scroll/blob/v4.3.44/contracts/src/L1/L1ScrollMessenger.sol#L187-L190
|
||||
db = db.Where("message_hash = ?", l1MessageQueueEvent.MessageHash.String())
|
||||
txHashUpdateFields["l1_replay_tx_hash"] = l1MessageQueueEvent.TxHash.String()
|
||||
case MessageQueueEventTypeDropTransaction:
|
||||
db = db.Where("message_nonce = ?", l1MessageQueueEvent.QueueIndex)
|
||||
db = db.Where("message_type = ?", MessageTypeL1SentMessage)
|
||||
txHashUpdateFields["l1_refund_tx_hash"] = l1MessageQueueEvent.TxHash.String()
|
||||
}
|
||||
if err := db.Updates(txHashUpdateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update tx hashes of replay and refund in L1 message queue events info, update fields: %v, error: %w", txHashUpdateFields, err)
|
||||
if err := db.Updates(updateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update L1 message queue events info, event: %+v, error: %w", l1MessageQueueEvent, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -332,223 +282,105 @@ func (c *CrossMessage) UpdateBatchStatusOfL2Withdrawals(ctx context.Context, sta
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateBatchIndexRollupStatusMerkleProofOfL2Messages updates the batch_index, rollup_status, and merkle_proof fields for a list of L2 cross messages.
|
||||
func (c *CrossMessage) UpdateBatchIndexRollupStatusMerkleProofOfL2Messages(ctx context.Context, messages []*CrossMessage) error {
|
||||
if len(messages) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, message := range messages {
|
||||
updateFields := map[string]interface{}{
|
||||
"batch_index": message.BatchIndex,
|
||||
"rollup_status": message.RollupStatus,
|
||||
"merkle_proof": message.MerkleProof,
|
||||
}
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Where("message_hash = ?", message.MessageHash)
|
||||
if err := db.Updates(updateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update L2 message with message_hash %s, error: %w", message.MessageHash, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertOrUpdateL1Messages inserts or updates a list of L1 cross messages into the database.
|
||||
func (c *CrossMessage) InsertOrUpdateL1Messages(ctx context.Context, messages []*CrossMessage) error {
|
||||
func (c *CrossMessage) InsertOrUpdateL1Messages(ctx context.Context, messages []*CrossMessage, dbTX ...*gorm.DB) error {
|
||||
if len(messages) == 0 {
|
||||
return nil
|
||||
}
|
||||
db := c.db
|
||||
if len(dbTX) > 0 && dbTX[0] != nil {
|
||||
db = dbTX[0]
|
||||
}
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
// 'tx_status' column is not explicitly assigned during the update to prevent a later status from being overwritten back to "sent".
|
||||
db = db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "message_hash"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"sender", "receiver", "token_type", "l1_block_number", "l1_tx_hash", "l1_token_address", "l2_token_address", "token_ids", "token_amounts", "message_type", "block_timestamp", "message_nonce"}),
|
||||
DoUpdates: clause.AssignmentColumns([]string{"sender", "receiver", "token_type", "l1_block_number", "l1_tx_hash", "l1_token_address", "l2_token_address", "token_ids", "token_amounts", "message_type", "tx_status", "block_timestamp", "message_nonce"}),
|
||||
})
|
||||
if err := db.Create(messages).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert message, error: %w", err)
|
||||
return fmt.Errorf("failed to insert message, message: %+v, error: %w", messages, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertOrUpdateL2Messages inserts or updates a list of L2 cross messages into the database.
|
||||
func (c *CrossMessage) InsertOrUpdateL2Messages(ctx context.Context, messages []*CrossMessage) error {
|
||||
func (c *CrossMessage) InsertOrUpdateL2Messages(ctx context.Context, messages []*CrossMessage, dbTX ...*gorm.DB) error {
|
||||
if len(messages) == 0 {
|
||||
return nil
|
||||
}
|
||||
db := c.db
|
||||
if len(dbTX) > 0 && dbTX[0] != nil {
|
||||
db = dbTX[0]
|
||||
}
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
// 'tx_status' column is not explicitly assigned during the update to prevent a later status from being overwritten back to "sent".
|
||||
db = db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "message_hash"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"sender", "receiver", "token_type", "l2_block_number", "l2_tx_hash", "l1_token_address", "l2_token_address", "token_ids", "token_amounts", "message_type", "block_timestamp", "message_from", "message_to", "message_value", "message_data", "message_nonce"}),
|
||||
DoUpdates: clause.AssignmentColumns([]string{"sender", "receiver", "token_type", "l2_block_number", "l2_tx_hash", "l1_token_address", "l2_token_address", "token_ids", "token_amounts", "message_type", "tx_status", "block_timestamp", "message_from", "message_to", "message_value", "message_data", "merkle_proof", "message_nonce"}),
|
||||
})
|
||||
if err := db.Create(messages).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert message, error: %w", err)
|
||||
return fmt.Errorf("failed to insert message, message: %+v, error: %w", messages, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertFailedL2GatewayTxs inserts a list of transactions that failed to interact with the L2 gateways into the database.
|
||||
// To resolve unique index confliction, L2 tx hash is used as the MessageHash.
|
||||
// The OnConflict clause is used to prevent inserting same failed transactions multiple times.
|
||||
func (c *CrossMessage) InsertFailedL2GatewayTxs(ctx context.Context, messages []*CrossMessage) error {
|
||||
// InsertFailedGatewayRouterTxs inserts a list of transactions that failed to interact with the gateway router into the database.
|
||||
// These failed transactions are only fetched once, so they are inserted without checking for duplicates.
|
||||
// To resolve unique index confliction, a random UUID will be generated and used as the MessageHash.
|
||||
func (c *CrossMessage) InsertFailedGatewayRouterTxs(ctx context.Context, messages []*CrossMessage, dbTX ...*gorm.DB) error {
|
||||
if len(messages) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, message := range messages {
|
||||
message.MessageHash = message.L2TxHash
|
||||
db := c.db
|
||||
if len(dbTX) > 0 && dbTX[0] != nil {
|
||||
db = dbTX[0]
|
||||
}
|
||||
|
||||
db := c.db
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "message_hash"}},
|
||||
DoNothing: true,
|
||||
})
|
||||
|
||||
if err := db.Create(&messages).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert failed gateway router txs, error: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertFailedL1GatewayTxs inserts a list of transactions that failed to interact with the L1 gateways into the database.
|
||||
// To resolve unique index confliction, L1 tx hash is used as the MessageHash.
|
||||
// The OnConflict clause is used to prevent inserting same failed transactions multiple times.
|
||||
func (c *CrossMessage) InsertFailedL1GatewayTxs(ctx context.Context, messages []*CrossMessage) error {
|
||||
if len(messages) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, message := range messages {
|
||||
message.MessageHash = message.L1TxHash
|
||||
message.MessageHash = uuid.New().String()
|
||||
}
|
||||
|
||||
db := c.db
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "message_hash"}},
|
||||
DoNothing: true,
|
||||
})
|
||||
|
||||
if err := db.Create(&messages).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert failed gateway router txs, error: %w", err)
|
||||
if err := db.Create(messages).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert failed gateway router txs, message: %+v, error: %w", messages, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertOrUpdateL2RelayedMessagesOfL1Deposits inserts or updates the database with a list of L2 relayed messages related to L1 deposits.
|
||||
func (c *CrossMessage) InsertOrUpdateL2RelayedMessagesOfL1Deposits(ctx context.Context, l2RelayedMessages []*CrossMessage) error {
|
||||
func (c *CrossMessage) InsertOrUpdateL2RelayedMessagesOfL1Deposits(ctx context.Context, l2RelayedMessages []*CrossMessage, dbTX ...*gorm.DB) error {
|
||||
if len(l2RelayedMessages) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Deduplicate messages, for each message_hash, retaining message with the highest block number.
|
||||
// This is necessary as a single message, like a FailedRelayedMessage or a reverted relayed transaction,
|
||||
// may be relayed multiple times within certain block ranges, potentially leading to the error:
|
||||
// "ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time (SQLSTATE 21000)".
|
||||
// This happens if we attempt to insert multiple records with the same message_hash in a single db.Create operation.
|
||||
// For example, see these transactions where the same message was relayed twice within certain block ranges:
|
||||
// Reverted tx 1: https://sepolia.scrollscan.com/tx/0xcd6979277c3bc747445273a5e58ef1e9692fbe101d88cfefbbb69d3aef3193c0
|
||||
// Reverted tx 2: https://sepolia.scrollscan.com/tx/0x43e28ed7cb71107c18c5d8ebbdb4a1d9cac73e60391d14d41e92985028faa337
|
||||
// Another example:
|
||||
// FailedRelayedMessage 1: https://sepolia.scrollscan.com/tx/0xfadb147fb211e5096446c5cac3ae0a8a705d2ece6c47c65135c8874f84638f17
|
||||
// FailedRelayedMessage 2: https://sepolia.scrollscan.com/tx/0x6cb149b61afd07bf2e17561a59ebebde41e343b6610290c97515b2f862160b42
|
||||
mergedL2RelayedMessages := make(map[string]*CrossMessage)
|
||||
for _, message := range l2RelayedMessages {
|
||||
if existing, found := mergedL2RelayedMessages[message.MessageHash]; found {
|
||||
if TxStatusType(message.TxStatus) == TxStatusTypeRelayed || message.L2BlockNumber > existing.L2BlockNumber {
|
||||
mergedL2RelayedMessages[message.MessageHash] = message
|
||||
}
|
||||
} else {
|
||||
mergedL2RelayedMessages[message.MessageHash] = message
|
||||
}
|
||||
}
|
||||
uniqueL2RelayedMessages := make([]*CrossMessage, 0, len(mergedL2RelayedMessages))
|
||||
for _, msg := range mergedL2RelayedMessages {
|
||||
uniqueL2RelayedMessages = append(uniqueL2RelayedMessages, msg)
|
||||
}
|
||||
// Do not update tx status of successfully relayed messages,
|
||||
// because if a message is handled, the later relayed message tx would be reverted.
|
||||
// ref: https://github.com/scroll-tech/scroll/blob/v4.3.44/contracts/src/L2/L2ScrollMessenger.sol#L102
|
||||
// e.g.,
|
||||
// Successfully relayed: https://sepolia.scrollscan.com/tx/0x4eb7cb07ba76956259c0079819a34a146f8a93dd891dc94812e9b3d66b056ec7#eventlog
|
||||
// Reverted tx 1 (Reason: Message was already successfully executed): https://sepolia.scrollscan.com/tx/0x1973cafa14eb40734df30da7bfd4d9aceb53f8f26e09d96198c16d0e2e4a95fd
|
||||
// Reverted tx 2 (Reason: Message was already successfully executed): https://sepolia.scrollscan.com/tx/0x02fc3a28684a590aead2482022f56281539085bd3d273ac8dedc1ceccb2bc554
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "message_hash"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"message_type", "l2_block_number", "l2_tx_hash", "tx_status"}),
|
||||
Where: clause.Where{
|
||||
Exprs: []clause.Expression{
|
||||
clause.And(
|
||||
// do not over-write terminal statuses.
|
||||
clause.Neq{Column: "cross_message_v2.tx_status", Value: TxStatusTypeRelayed},
|
||||
clause.Neq{Column: "cross_message_v2.tx_status", Value: TxStatusTypeDropped},
|
||||
),
|
||||
},
|
||||
},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"l2_block_number", "l2_tx_hash", "tx_status"}),
|
||||
})
|
||||
if err := db.Create(uniqueL2RelayedMessages).Error; err != nil {
|
||||
return fmt.Errorf("failed to update L2 reverted relayed message of L1 deposit, error: %w", err)
|
||||
if err := db.Create(l2RelayedMessages).Error; err != nil {
|
||||
return fmt.Errorf("failed to update L2 relayed message of L1 deposit, L2 relayed message: %+v, error: %w", l2RelayedMessages, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertOrUpdateL1RelayedMessagesOfL2Withdrawals inserts or updates the database with a list of L1 relayed messages related to L2 withdrawals.
|
||||
func (c *CrossMessage) InsertOrUpdateL1RelayedMessagesOfL2Withdrawals(ctx context.Context, l1RelayedMessages []*CrossMessage) error {
|
||||
func (c *CrossMessage) InsertOrUpdateL1RelayedMessagesOfL2Withdrawals(ctx context.Context, l1RelayedMessages []*CrossMessage, dbTX ...*gorm.DB) error {
|
||||
if len(l1RelayedMessages) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Deduplicate messages, for each message_hash, retaining message with the highest block number.
|
||||
// This is necessary as a single message, like a FailedRelayedMessage or a reverted relayed transaction,
|
||||
// may be relayed multiple times within certain block ranges, potentially leading to the error:
|
||||
// "ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time (SQLSTATE 21000)".
|
||||
// This happens if we attempt to insert multiple records with the same message_hash in a single db.Create operation.
|
||||
// For example, see these transactions where the same message was relayed twice within certain block ranges:
|
||||
// FailedRelayedMessage 1: https://sepolia.etherscan.io/tx/0x28b3212cda6ca0f3790f362a780257bbe2b37417ccf75a4eca6c3a08294c8f1b#eventlog
|
||||
// FailedRelayedMessage 2: https://sepolia.etherscan.io/tx/0xc8a8254825dd2cab5caef58cfd8d88c077ceadadc78f2340214a86cf8ab88543#eventlog
|
||||
// Another example (relayed success, then relayed again):
|
||||
// Relay Message, and success: https://sepolia.etherscan.io/tx/0xcfdf2f5446719e3e123a8aa06e4d6b3809c3850a13adf875755c8b1e423aa448#eventlog
|
||||
// Relay Message again, and reverted: https://sepolia.etherscan.io/tx/0xb1fcae7546f3de4cfd0b4d679f4075adb4eb69578b12e2b5673f5f24b1836578
|
||||
mergedL1RelayedMessages := make(map[string]*CrossMessage)
|
||||
for _, message := range l1RelayedMessages {
|
||||
if existing, found := mergedL1RelayedMessages[message.MessageHash]; found {
|
||||
if TxStatusType(message.TxStatus) == TxStatusTypeRelayed || message.L1BlockNumber > existing.L1BlockNumber {
|
||||
mergedL1RelayedMessages[message.MessageHash] = message
|
||||
}
|
||||
} else {
|
||||
mergedL1RelayedMessages[message.MessageHash] = message
|
||||
}
|
||||
}
|
||||
uniqueL1RelayedMessages := make([]*CrossMessage, 0, len(mergedL1RelayedMessages))
|
||||
for _, msg := range mergedL1RelayedMessages {
|
||||
uniqueL1RelayedMessages = append(uniqueL1RelayedMessages, msg)
|
||||
}
|
||||
db := c.db
|
||||
if len(dbTX) > 0 && dbTX[0] != nil {
|
||||
db = dbTX[0]
|
||||
}
|
||||
db = db.WithContext(ctx)
|
||||
db = db.Model(&CrossMessage{})
|
||||
db = db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "message_hash"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"message_type", "l1_block_number", "l1_tx_hash", "tx_status"}),
|
||||
Where: clause.Where{
|
||||
Exprs: []clause.Expression{
|
||||
clause.And(
|
||||
// do not over-write terminal statuses.
|
||||
clause.Neq{Column: "cross_message_v2.tx_status", Value: TxStatusTypeRelayed},
|
||||
clause.Neq{Column: "cross_message_v2.tx_status", Value: TxStatusTypeDropped},
|
||||
),
|
||||
},
|
||||
},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"l1_block_number", "l1_tx_hash", "tx_status"}),
|
||||
})
|
||||
if err := db.Create(uniqueL1RelayedMessages).Error; err != nil {
|
||||
return fmt.Errorf("failed to update L1 relayed message of L2 withdrawal, error: %w", err)
|
||||
if err := db.Create(l1RelayedMessages).Error; err != nil {
|
||||
return fmt.Errorf("failed to update L1 relayed message of L2 withdrawal, L1 relayed messages: %+v, error: %w", l1RelayedMessages, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ const MigrationsDir string = "migrations"
|
||||
func init() {
|
||||
goose.SetBaseFS(embedMigrations)
|
||||
goose.SetSequential(true)
|
||||
goose.SetTableName("bridge_historyv2_migrations")
|
||||
goose.SetTableName("bridge_history_migrations")
|
||||
|
||||
verbose, _ := strconv.ParseBool(os.Getenv("LOG_SQL_MIGRATIONS"))
|
||||
goose.SetVerbose(verbose)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE TABLE cross_message_v2
|
||||
create table cross_message
|
||||
(
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
message_type SMALLINT NOT NULL,
|
||||
@@ -12,8 +12,6 @@ CREATE TABLE cross_message_v2
|
||||
|
||||
message_hash VARCHAR DEFAULT NULL, -- NULL for failed txs
|
||||
l1_tx_hash VARCHAR DEFAULT NULL,
|
||||
l1_replay_tx_hash VARCHAR DEFAULT NULL,
|
||||
l1_refund_tx_hash VARCHAR DEFAULT NULL,
|
||||
l2_tx_hash VARCHAR DEFAULT NULL,
|
||||
l1_block_number BIGINT DEFAULT NULL,
|
||||
l2_block_number BIGINT DEFAULT NULL,
|
||||
@@ -38,20 +36,11 @@ CREATE TABLE cross_message_v2
|
||||
deleted_at TIMESTAMP(0) DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_cm_message_hash ON cross_message_v2 (message_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_message_type_l1_block_number ON cross_message_v2 (message_type, l1_block_number DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_message_type_l2_block_number ON cross_message_v2 (message_type, l2_block_number DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_message_type_rollup_status_message_nonce ON cross_message_v2 (message_type, rollup_status, message_nonce DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_message_type_message_nonce_tx_status_l2_block_number ON cross_message_v2 (message_type, message_nonce, tx_status, l2_block_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_l1_tx_hash ON cross_message_v2 (l1_tx_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_l2_tx_hash ON cross_message_v2 (l2_tx_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_message_type_tx_status_sender_block_timestamp ON cross_message_v2 (message_type, tx_status, sender, block_timestamp DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_message_type_sender_block_timestamp ON cross_message_v2 (message_type, sender, block_timestamp DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_cm_sender_block_timestamp ON cross_message_v2 (sender, block_timestamp DESC);
|
||||
CREATE UNIQUE INDEX if not exists idx_cm_message_hash ON cross_message (message_hash);
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE IF EXISTS cross_message_v2;
|
||||
drop table if exists cross_message;
|
||||
-- +goose StatementEnd
|
||||
@@ -0,0 +1,20 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
create table batch_event
|
||||
(
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
batch_status SMALLINT NOT NULL,
|
||||
batch_index BIGINT NOT NULL,
|
||||
batch_hash VARCHAR NOT NULL,
|
||||
start_block_number BIGINT NOT NULL,
|
||||
end_block_number BIGINT NOT NULL,
|
||||
created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP(0) DEFAULT NULL
|
||||
);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
drop table if exists event_batch;
|
||||
-- +goose StatementEnd
|
||||
@@ -1,29 +0,0 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE TABLE batch_event_v2
|
||||
(
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
l1_block_number BIGINT NOT NULL,
|
||||
batch_status SMALLINT NOT NULL,
|
||||
batch_index BIGINT NOT NULL,
|
||||
batch_hash VARCHAR NOT NULL,
|
||||
start_block_number BIGINT NOT NULL,
|
||||
end_block_number BIGINT NOT NULL,
|
||||
update_status SMALLINT NOT NULL,
|
||||
created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP(0) DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS unique_idx_be_batch_hash ON batch_event_v2 (batch_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_be_l1_block_number ON batch_event_v2 (l1_block_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_be_batch_index ON batch_event_v2 (batch_index);
|
||||
CREATE INDEX IF NOT EXISTS idx_be_batch_index_batch_hash ON batch_event_v2 (batch_index, batch_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_be_end_block_number_update_status_batch_status_batch_index ON batch_event_v2 (end_block_number, update_status, batch_status, batch_index);
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE IF EXISTS batch_event_v2;
|
||||
-- +goose StatementEnd
|
||||
@@ -28,8 +28,8 @@ func Route(router *gin.Engine, conf *config.Config, reg prometheus.Registerer) {
|
||||
r := router.Group("api/")
|
||||
|
||||
r.GET("/txs", api.HistoryCtrler.GetTxsByAddress)
|
||||
r.GET("/l2/withdrawals", api.HistoryCtrler.GetL2WithdrawalsByAddress)
|
||||
r.GET("/l2/unclaimed/withdrawals", api.HistoryCtrler.GetL2UnclaimedWithdrawalsByAddress)
|
||||
r.GET("/withdrawals", api.HistoryCtrler.GetL2WithdrawalsByAddress)
|
||||
r.GET("/claimablewithdrawals", api.HistoryCtrler.GetL2ClaimableWithdrawalsByAddress)
|
||||
|
||||
r.POST("/txsbyhashes", api.HistoryCtrler.PostQueryTxsByHashes)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@ package types
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"scroll-tech/bridge-history-api/internal/orm"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -28,19 +27,19 @@ const (
|
||||
// QueryByAddressRequest the request parameter of address api
|
||||
type QueryByAddressRequest struct {
|
||||
Address string `form:"address" binding:"required"`
|
||||
Page uint64 `form:"page" binding:"required,min=1"`
|
||||
Page uint64 `form:"page" binding:"required"`
|
||||
PageSize uint64 `form:"page_size" binding:"required,min=1,max=100"`
|
||||
}
|
||||
|
||||
// QueryByHashRequest the request parameter of hash api
|
||||
type QueryByHashRequest struct {
|
||||
Txs []string `json:"txs" binding:"required,min=1,max=100"`
|
||||
Txs []string `raw:"txs" binding:"required"`
|
||||
}
|
||||
|
||||
// ResultData contains return txs and total
|
||||
type ResultData struct {
|
||||
Results []*TxHistoryInfo `json:"results"`
|
||||
Total uint64 `json:"total"`
|
||||
Result []*TxHistoryInfo `json:"result"`
|
||||
Total uint64 `json:"total"`
|
||||
}
|
||||
|
||||
// Response the response schema
|
||||
@@ -50,46 +49,37 @@ type Response struct {
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// CounterpartChainTx is the schema of counterpart chain tx info
|
||||
type CounterpartChainTx struct {
|
||||
// Finalized the schema of tx finalized infos
|
||||
type Finalized struct {
|
||||
Hash string `json:"hash"`
|
||||
BlockNumber uint64 `json:"block_number"`
|
||||
BlockNumber uint64 `json:"blockNumber"`
|
||||
}
|
||||
|
||||
// ClaimInfo is the schema of tx claim info
|
||||
type ClaimInfo struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Value string `json:"value"`
|
||||
Nonce string `json:"nonce"`
|
||||
Message string `json:"message"`
|
||||
Proof L2MessageProof `json:"proof"`
|
||||
Claimable bool `json:"claimable"`
|
||||
}
|
||||
|
||||
// L2MessageProof is the schema of L2 message proof
|
||||
type L2MessageProof struct {
|
||||
BatchIndex string `json:"batch_index"`
|
||||
MerkleProof string `json:"merkle_proof"`
|
||||
// UserClaimInfo the schema of tx claim infos
|
||||
type UserClaimInfo struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Value string `json:"value"`
|
||||
Nonce string `json:"nonce"`
|
||||
Message string `json:"message"`
|
||||
Proof string `json:"proof"`
|
||||
BatchIndex string `json:"batch_index"`
|
||||
Claimable bool `json:"claimable"`
|
||||
}
|
||||
|
||||
// TxHistoryInfo the schema of tx history infos
|
||||
type TxHistoryInfo struct {
|
||||
Hash string `json:"hash"`
|
||||
ReplayTxHash string `json:"replay_tx_hash"`
|
||||
RefundTxHash string `json:"refund_tx_hash"`
|
||||
MessageHash string `json:"message_hash"`
|
||||
TokenType orm.TokenType `json:"token_type"` // 0: unknown, 1: eth, 2: erc20, 3: erc721, 4: erc1155
|
||||
TokenIDs []string `json:"token_ids"` // only for erc721 and erc1155
|
||||
TokenAmounts []string `json:"token_amounts"` // for eth and erc20, the length is 1, for erc721 and erc1155, the length could be > 1
|
||||
MessageType orm.MessageType `json:"message_type"` // 0: unknown, 1: layer 1 message, 2: layer 2 message
|
||||
L1TokenAddress string `json:"l1_token_address"`
|
||||
L2TokenAddress string `json:"l2_token_address"`
|
||||
BlockNumber uint64 `json:"block_number"`
|
||||
TxStatus orm.TxStatusType `json:"tx_status"` // 0: sent, 1: sent failed, 2: relayed, 3: failed relayed, 4: relayed reverted, 5: skipped, 6: dropped
|
||||
CounterpartChainTx *CounterpartChainTx `json:"counterpart_chain_tx"`
|
||||
ClaimInfo *ClaimInfo `json:"claim_info"`
|
||||
BlockTimestamp uint64 `json:"block_timestamp"`
|
||||
Hash string `json:"hash"`
|
||||
MsgHash string `json:"msgHash"`
|
||||
Amount string `json:"amount"`
|
||||
IsL1 bool `json:"isL1"`
|
||||
L1Token string `json:"l1Token"`
|
||||
L2Token string `json:"l2Token"`
|
||||
BlockNumber uint64 `json:"blockNumber"`
|
||||
TxStatus int `json:"txStatus"`
|
||||
FinalizeTx *Finalized `json:"finalizeTx"`
|
||||
ClaimInfo *UserClaimInfo `json:"claimInfo"`
|
||||
CreatedAt *time.Time `json:"createdTime"`
|
||||
}
|
||||
|
||||
// RenderJSON renders response with json
|
||||
|
||||
@@ -6,15 +6,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/accounts/abi"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
backendabi "scroll-tech/bridge-history-api/abi"
|
||||
)
|
||||
@@ -114,72 +111,3 @@ func GetBatchRangeFromCalldata(calldata []byte) (uint64, uint64, error) {
|
||||
|
||||
return startBlock, finishBlock, err
|
||||
}
|
||||
|
||||
// GetBlocksInRange gets a batch of blocks for a block range [start, end] inclusive.
|
||||
func GetBlocksInRange(ctx context.Context, cli *ethclient.Client, start, end uint64) ([]*types.Block, error) {
|
||||
var (
|
||||
eg errgroup.Group
|
||||
blocks = make([]*types.Block, end-start+1)
|
||||
concurrency = 32
|
||||
sem = make(chan struct{}, concurrency)
|
||||
)
|
||||
|
||||
for i := start; i <= end; i++ {
|
||||
sem <- struct{}{} // Acquire a slot in the semaphore
|
||||
blockNum := int64(i)
|
||||
index := i - start
|
||||
eg.Go(func() error {
|
||||
defer func() { <-sem }() // Release the slot when done
|
||||
block, err := cli.BlockByNumber(ctx, big.NewInt(blockNum))
|
||||
if err != nil {
|
||||
log.Error("Failed to fetch block number", "number", blockNum, "error", err)
|
||||
return err
|
||||
}
|
||||
blocks[index] = block
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
log.Error("Error waiting for block fetching routines", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
// ConvertBigIntArrayToString convert the big int array to string
|
||||
func ConvertBigIntArrayToString(array []*big.Int) string {
|
||||
stringArray := make([]string, len(array))
|
||||
for i, num := range array {
|
||||
stringArray[i] = num.String()
|
||||
}
|
||||
|
||||
result := strings.Join(stringArray, ", ")
|
||||
return result
|
||||
}
|
||||
|
||||
// ConvertStringToStringArray takes a string with values separated by commas and returns a slice of strings
|
||||
func ConvertStringToStringArray(s string) []string {
|
||||
if s == "" {
|
||||
return []string{}
|
||||
}
|
||||
stringParts := strings.Split(s, ",")
|
||||
for i, part := range stringParts {
|
||||
stringParts[i] = strings.TrimSpace(part)
|
||||
}
|
||||
return stringParts
|
||||
}
|
||||
|
||||
// GetSkippedQueueIndices gets the skipped queue indices
|
||||
func GetSkippedQueueIndices(startIndex uint64, skippedBitmap *big.Int) []uint64 {
|
||||
var indices []uint64
|
||||
for i := 0; i < 256; i++ {
|
||||
index := startIndex + uint64(i)
|
||||
bit := new(big.Int).Rsh(skippedBitmap, uint(i))
|
||||
if bit.Bit(0) == 0 {
|
||||
continue
|
||||
}
|
||||
indices = append(indices, index)
|
||||
}
|
||||
return indices
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
@@ -37,55 +36,3 @@ func TestGetBatchRangeFromCalldata(t *testing.T) {
|
||||
assert.Equal(t, start, uint64(0))
|
||||
assert.Equal(t, finish, uint64(0))
|
||||
}
|
||||
|
||||
// TestConvertBigIntArrayToString tests the ConvertBigIntArrayToString function
|
||||
func TestConvertBigIntArrayToString(t *testing.T) {
|
||||
tests := []struct {
|
||||
array []*big.Int
|
||||
expected string
|
||||
}{
|
||||
{[]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, "1, 2, 3"},
|
||||
{[]*big.Int{big.NewInt(0), big.NewInt(-1)}, "0, -1"},
|
||||
{[]*big.Int{}, ""},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := ConvertBigIntArrayToString(test.array)
|
||||
assert.Equal(t, test.expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertStringToStringArray tests the ConvertStringToStringArray function
|
||||
func TestConvertStringToStringArray(t *testing.T) {
|
||||
tests := []struct {
|
||||
s string
|
||||
expected []string
|
||||
}{
|
||||
{"1, 2, 3", []string{"1", "2", "3"}},
|
||||
{" 4 , 5 , 6 ", []string{"4", "5", "6"}},
|
||||
{"", []string{}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := ConvertStringToStringArray(test.s)
|
||||
assert.Equal(t, test.expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetSkippedQueueIndices tests the GetSkippedQueueIndices function
|
||||
func TestGetSkippedQueueIndices(t *testing.T) {
|
||||
tests := []struct {
|
||||
startIndex uint64
|
||||
bitmap *big.Int
|
||||
expected []uint64
|
||||
}{
|
||||
{0, big.NewInt(0b101), []uint64{0, 2}},
|
||||
{10, big.NewInt(0b110), []uint64{11, 12}},
|
||||
{0, big.NewInt(0), nil}, // No bits set
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := GetSkippedQueueIndices(test.startIndex, test.bitmap)
|
||||
assert.Equal(t, test.expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
)
|
||||
|
||||
// MaxHeight is the maximum possible height of withdrawal trie
|
||||
// MaxHeight is the maixium possible height of withdraw trie
|
||||
const MaxHeight = 40
|
||||
|
||||
// WithdrawTrie is an append only merkle trie
|
||||
@@ -38,15 +38,14 @@ func NewWithdrawTrie() *WithdrawTrie {
|
||||
|
||||
// Initialize will initialize the merkle trie with rightest leaf node
|
||||
func (w *WithdrawTrie) Initialize(currentMessageNonce uint64, msgHash common.Hash, proofBytes []byte) {
|
||||
proof := decodeBytesToMerkleProof(proofBytes)
|
||||
branches := recoverBranchFromProof(proof, currentMessageNonce, msgHash)
|
||||
proof := DecodeBytesToMerkleProof(proofBytes)
|
||||
branches := RecoverBranchFromProof(proof, currentMessageNonce, msgHash)
|
||||
w.height = len(proof)
|
||||
w.branches = branches
|
||||
w.NextMessageNonce = currentMessageNonce + 1
|
||||
}
|
||||
|
||||
// AppendMessages appends a list of new messages as leaf nodes to the rightest of the tree and returns the proofs for all messages.
|
||||
// The function correctly returns the proofs for the entire tree after all messages have been inserted, not the individual proofs after each insertion.
|
||||
func (w *WithdrawTrie) AppendMessages(hashes []common.Hash) [][]byte {
|
||||
length := len(hashes)
|
||||
if length == 0 {
|
||||
@@ -94,7 +93,7 @@ func (w *WithdrawTrie) AppendMessages(hashes []common.Hash) [][]byte {
|
||||
|
||||
// update branches using hashes one by one
|
||||
for i := 0; i < length; i++ {
|
||||
proof := updateBranchWithNewMessage(w.zeroes, w.branches, w.NextMessageNonce, hashes[i])
|
||||
proof := UpdateBranchWithNewMessage(w.zeroes, w.branches, w.NextMessageNonce, hashes[i])
|
||||
w.NextMessageNonce++
|
||||
w.height = len(proof)
|
||||
}
|
||||
@@ -108,7 +107,7 @@ func (w *WithdrawTrie) AppendMessages(hashes []common.Hash) [][]byte {
|
||||
merkleProof = append(merkleProof, cache[h][index^1])
|
||||
index >>= 1
|
||||
}
|
||||
proofs[i] = encodeMerkleProofToBytes(merkleProof)
|
||||
proofs[i] = EncodeMerkleProofToBytes(merkleProof)
|
||||
}
|
||||
|
||||
return proofs
|
||||
@@ -122,8 +121,8 @@ func (w *WithdrawTrie) MessageRoot() common.Hash {
|
||||
return w.branches[w.height]
|
||||
}
|
||||
|
||||
// decodeBytesToMerkleProof transfer byte array to bytes32 array. The caller should make sure the length is matched.
|
||||
func decodeBytesToMerkleProof(proofBytes []byte) []common.Hash {
|
||||
// DecodeBytesToMerkleProof transfer byte array to bytes32 array. The caller should make sure the length is matched.
|
||||
func DecodeBytesToMerkleProof(proofBytes []byte) []common.Hash {
|
||||
proof := make([]common.Hash, len(proofBytes)/32)
|
||||
for i := 0; i < len(proofBytes); i += 32 {
|
||||
proof[i/32] = common.BytesToHash(proofBytes[i : i+32])
|
||||
@@ -131,8 +130,8 @@ func decodeBytesToMerkleProof(proofBytes []byte) []common.Hash {
|
||||
return proof
|
||||
}
|
||||
|
||||
// encodeMerkleProofToBytes transfer byte32 array to byte array by concatenation.
|
||||
func encodeMerkleProofToBytes(proof []common.Hash) []byte {
|
||||
// EncodeMerkleProofToBytes transfer byte32 array to byte array by concatenation.
|
||||
func EncodeMerkleProofToBytes(proof []common.Hash) []byte {
|
||||
var proofBytes []byte
|
||||
for i := 0; i < len(proof); i++ {
|
||||
proofBytes = append(proofBytes, proof[i][:]...)
|
||||
@@ -140,8 +139,8 @@ func encodeMerkleProofToBytes(proof []common.Hash) []byte {
|
||||
return proofBytes
|
||||
}
|
||||
|
||||
// updateBranchWithNewMessage update the branches to latest with new message and return the merkle proof for the message.
|
||||
func updateBranchWithNewMessage(zeroes []common.Hash, branches []common.Hash, index uint64, msgHash common.Hash) []common.Hash {
|
||||
// UpdateBranchWithNewMessage update the branches to latest with new message and return the merkle proof for the message.
|
||||
func UpdateBranchWithNewMessage(zeroes []common.Hash, branches []common.Hash, index uint64, msgHash common.Hash) []common.Hash {
|
||||
root := msgHash
|
||||
var merkleProof []common.Hash
|
||||
var height uint64
|
||||
@@ -163,8 +162,8 @@ func updateBranchWithNewMessage(zeroes []common.Hash, branches []common.Hash, in
|
||||
return merkleProof
|
||||
}
|
||||
|
||||
// recoverBranchFromProof will recover latest branches from merkle proof and message hash
|
||||
func recoverBranchFromProof(proof []common.Hash, index uint64, msgHash common.Hash) []common.Hash {
|
||||
// RecoverBranchFromProof will recover latest branches from merkle proof and message hash
|
||||
func RecoverBranchFromProof(proof []common.Hash, index uint64, msgHash common.Hash) []common.Hash {
|
||||
branches := make([]common.Hash, 64)
|
||||
root := msgHash
|
||||
var height uint64
|
||||
|
||||
@@ -16,29 +16,29 @@ func TestUpdateBranchWithNewMessage(t *testing.T) {
|
||||
zeroes[i] = Keccak2(zeroes[i-1], zeroes[i-1])
|
||||
}
|
||||
|
||||
updateBranchWithNewMessage(zeroes, branches, 0, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
UpdateBranchWithNewMessage(zeroes, branches, 0, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
if branches[0] != common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001") {
|
||||
t.Fatalf("Invalid root, want %s, got %s", "0x0000000000000000000000000000000000000000000000000000000000000001", branches[0].Hex())
|
||||
}
|
||||
|
||||
updateBranchWithNewMessage(zeroes, branches, 1, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002"))
|
||||
UpdateBranchWithNewMessage(zeroes, branches, 1, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002"))
|
||||
if branches[1] != common.HexToHash("0xe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0") {
|
||||
t.Fatalf("Invalid root, want %s, got %s", "0xe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0", branches[1].Hex())
|
||||
}
|
||||
|
||||
updateBranchWithNewMessage(zeroes, branches, 2, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000003"))
|
||||
UpdateBranchWithNewMessage(zeroes, branches, 2, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000003"))
|
||||
if branches[2] != common.HexToHash("0x222ff5e0b5877792c2bc1670e2ccd0c2c97cd7bb1672a57d598db05092d3d72c") {
|
||||
t.Fatalf("Invalid root, want %s, got %s", "0x222ff5e0b5877792c2bc1670e2ccd0c2c97cd7bb1672a57d598db05092d3d72c", branches[2].Hex())
|
||||
}
|
||||
|
||||
updateBranchWithNewMessage(zeroes, branches, 3, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000004"))
|
||||
UpdateBranchWithNewMessage(zeroes, branches, 3, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000004"))
|
||||
if branches[2] != common.HexToHash("0xa9bb8c3f1f12e9aa903a50c47f314b57610a3ab32f2d463293f58836def38d36") {
|
||||
t.Fatalf("Invalid root, want %s, got %s", "0xa9bb8c3f1f12e9aa903a50c47f314b57610a3ab32f2d463293f58836def38d36", branches[2].Hex())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeEncodeMerkleProof(t *testing.T) {
|
||||
proof := decodeBytesToMerkleProof(common.Hex2Bytes("2ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49012ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49022ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49032ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d4904"))
|
||||
proof := DecodeBytesToMerkleProof(common.Hex2Bytes("2ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49012ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49022ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49032ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d4904"))
|
||||
if len(proof) != 4 {
|
||||
t.Fatalf("proof length mismatch, want %d, got %d", 4, len(proof))
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func TestDecodeEncodeMerkleProof(t *testing.T) {
|
||||
t.Fatalf("proof[3] mismatch, want %s, got %s", "0x2ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d4904", proof[0].Hex())
|
||||
}
|
||||
|
||||
bytes := encodeMerkleProofToBytes(proof)
|
||||
bytes := EncodeMerkleProofToBytes(proof)
|
||||
if common.Bytes2Hex(bytes) != "2ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49012ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49022ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d49032ebffc1a6671c51e30777a680904b103992630ec995b6e6ff76a04d5259d4904" {
|
||||
t.Fatalf("wrong encoded bytes")
|
||||
}
|
||||
@@ -69,32 +69,32 @@ func TestRecoverBranchFromProof(t *testing.T) {
|
||||
zeroes[i] = Keccak2(zeroes[i-1], zeroes[i-1])
|
||||
}
|
||||
|
||||
proof := updateBranchWithNewMessage(zeroes, branches, 0, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
tmpBranches := recoverBranchFromProof(proof, 0, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
proof := UpdateBranchWithNewMessage(zeroes, branches, 0, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
tmpBranches := RecoverBranchFromProof(proof, 0, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
for i := 0; i < 64; i++ {
|
||||
if tmpBranches[i] != branches[i] {
|
||||
t.Fatalf("Invalid branch, want %s, got %s", branches[i].Hex(), tmpBranches[i].Hex())
|
||||
}
|
||||
}
|
||||
|
||||
proof = updateBranchWithNewMessage(zeroes, branches, 1, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002"))
|
||||
tmpBranches = recoverBranchFromProof(proof, 1, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002"))
|
||||
proof = UpdateBranchWithNewMessage(zeroes, branches, 1, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002"))
|
||||
tmpBranches = RecoverBranchFromProof(proof, 1, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002"))
|
||||
for i := 0; i < 64; i++ {
|
||||
if tmpBranches[i] != branches[i] {
|
||||
t.Fatalf("Invalid branch, want %s, got %s", branches[i].Hex(), tmpBranches[i].Hex())
|
||||
}
|
||||
}
|
||||
|
||||
proof = updateBranchWithNewMessage(zeroes, branches, 2, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000003"))
|
||||
tmpBranches = recoverBranchFromProof(proof, 2, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000003"))
|
||||
proof = UpdateBranchWithNewMessage(zeroes, branches, 2, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000003"))
|
||||
tmpBranches = RecoverBranchFromProof(proof, 2, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000003"))
|
||||
for i := 0; i < 64; i++ {
|
||||
if tmpBranches[i] != branches[i] {
|
||||
t.Fatalf("Invalid branch, want %s, got %s", branches[i].Hex(), tmpBranches[i].Hex())
|
||||
}
|
||||
}
|
||||
|
||||
proof = updateBranchWithNewMessage(zeroes, branches, 3, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000004"))
|
||||
tmpBranches = recoverBranchFromProof(proof, 3, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000004"))
|
||||
proof = UpdateBranchWithNewMessage(zeroes, branches, 3, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000004"))
|
||||
tmpBranches = RecoverBranchFromProof(proof, 3, common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000004"))
|
||||
for i := 0; i < 64; i++ {
|
||||
if tmpBranches[i] != branches[i] {
|
||||
t.Fatalf("Invalid branch, want %s, got %s", branches[i].Hex(), tmpBranches[i].Hex())
|
||||
@@ -123,7 +123,7 @@ func TestWithdrawTrieOneByOne(t *testing.T) {
|
||||
})
|
||||
assert.Equal(t, withdrawTrie.NextMessageNonce, uint64(i+1))
|
||||
assert.Equal(t, expectedRoot.String(), withdrawTrie.MessageRoot().String())
|
||||
proof := decodeBytesToMerkleProof(proofBytes[0])
|
||||
proof := DecodeBytesToMerkleProof(proofBytes[0])
|
||||
verifiedRoot := verifyMerkleProof(uint64(i), hash, proof)
|
||||
assert.Equal(t, expectedRoot.String(), verifiedRoot.String())
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func TestWithdrawTrieMultiple(t *testing.T) {
|
||||
|
||||
for i := initial; i <= finish; i++ {
|
||||
hash := common.BigToHash(big.NewInt(int64(i + 1)))
|
||||
proof := decodeBytesToMerkleProof(proofBytes[i-initial])
|
||||
proof := DecodeBytesToMerkleProof(proofBytes[i-initial])
|
||||
verifiedRoot := verifyMerkleProof(uint64(i), hash, proof)
|
||||
assert.Equal(t, expectedRoots[finish].String(), verifiedRoot.String())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Source: https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml
|
||||
# options for analysis running
|
||||
run:
|
||||
# default concurrency is the available CPU number
|
||||
# default concurrency is a available CPU number
|
||||
concurrency: 4
|
||||
|
||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# Download Go dependencies
|
||||
FROM golang:1.20-alpine3.16 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod* ./
|
||||
COPY ./bridge-history-api/go.* ./
|
||||
RUN go mod download -x
|
||||
|
||||
# Build bridgehistoryapi-api
|
||||
FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/bridge-history-api/cmd/api && go build -v -p 4 -o /bin/bridgehistoryapi-api
|
||||
|
||||
# Pull bridgehistoryapi-api into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/bridgehistoryapi-api /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["bridgehistoryapi-api"]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Download Go dependencies
|
||||
FROM golang:1.20-alpine3.16 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod* ./
|
||||
COPY ./bridge-history-api/go.* ./
|
||||
RUN go mod download -x
|
||||
|
||||
# Build bridgehistoryapi-cross-msg-fetcher
|
||||
FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/bridge-history-api/cmd/cross_msg_fetcher && go build -v -p 4 -o /bin/bridgehistoryapi-cross-msg-fetcher
|
||||
|
||||
# Pull bridgehistoryapi-cross-msg-fetcher into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/bridgehistoryapi-cross-msg-fetcher /bin/
|
||||
|
||||
ENTRYPOINT ["bridgehistoryapi-cross-msg-fetcher"]
|
||||
@@ -14,6 +14,7 @@ RUN --mount=target=. \
|
||||
|
||||
# Pull db_cli into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/db_cli /bin/
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["db_cli"]
|
||||
@@ -1,21 +0,0 @@
|
||||
# Download Go dependencies
|
||||
FROM golang:1.20-alpine3.16 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod* ./
|
||||
COPY ./bridge-history-api/go.* ./
|
||||
RUN go mod download -x
|
||||
|
||||
# Build bridgehistoryapi-fetcher
|
||||
FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/bridge-history-api/cmd/fetcher && go build -v -p 4 -o /bin/bridgehistoryapi-fetcher
|
||||
|
||||
# Pull bridgehistoryapi-fetcher into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/bridgehistoryapi-fetcher /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["bridgehistoryapi-fetcher"]
|
||||
21
build/dockerfiles/bridgehistoryapi-server.Dockerfile
Normal file
21
build/dockerfiles/bridgehistoryapi-server.Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
||||
# Download Go dependencies
|
||||
FROM golang:1.20-alpine3.16 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod* ./
|
||||
COPY ./bridge-history-api/go.* ./
|
||||
RUN go mod download -x
|
||||
|
||||
# Build bridgehistoryapi-server
|
||||
FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/bridge-history-api/cmd/backend_server && go build -v -p 4 -o /bin/bridgehistoryapi-server
|
||||
|
||||
# Pull bridgehistoryapi-server into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/bridgehistoryapi-server /bin/
|
||||
|
||||
ENTRYPOINT ["bridgehistoryapi-server"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Build libzkp dependency
|
||||
FROM scrolltech/go-rust-builder:go-1.20-rust-nightly-2022-12-10 as chef
|
||||
FROM scrolltech/go-rust-builder:go-1.19-rust-nightly-2022-12-10 as chef
|
||||
WORKDIR app
|
||||
|
||||
FROM chef as planner
|
||||
@@ -17,7 +17,7 @@ RUN find ./ | grep libzktrie.so | xargs -I{} cp {} /app/target/release/
|
||||
|
||||
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-rust-builder:go-1.20-rust-nightly-2022-12-10 as base
|
||||
FROM scrolltech/go-rust-builder:go-1.19-rust-nightly-2022-12-10 as base
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
COPY ./rollup/go.* ./rollup/
|
||||
@@ -46,5 +46,5 @@ RUN mkdir -p /src/coordinator/internal/logic/verifier/lib
|
||||
COPY --from=builder /bin/lib /src/coordinator/internal/logic/verifier/lib
|
||||
COPY --from=builder /bin/coordinator_api /bin/
|
||||
RUN /bin/coordinator_api --version
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["/bin/coordinator_api"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-alpine-builder:1.20 as base
|
||||
FROM scrolltech/go-alpine-builder:1.19 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
@@ -21,5 +21,5 @@ RUN --mount=target=. \
|
||||
# Pull coordinator into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /bin/coordinator_cron /bin/
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["coordinator_cron"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-alpine-builder:1.20 as base
|
||||
FROM scrolltech/go-alpine-builder:1.19 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
@@ -21,6 +21,7 @@ RUN --mount=target=. \
|
||||
|
||||
# Pull db_cli into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/db_cli /bin/
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["db_cli"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-alpine-builder:1.20 as base
|
||||
FROM scrolltech/go-alpine-builder:1.19 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
@@ -21,6 +21,7 @@ RUN --mount=target=. \
|
||||
|
||||
# Pull event_watcher into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/event_watcher /bin/
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["event_watcher"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-alpine-builder:1.20 as base
|
||||
FROM scrolltech/go-alpine-builder:1.19 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
@@ -21,6 +21,7 @@ RUN --mount=target=. \
|
||||
|
||||
# Pull gas_oracle into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/gas_oracle /bin/
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["gas_oracle"]
|
||||
@@ -1,5 +1,5 @@
|
||||
ifeq ($(GO_VERSION),)
|
||||
GO_VERSION=1.20
|
||||
GO_VERSION=1.19
|
||||
endif
|
||||
ifeq ($(RUST_VERSION),)
|
||||
RUST_VERSION=nightly-2022-12-10
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ARG CUDA_VERSION=11.7.1
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.19
|
||||
ARG RUST_VERSION=nightly-2022-12-10
|
||||
ARG CARGO_CHEF_TAG=0.1.41
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.19
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.19
|
||||
ARG RUST_VERSION=nightly-2022-12-10
|
||||
ARG CARGO_CHEF_TAG=0.1.41
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.19
|
||||
ARG RUST_VERSION=nightly-2022-12-10
|
||||
ARG CARGO_CHEF_TAG=0.1.41
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Start from the latest golang base image
|
||||
FROM golang:1.21
|
||||
FROM golang:1.19
|
||||
|
||||
# Install Docker
|
||||
RUN apt-get update && apt-get install -y docker.io docker-compose
|
||||
RUN apt-get update && apt-get install -y docker.io
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /go/src/app
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-alpine-builder:1.20 as base
|
||||
FROM scrolltech/go-alpine-builder:1.19 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
@@ -21,6 +21,7 @@ RUN --mount=target=. \
|
||||
|
||||
# Pull rollup_relayer into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/rollup_relayer /bin/
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["rollup_relayer"]
|
||||
26
build/run_tests.sh
Executable file
26
build/run_tests.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
set -uex
|
||||
|
||||
profile_name=$1
|
||||
|
||||
exclude_dirs=("scroll-tech/rollup/cmd" "scroll-tech/rollup/tests" "scroll-tech/rollup/mock_bridge" "scroll-tech/coordinator/cmd" "scroll-tech/coordinator/internal/logic/verifier")
|
||||
|
||||
all_packages=$(go list ./... | grep -v "^scroll-tech/${profile_name}$")
|
||||
coverpkg="scroll-tech/${profile_name}"
|
||||
|
||||
for pkg in $all_packages; do
|
||||
exclude_pkg=false
|
||||
for exclude_dir in "${exclude_dirs[@]}"; do
|
||||
if [[ $pkg == $exclude_dir* ]]; then
|
||||
exclude_pkg=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$exclude_pkg" = false ]; then
|
||||
coverpkg="$coverpkg,$pkg/..."
|
||||
fi
|
||||
done
|
||||
|
||||
echo "coverage.${profile_name}.txt"
|
||||
go test -v -race -gcflags="-l" -ldflags="-s=false" -coverpkg="$coverpkg" -coverprofile=../coverage.${profile_name}.txt -covermode=atomic ./...
|
||||
@@ -36,8 +36,3 @@ flag_management:
|
||||
- type: project
|
||||
target: auto
|
||||
threshold: 1%
|
||||
- name: contracts
|
||||
statuses:
|
||||
- type: project
|
||||
target: auto
|
||||
threshold: 1%
|
||||
|
||||
@@ -15,7 +15,7 @@ var verbose bool
|
||||
|
||||
func init() {
|
||||
v := os.Getenv("LOG_DOCKER")
|
||||
if strings.ToLower(v) == "true" {
|
||||
if v == "true" || v == "TRUE" {
|
||||
verbose = true
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,8 @@ func (c *Cmd) Write(data []byte) (int, error) {
|
||||
if verbose || c.openLog {
|
||||
fmt.Printf("%s:\n\t%v", c.name, out)
|
||||
} else if strings.Contains(strings.ToLower(out), "error") ||
|
||||
strings.Contains(strings.ToLower(out), "warning") {
|
||||
strings.Contains(strings.ToLower(out), "warning") ||
|
||||
strings.Contains(strings.ToLower(out), "info") {
|
||||
fmt.Printf("%s:\n\t%v", c.name, out)
|
||||
}
|
||||
go c.checkFuncs.IterCb(func(_ string, value interface{}) {
|
||||
|
||||
@@ -48,7 +48,7 @@ func (c *Cmd) WaitExit() {
|
||||
select {
|
||||
case err = <-c.ErrChan:
|
||||
if err != nil {
|
||||
fmt.Printf("%s appear error during running, err: %v\n", c.name, err)
|
||||
fmt.Printf("%s appear error durning running, err: %v\n", c.name, err)
|
||||
}
|
||||
default:
|
||||
<-time.After(time.Millisecond * 500)
|
||||
|
||||
@@ -70,9 +70,6 @@ func InitDB(config *Config) (*gorm.DB, error) {
|
||||
return nil, pingErr
|
||||
}
|
||||
|
||||
sqlDB.SetConnMaxLifetime(time.Minute * 10)
|
||||
sqlDB.SetConnMaxIdleTime(time.Minute * 5)
|
||||
|
||||
sqlDB.SetMaxOpenConns(config.MaxOpenNum)
|
||||
sqlDB.SetMaxIdleConns(config.MaxIdleNum)
|
||||
|
||||
|
||||
@@ -1,27 +1,62 @@
|
||||
package database_test
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"scroll-tech/common/database"
|
||||
"scroll-tech/common/testcontainers"
|
||||
"scroll-tech/common/docker"
|
||||
"scroll-tech/common/version"
|
||||
)
|
||||
|
||||
func TestGormLogger(t *testing.T) {
|
||||
output := io.Writer(os.Stderr)
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream := log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger := log.NewGlogHandler(ostream)
|
||||
// Set log level
|
||||
glogger.Verbosity(log.LvlTrace)
|
||||
log.Root().SetHandler(glogger)
|
||||
|
||||
var gl gormLogger
|
||||
gl.gethLogger = log.Root()
|
||||
|
||||
gl.Error(context.Background(), "test %s error:%v", "testError", errors.New("test error"))
|
||||
gl.Warn(context.Background(), "test %s warn:%v", "testWarn", errors.New("test warn"))
|
||||
gl.Info(context.Background(), "test %s warn:%v", "testInfo", errors.New("test info"))
|
||||
gl.Trace(context.Background(), time.Now(), func() (string, int64) { return "test trace", 1 }, nil)
|
||||
}
|
||||
|
||||
func TestDB(t *testing.T) {
|
||||
version.Version = "v4.1.98-aaa-bbb-ccc"
|
||||
base := docker.NewDockerApp()
|
||||
base.RunDBImage(t)
|
||||
|
||||
testApps := testcontainers.NewTestcontainerApps()
|
||||
assert.NoError(t, testApps.StartPostgresContainer())
|
||||
dbCfg := &Config{
|
||||
DSN: base.DBConfig.DSN,
|
||||
DriverName: base.DBConfig.DriverName,
|
||||
MaxOpenNum: base.DBConfig.MaxOpenNum,
|
||||
MaxIdleNum: base.DBConfig.MaxIdleNum,
|
||||
}
|
||||
|
||||
db, err := testApps.GetGormDBClient()
|
||||
var err error
|
||||
db, err := InitDB(dbCfg)
|
||||
assert.NoError(t, err)
|
||||
|
||||
sqlDB, err := database.Ping(db)
|
||||
sqlDB, err := Ping(db)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, sqlDB)
|
||||
|
||||
assert.NoError(t, database.CloseDB(db))
|
||||
assert.NoError(t, CloseDB(db))
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
)
|
||||
|
||||
func TestGormLogger(t *testing.T) {
|
||||
output := io.Writer(os.Stderr)
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream := log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger := log.NewGlogHandler(ostream)
|
||||
// Set log level
|
||||
glogger.Verbosity(log.LvlTrace)
|
||||
log.Root().SetHandler(glogger)
|
||||
|
||||
var gl gormLogger
|
||||
gl.gethLogger = log.Root()
|
||||
|
||||
gl.Error(context.Background(), "test %s error:%v", "testError", errors.New("test error"))
|
||||
gl.Warn(context.Background(), "test %s warn:%v", "testWarn", errors.New("test warn"))
|
||||
gl.Info(context.Background(), "test %s warn:%v", "testInfo", errors.New("test info"))
|
||||
gl.Trace(context.Background(), time.Now(), func() (string, int64) { return "test trace", 1 }, nil)
|
||||
}
|
||||
7
common/docker-compose/l1/.gitignore
vendored
7
common/docker-compose/l1/.gitignore
vendored
@@ -1,7 +0,0 @@
|
||||
consensus/beacondata*
|
||||
consensus/genesis.ssz
|
||||
consensus/validatordata*
|
||||
consensus/data*
|
||||
execution/geth
|
||||
execution/geth.ipc
|
||||
execution/data*
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Loop until no Docker containers matching 'posl1' are found
|
||||
while : ; do
|
||||
containers=$(docker ps -a --format '{{.Names}}' | grep posl1)
|
||||
if [[ -z "$containers" ]]; then
|
||||
break
|
||||
fi
|
||||
echo "find the following containers, removing..."
|
||||
echo "$containers"
|
||||
echo "$containers" | xargs -r docker stop
|
||||
echo "$containers" | xargs -r docker rm -f || echo "Warning: Failed to remove some containers."
|
||||
done
|
||||
|
||||
# Loop until no Docker networks matching 'posl1' are found
|
||||
while : ; do
|
||||
networks=$(docker network ls --format '{{.ID}} {{.Name}}' | grep posl1 | awk '{print $1}')
|
||||
if [[ -z "$networks" ]]; then
|
||||
break
|
||||
fi
|
||||
echo "find the following networks, removing..."
|
||||
echo "$networks"
|
||||
echo "$networks" | xargs -r docker network rm || echo "Warning: Failed to remove some networks."
|
||||
done
|
||||
@@ -1,30 +0,0 @@
|
||||
CONFIG_NAME: interop
|
||||
PRESET_BASE: interop
|
||||
|
||||
# Genesis
|
||||
GENESIS_FORK_VERSION: 0x20000089
|
||||
|
||||
# Altair
|
||||
ALTAIR_FORK_EPOCH: 0
|
||||
ALTAIR_FORK_VERSION: 0x20000090
|
||||
|
||||
# Merge
|
||||
BELLATRIX_FORK_EPOCH: 0
|
||||
BELLATRIX_FORK_VERSION: 0x20000091
|
||||
TERMINAL_TOTAL_DIFFICULTY: 0
|
||||
|
||||
# Capella
|
||||
CAPELLA_FORK_EPOCH: 0
|
||||
CAPELLA_FORK_VERSION: 0x20000092
|
||||
MAX_WITHDRAWALS_PER_PAYLOAD: 16
|
||||
|
||||
# Deneb
|
||||
DENEB_FORK_EPOCH: 0
|
||||
DENEB_FORK_VERSION: 0x20000093
|
||||
|
||||
# Time parameters
|
||||
SECONDS_PER_SLOT: 2
|
||||
SLOTS_PER_EPOCH: 2
|
||||
|
||||
# Deposit contract
|
||||
DEPOSIT_CONTRACT_ADDRESS: 0x4242424242424242424242424242424242424242
|
||||
@@ -1,127 +0,0 @@
|
||||
package dockercompose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
tc "github.com/testcontainers/testcontainers-go/modules/compose"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
)
|
||||
|
||||
// PoSL1TestEnv represents the config needed to test in PoS Layer 1.
|
||||
type PoSL1TestEnv struct {
|
||||
dockerComposeFile string
|
||||
compose tc.ComposeStack
|
||||
gethHTTPPort int
|
||||
hostPath string
|
||||
}
|
||||
|
||||
// NewPoSL1TestEnv creates and initializes a new instance of PoSL1TestEnv with a random HTTP port.
|
||||
func NewPoSL1TestEnv() (*PoSL1TestEnv, error) {
|
||||
rootDir, err := findProjectRootDir()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find project root directory: %v", err)
|
||||
}
|
||||
|
||||
hostPath, found := os.LookupEnv("HOST_PATH")
|
||||
if !found {
|
||||
hostPath = ""
|
||||
}
|
||||
|
||||
rnd, err := rand.Int(rand.Reader, big.NewInt(65536-1024))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate a random: %v", err)
|
||||
}
|
||||
gethHTTPPort := int(rnd.Int64()) + 1024
|
||||
|
||||
if err := os.Setenv("GETH_HTTP_PORT", fmt.Sprintf("%d", gethHTTPPort)); err != nil {
|
||||
return nil, fmt.Errorf("failed to set GETH_HTTP_PORT: %v", err)
|
||||
}
|
||||
|
||||
return &PoSL1TestEnv{
|
||||
dockerComposeFile: filepath.Join(rootDir, "common", "docker-compose", "l1", "docker-compose.yml"),
|
||||
gethHTTPPort: gethHTTPPort,
|
||||
hostPath: hostPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Start starts the PoS L1 test environment by running the associated Docker Compose configuration.
|
||||
func (e *PoSL1TestEnv) Start() error {
|
||||
var err error
|
||||
e.compose, err = tc.NewDockerCompose([]string{e.dockerComposeFile}...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create docker compose: %w", err)
|
||||
}
|
||||
|
||||
env := map[string]string{
|
||||
"GETH_HTTP_PORT": fmt.Sprintf("%d", e.gethHTTPPort),
|
||||
}
|
||||
|
||||
if e.hostPath != "" {
|
||||
env["HOST_PATH"] = e.hostPath
|
||||
}
|
||||
|
||||
if err = e.compose.WaitForService("geth", wait.NewHTTPStrategy("/").WithPort("8545/tcp").WithStartupTimeout(15*time.Second)).WithEnv(env).Up(context.Background()); err != nil {
|
||||
if errStop := e.Stop(); errStop != nil {
|
||||
log.Error("failed to stop PoS L1 test environment", "err", errStop)
|
||||
}
|
||||
return fmt.Errorf("failed to start PoS L1 test environment: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the PoS L1 test environment by stopping and removing the associated Docker Compose services.
|
||||
func (e *PoSL1TestEnv) Stop() error {
|
||||
if e.compose != nil {
|
||||
if err := e.compose.Down(context.Background(), tc.RemoveOrphans(true), tc.RemoveVolumes(true), tc.RemoveImagesLocal); err != nil {
|
||||
return fmt.Errorf("failed to stop PoS L1 test environment: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Endpoint returns the HTTP endpoint for the PoS L1 test environment.
|
||||
func (e *PoSL1TestEnv) Endpoint() string {
|
||||
return fmt.Sprintf("http://127.0.0.1:%d", e.gethHTTPPort)
|
||||
}
|
||||
|
||||
// L1Client returns an ethclient by dialing the running PoS L1 test environment
|
||||
func (e *PoSL1TestEnv) L1Client() (*ethclient.Client, error) {
|
||||
if e == nil {
|
||||
return nil, fmt.Errorf("PoS L1 test environment is not initialized")
|
||||
}
|
||||
|
||||
client, err := ethclient.Dial(e.Endpoint())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to dial PoS L1 test environment: %w", err)
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func findProjectRootDir() (string, error) {
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get working directory: %w", err)
|
||||
}
|
||||
|
||||
for {
|
||||
_, err := os.Stat(filepath.Join(currentDir, "go.work"))
|
||||
if err == nil {
|
||||
return currentDir, nil
|
||||
}
|
||||
|
||||
parentDir := filepath.Dir(currentDir)
|
||||
if parentDir == currentDir {
|
||||
return "", fmt.Errorf("go.work file not found in any parent directory")
|
||||
}
|
||||
|
||||
currentDir = parentDir
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
initialize-env:
|
||||
image: "alpine:3.19.0"
|
||||
command:
|
||||
/bin/sh -c "mkdir -p /data/consensus &&
|
||||
cp -a /consensus/* /data/consensus/ &&
|
||||
mkdir -p /data/execution &&
|
||||
cp -a /execution/* /data/execution/"
|
||||
volumes:
|
||||
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus:/consensus
|
||||
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution:/execution
|
||||
- data:/data
|
||||
|
||||
# Creates a genesis state for the beacon chain using a YAML configuration file and
|
||||
# a deterministic set of 64 validators.
|
||||
create-beacon-chain-genesis:
|
||||
image: "gcr.io/prysmaticlabs/prysm/cmd/prysmctl:latest"
|
||||
command:
|
||||
- testnet
|
||||
- generate-genesis
|
||||
- --fork=deneb
|
||||
- --num-validators=64
|
||||
- --genesis-time-delay=3
|
||||
- --output-ssz=/data/consensus/genesis.ssz
|
||||
- --chain-config-file=/data/consensus/config.yml
|
||||
- --geth-genesis-json-in=/data/execution/genesis.json
|
||||
- --geth-genesis-json-out=/data/execution/genesis.json
|
||||
volumes:
|
||||
- data:/data
|
||||
depends_on:
|
||||
initialize-env:
|
||||
condition: service_completed_successfully
|
||||
|
||||
# Sets up the genesis configuration for the go-ethereum client from a JSON file.
|
||||
geth-genesis:
|
||||
image: "ethereum/client-go:v1.13.14"
|
||||
command: --datadir=/data/execution init /data/execution/genesis.json
|
||||
volumes:
|
||||
- data:/data
|
||||
depends_on:
|
||||
create-beacon-chain-genesis:
|
||||
condition: service_completed_successfully
|
||||
initialize-env:
|
||||
condition: service_completed_successfully
|
||||
|
||||
# Runs a Prysm beacon chain from a specified genesis state created in the previous step
|
||||
# and connects to go-ethereum in the same network as the execution client.
|
||||
# The account used in go-ethereum is set as the suggested fee recipient for transactions
|
||||
# proposed via the validators attached to the beacon node.
|
||||
beacon-chain:
|
||||
image: "gcr.io/prysmaticlabs/prysm/beacon-chain:v5.0.0"
|
||||
command:
|
||||
- --datadir=/data/consensus/beacondata
|
||||
# No peers to sync with in this testnet, so setting to 0
|
||||
- --min-sync-peers=0
|
||||
- --genesis-state=/data/consensus/genesis.ssz
|
||||
- --bootstrap-node=
|
||||
- --interop-eth1data-votes
|
||||
# The chain configuration file used for setting up Prysm
|
||||
- --chain-config-file=/data/consensus/config.yml
|
||||
# We specify the chain id used by our execution client
|
||||
- --contract-deployment-block=0
|
||||
- --chain-id=${CHAIN_ID:-32382}
|
||||
- --rpc-host=0.0.0.0
|
||||
- --grpc-gateway-host=0.0.0.0
|
||||
- --execution-endpoint=http://geth:8551
|
||||
- --accept-terms-of-use
|
||||
- --jwt-secret=/data/execution/jwtsecret
|
||||
- --suggested-fee-recipient=0x123463a4b065722e99115d6c222f267d9cabb524
|
||||
- --minimum-peers-per-subnet=0
|
||||
- --enable-debug-rpc-endpoints
|
||||
- --force-clear-db
|
||||
depends_on:
|
||||
create-beacon-chain-genesis:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- data:/data
|
||||
|
||||
# Runs the go-ethereum execution client with the specified, unlocked account and necessary
|
||||
# APIs to allow for proof-of-stake consensus via Prysm.
|
||||
geth:
|
||||
image: "ethereum/client-go:v1.13.14"
|
||||
command:
|
||||
- --http
|
||||
- --http.api=eth,net,web3
|
||||
- --http.addr=0.0.0.0
|
||||
- --http.corsdomain=*
|
||||
- --authrpc.vhosts=*
|
||||
- --authrpc.addr=0.0.0.0
|
||||
- --authrpc.jwtsecret=/data/execution/jwtsecret
|
||||
- --datadir=/data/execution
|
||||
- --allow-insecure-unlock
|
||||
- --unlock=0x123463a4b065722e99115d6c222f267d9cabb524
|
||||
- --password=/data/execution/geth_password.txt
|
||||
- --nodiscover
|
||||
- --syncmode=full
|
||||
ports:
|
||||
- ${GETH_HTTP_PORT:-8545}:8545
|
||||
depends_on:
|
||||
geth-genesis:
|
||||
condition: service_completed_successfully
|
||||
beacon-chain:
|
||||
condition: service_started
|
||||
volumes:
|
||||
- data:/data
|
||||
|
||||
# We run a validator client with 64, deterministically-generated keys that match
|
||||
# The validator keys present in the beacon chain genesis state generated a few steps above.
|
||||
validator:
|
||||
image: "gcr.io/prysmaticlabs/prysm/validator:v5.0.0"
|
||||
command:
|
||||
- --beacon-rpc-provider=beacon-chain:4000
|
||||
- --datadir=/data/consensus/validatordata
|
||||
- --accept-terms-of-use
|
||||
- --interop-num-validators=64
|
||||
- --interop-start-index=0
|
||||
- --chain-config-file=/data/consensus/config.yml
|
||||
- --force-clear-db
|
||||
depends_on:
|
||||
beacon-chain:
|
||||
condition: service_started
|
||||
volumes:
|
||||
- data:/data
|
||||
|
||||
volumes:
|
||||
data:
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
0xfad2709d0bb03bf0e8ba3c99bea194575d3e98863133d1af638ed056d1d59345
|
||||
@@ -1 +0,0 @@
|
||||
{"address":"123463a4b065722e99115d6c222f267d9cabb524","crypto":{"cipher":"aes-128-ctr","ciphertext":"93b90389b855889b9f91c89fd15b9bd2ae95b06fe8e2314009fc88859fc6fde9","cipherparams":{"iv":"9dc2eff7967505f0e6a40264d1511742"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c07503bb1b66083c37527cd8f06f8c7c1443d4c724767f625743bd47ae6179a4"},"mac":"6d359be5d6c432d5bbb859484009a4bf1bd71b76e89420c380bd0593ce25a817"},"id":"622df904-0bb1-4236-b254-f1b8dfdff1ec","version":3}
|
||||
196
common/docker/docker_app.go
Normal file
196
common/docker/docker_app.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"scroll-tech/database"
|
||||
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
l1StartPort = 10000
|
||||
l2StartPort = 20000
|
||||
dbStartPort = 30000
|
||||
)
|
||||
|
||||
// AppAPI app interface.
|
||||
type AppAPI interface {
|
||||
IsRunning() bool
|
||||
WaitResult(t *testing.T, timeout time.Duration, keyword string) bool
|
||||
RunApp(waitResult func() bool)
|
||||
WaitExit()
|
||||
ExpectWithTimeout(t *testing.T, parallel bool, timeout time.Duration, keyword string)
|
||||
}
|
||||
|
||||
// App is collection struct of runtime docker images
|
||||
type App struct {
|
||||
L1gethImg GethImgInstance
|
||||
L2gethImg GethImgInstance
|
||||
DBImg ImgInstance
|
||||
|
||||
dbClient *sql.DB
|
||||
DBConfig *database.DBConfig
|
||||
DBConfigFile string
|
||||
|
||||
// common time stamp.
|
||||
Timestamp int
|
||||
}
|
||||
|
||||
// NewDockerApp returns new instance of dokerApp struct
|
||||
func NewDockerApp() *App {
|
||||
timestamp := time.Now().Nanosecond()
|
||||
app := &App{
|
||||
Timestamp: timestamp,
|
||||
L1gethImg: newTestL1Docker(),
|
||||
L2gethImg: newTestL2Docker(),
|
||||
DBImg: newTestDBDocker("postgres"),
|
||||
DBConfigFile: fmt.Sprintf("/tmp/%d_db-config.json", timestamp),
|
||||
}
|
||||
if err := app.mockDBConfig(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// RunImages runs all images togather
|
||||
func (b *App) RunImages(t *testing.T) {
|
||||
b.RunDBImage(t)
|
||||
b.RunL1Geth(t)
|
||||
b.RunL2Geth(t)
|
||||
}
|
||||
|
||||
// RunDBImage starts postgres docker container.
|
||||
func (b *App) RunDBImage(t *testing.T) {
|
||||
if b.DBImg.IsRunning() {
|
||||
return
|
||||
}
|
||||
assert.NoError(t, b.DBImg.Start())
|
||||
|
||||
// try 5 times until the db is ready.
|
||||
ok := utils.TryTimes(10, func() bool {
|
||||
db, err := sqlx.Open("postgres", b.DBImg.Endpoint())
|
||||
return err == nil && db != nil && db.Ping() == nil
|
||||
})
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
// Free clear all running images, double check and recycle docker container.
|
||||
func (b *App) Free() {
|
||||
if b.L1gethImg.IsRunning() {
|
||||
_ = b.L1gethImg.Stop()
|
||||
}
|
||||
if b.L2gethImg.IsRunning() {
|
||||
_ = b.L2gethImg.Stop()
|
||||
}
|
||||
if b.DBImg.IsRunning() {
|
||||
_ = b.DBImg.Stop()
|
||||
_ = os.Remove(b.DBConfigFile)
|
||||
if !utils.IsNil(b.dbClient) {
|
||||
_ = b.dbClient.Close()
|
||||
b.dbClient = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RunL1Geth starts l1geth docker container.
|
||||
func (b *App) RunL1Geth(t *testing.T) {
|
||||
if b.L1gethImg.IsRunning() {
|
||||
return
|
||||
}
|
||||
assert.NoError(t, b.L1gethImg.Start())
|
||||
}
|
||||
|
||||
// L1Client returns a ethclient by dialing running l1geth
|
||||
func (b *App) L1Client() (*ethclient.Client, error) {
|
||||
if utils.IsNil(b.L1gethImg) {
|
||||
return nil, fmt.Errorf("l1 geth is not running")
|
||||
}
|
||||
client, err := ethclient.Dial(b.L1gethImg.Endpoint())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// RunL2Geth starts l2geth docker container.
|
||||
func (b *App) RunL2Geth(t *testing.T) {
|
||||
if b.L2gethImg.IsRunning() {
|
||||
return
|
||||
}
|
||||
assert.NoError(t, b.L2gethImg.Start())
|
||||
}
|
||||
|
||||
// L2Client returns a ethclient by dialing running l2geth
|
||||
func (b *App) L2Client() (*ethclient.Client, error) {
|
||||
if utils.IsNil(b.L2gethImg) {
|
||||
return nil, fmt.Errorf("l2 geth is not running")
|
||||
}
|
||||
client, err := ethclient.Dial(b.L2gethImg.Endpoint())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// DBClient create and return *sql.DB instance.
|
||||
func (b *App) DBClient(t *testing.T) *sql.DB {
|
||||
if !utils.IsNil(b.dbClient) {
|
||||
return b.dbClient
|
||||
}
|
||||
var (
|
||||
cfg = b.DBConfig
|
||||
err error
|
||||
)
|
||||
b.dbClient, err = sql.Open(cfg.DriverName, cfg.DSN)
|
||||
assert.NoError(t, err)
|
||||
b.dbClient.SetMaxOpenConns(cfg.MaxOpenNum)
|
||||
b.dbClient.SetMaxIdleConns(cfg.MaxIdleNum)
|
||||
assert.NoError(t, b.dbClient.Ping())
|
||||
return b.dbClient
|
||||
}
|
||||
|
||||
func (b *App) mockDBConfig() error {
|
||||
b.DBConfig = &database.DBConfig{
|
||||
DSN: "",
|
||||
DriverName: "postgres",
|
||||
MaxOpenNum: 200,
|
||||
MaxIdleNum: 20,
|
||||
}
|
||||
|
||||
if b.DBImg != nil {
|
||||
b.DBConfig.DSN = b.DBImg.Endpoint()
|
||||
}
|
||||
data, err := json.Marshal(b.DBConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(b.DBConfigFile, data, 0644) //nolint:gosec
|
||||
}
|
||||
|
||||
func newTestL1Docker() GethImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
return NewImgGeth("scroll_l1geth", "", "", 0, l1StartPort+int(id.Int64()))
|
||||
}
|
||||
|
||||
func newTestL2Docker() GethImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
return NewImgGeth("scroll_l2geth", "", "", 0, l2StartPort+int(id.Int64()))
|
||||
}
|
||||
|
||||
func newTestDBDocker(driverName string) ImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
return NewImgDB(driverName, "123456", "test_db", dbStartPort+int(id.Int64()))
|
||||
}
|
||||
132
common/docker/docker_db.go
Normal file
132
common/docker/docker_db.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
"scroll-tech/common/cmd"
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
// ImgDB the postgres image manager.
|
||||
type ImgDB struct {
|
||||
image string
|
||||
name string
|
||||
id string
|
||||
|
||||
dbName string
|
||||
port int
|
||||
password string
|
||||
|
||||
running bool
|
||||
cmd *cmd.Cmd
|
||||
}
|
||||
|
||||
// NewImgDB return postgres db img instance.
|
||||
func NewImgDB(image, password, dbName string, port int) ImgInstance {
|
||||
img := &ImgDB{
|
||||
image: image,
|
||||
name: fmt.Sprintf("%s-%s_%d", image, dbName, port),
|
||||
password: password,
|
||||
dbName: dbName,
|
||||
port: port,
|
||||
}
|
||||
img.cmd = cmd.NewCmd("docker", img.prepare()...)
|
||||
return img
|
||||
}
|
||||
|
||||
// Start postgres db container.
|
||||
func (i *ImgDB) Start() error {
|
||||
id := GetContainerID(i.name)
|
||||
if id != "" {
|
||||
return fmt.Errorf("container already exist, name: %s", i.name)
|
||||
}
|
||||
i.running = i.isOk()
|
||||
if !i.running {
|
||||
_ = i.Stop()
|
||||
return fmt.Errorf("failed to start image: %s", i.image)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop the container.
|
||||
func (i *ImgDB) Stop() error {
|
||||
if !i.running {
|
||||
return nil
|
||||
}
|
||||
i.running = false
|
||||
|
||||
ctx := context.Background()
|
||||
// stop the running container.
|
||||
if i.id == "" {
|
||||
i.id = GetContainerID(i.name)
|
||||
}
|
||||
|
||||
timeoutSec := 3
|
||||
timeout := container.StopOptions{
|
||||
Timeout: &timeoutSec,
|
||||
}
|
||||
if err := cli.ContainerStop(ctx, i.id, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
// remove the stopped container.
|
||||
return cli.ContainerRemove(ctx, i.id, types.ContainerRemoveOptions{})
|
||||
}
|
||||
|
||||
// Endpoint return the dsn.
|
||||
func (i *ImgDB) Endpoint() string {
|
||||
return fmt.Sprintf("postgres://postgres:%s@localhost:%d/%s?sslmode=disable", i.password, i.port, i.dbName)
|
||||
}
|
||||
|
||||
// IsRunning returns docker container's running status.
|
||||
func (i *ImgDB) IsRunning() bool {
|
||||
return i.running
|
||||
}
|
||||
|
||||
func (i *ImgDB) prepare() []string {
|
||||
cmd := []string{"run", "--rm", "--name", i.name, "-p", fmt.Sprintf("%d:5432", i.port)}
|
||||
envs := []string{
|
||||
"-e", "POSTGRES_PASSWORD=" + i.password,
|
||||
"-e", fmt.Sprintf("POSTGRES_DB=%s", i.dbName),
|
||||
}
|
||||
|
||||
cmd = append(cmd, envs...)
|
||||
return append(cmd, i.image)
|
||||
}
|
||||
|
||||
func (i *ImgDB) isOk() bool {
|
||||
keyword := "database system is ready to accept connections"
|
||||
okCh := make(chan struct{}, 1)
|
||||
i.cmd.RegistFunc(keyword, func(buf string) {
|
||||
if strings.Contains(buf, keyword) {
|
||||
select {
|
||||
case okCh <- struct{}{}:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
defer i.cmd.UnRegistFunc(keyword)
|
||||
// Start cmd in parallel.
|
||||
i.cmd.RunCmd(true)
|
||||
|
||||
select {
|
||||
case <-okCh:
|
||||
utils.TryTimes(20, func() bool {
|
||||
i.id = GetContainerID(i.name)
|
||||
return i.id != ""
|
||||
})
|
||||
case err := <-i.cmd.ErrChan:
|
||||
if err != nil {
|
||||
fmt.Printf("failed to start %s, err: %v\n", i.name, err)
|
||||
}
|
||||
case <-time.After(time.Second * 20):
|
||||
return false
|
||||
}
|
||||
return i.id != ""
|
||||
}
|
||||
175
common/docker/docker_geth.go
Normal file
175
common/docker/docker_geth.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
|
||||
"scroll-tech/common/cmd"
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
// ImgGeth the geth image manager include l1geth and l2geth.
|
||||
type ImgGeth struct {
|
||||
image string
|
||||
name string
|
||||
id string
|
||||
|
||||
volume string
|
||||
ipcPath string
|
||||
httpPort int
|
||||
wsPort int
|
||||
chainID *big.Int
|
||||
|
||||
running bool
|
||||
cmd *cmd.Cmd
|
||||
}
|
||||
|
||||
// NewImgGeth return geth img instance.
|
||||
func NewImgGeth(image, volume, ipc string, hPort, wPort int) GethImgInstance {
|
||||
img := &ImgGeth{
|
||||
image: image,
|
||||
name: fmt.Sprintf("%s-%d", image, time.Now().Nanosecond()),
|
||||
volume: volume,
|
||||
ipcPath: ipc,
|
||||
httpPort: hPort,
|
||||
wsPort: wPort,
|
||||
}
|
||||
img.cmd = cmd.NewCmd("docker", img.params()...)
|
||||
return img
|
||||
}
|
||||
|
||||
// Start run image and check if it is running healthily.
|
||||
func (i *ImgGeth) Start() error {
|
||||
id := GetContainerID(i.name)
|
||||
if id != "" {
|
||||
return fmt.Errorf("container already exist, name: %s", i.name)
|
||||
}
|
||||
i.running = i.isOk()
|
||||
if !i.running {
|
||||
_ = i.Stop()
|
||||
return fmt.Errorf("failed to start image: %s", i.image)
|
||||
}
|
||||
|
||||
// try 10 times to get chainID until is ok.
|
||||
utils.TryTimes(10, func() bool {
|
||||
client, err := ethclient.Dial(i.Endpoint())
|
||||
if err == nil && client != nil {
|
||||
i.chainID, err = client.ChainID(context.Background())
|
||||
return err == nil && i.chainID != nil
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning returns docker container's running status.
|
||||
func (i *ImgGeth) IsRunning() bool {
|
||||
return i.running
|
||||
}
|
||||
|
||||
// Endpoint return the connection endpoint.
|
||||
func (i *ImgGeth) Endpoint() string {
|
||||
switch true {
|
||||
case i.httpPort != 0:
|
||||
return fmt.Sprintf("http://127.0.0.1:%d", i.httpPort)
|
||||
case i.wsPort != 0:
|
||||
return fmt.Sprintf("ws://127.0.0.1:%d", i.wsPort)
|
||||
default:
|
||||
return i.ipcPath
|
||||
}
|
||||
}
|
||||
|
||||
// ChainID return chainID.
|
||||
func (i *ImgGeth) ChainID() *big.Int {
|
||||
return i.chainID
|
||||
}
|
||||
|
||||
func (i *ImgGeth) isOk() bool {
|
||||
keyword := "WebSocket enabled"
|
||||
okCh := make(chan struct{}, 1)
|
||||
i.cmd.RegistFunc(keyword, func(buf string) {
|
||||
if strings.Contains(buf, keyword) {
|
||||
select {
|
||||
case okCh <- struct{}{}:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
defer i.cmd.UnRegistFunc(keyword)
|
||||
// Start cmd in parallel.
|
||||
i.cmd.RunCmd(true)
|
||||
|
||||
select {
|
||||
case <-okCh:
|
||||
utils.TryTimes(20, func() bool {
|
||||
i.id = GetContainerID(i.name)
|
||||
return i.id != ""
|
||||
})
|
||||
case err := <-i.cmd.ErrChan:
|
||||
if err != nil {
|
||||
fmt.Printf("failed to start %s, err: %v\n", i.name, err)
|
||||
}
|
||||
case <-time.After(time.Second * 10):
|
||||
return false
|
||||
}
|
||||
return i.id != ""
|
||||
}
|
||||
|
||||
// Stop the docker container.
|
||||
func (i *ImgGeth) Stop() error {
|
||||
if !i.running {
|
||||
return nil
|
||||
}
|
||||
i.running = false
|
||||
|
||||
ctx := context.Background()
|
||||
// check if container is running, stop the running container.
|
||||
id := GetContainerID(i.name)
|
||||
if id != "" {
|
||||
timeoutSec := 3
|
||||
timeout := container.StopOptions{
|
||||
Timeout: &timeoutSec,
|
||||
}
|
||||
if err := cli.ContainerStop(ctx, id, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
i.id = id
|
||||
}
|
||||
// remove the stopped container.
|
||||
return cli.ContainerRemove(ctx, i.id, types.ContainerRemoveOptions{})
|
||||
}
|
||||
|
||||
func (i *ImgGeth) params() []string {
|
||||
cmds := []string{"run", "--rm", "--name", i.name}
|
||||
var ports []string
|
||||
if i.httpPort != 0 {
|
||||
ports = append(ports, []string{"-p", strconv.Itoa(i.httpPort) + ":8545"}...)
|
||||
}
|
||||
if i.wsPort != 0 {
|
||||
ports = append(ports, []string{"-p", strconv.Itoa(i.wsPort) + ":8546"}...)
|
||||
}
|
||||
|
||||
var envs []string
|
||||
if i.ipcPath != "" {
|
||||
envs = append(envs, []string{"-e", fmt.Sprintf("IPC_PATH=%s", i.ipcPath)}...)
|
||||
}
|
||||
|
||||
if i.volume != "" {
|
||||
cmds = append(cmds, []string{"-v", fmt.Sprintf("%s:%s", i.volume, i.volume)}...)
|
||||
}
|
||||
|
||||
cmds = append(cmds, ports...)
|
||||
cmds = append(cmds, envs...)
|
||||
|
||||
return append(cmds, i.image)
|
||||
}
|
||||
54
common/docker/docker_test.go
Normal file
54
common/docker/docker_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package docker_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/lib/pq" //nolint:golint
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"scroll-tech/common/docker"
|
||||
)
|
||||
|
||||
var (
|
||||
base *docker.App
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
base = docker.NewDockerApp()
|
||||
|
||||
m.Run()
|
||||
|
||||
base.Free()
|
||||
}
|
||||
|
||||
func TestDB(t *testing.T) {
|
||||
base.RunDBImage(t)
|
||||
|
||||
db, err := sqlx.Open("postgres", base.DBImg.Endpoint())
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.Ping())
|
||||
}
|
||||
|
||||
func TestL1Geth(t *testing.T) {
|
||||
base.RunL1Geth(t)
|
||||
|
||||
client, err := base.L1Client()
|
||||
assert.NoError(t, err)
|
||||
|
||||
chainID, err := client.ChainID(context.Background())
|
||||
assert.NoError(t, err)
|
||||
t.Logf("chainId: %s", chainID.String())
|
||||
}
|
||||
|
||||
func TestL2Geth(t *testing.T) {
|
||||
base.RunL2Geth(t)
|
||||
|
||||
client, err := base.L2Client()
|
||||
assert.NoError(t, err)
|
||||
|
||||
chainID, err := client.ChainID(context.Background())
|
||||
assert.NoError(t, err)
|
||||
t.Logf("chainId: %s", chainID.String())
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
)
|
||||
@@ -40,7 +40,7 @@ type GethImgInstance interface {
|
||||
func GetContainerID(name string) string {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("name", name)
|
||||
lst, _ := cli.ContainerList(context.Background(), container.ListOptions{
|
||||
lst, _ := cli.ContainerList(context.Background(), types.ContainerListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
if len(lst) > 0 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ethereum/client-go:v1.13.14
|
||||
FROM ethereum/client-go
|
||||
|
||||
COPY password /l1geth/
|
||||
COPY genesis.json /l1geth/
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"archimedesBlock": 0,
|
||||
"shanghaiBlock": 0,
|
||||
"clique": {
|
||||
"period": 1,
|
||||
"period": 3,
|
||||
"epoch": 30000
|
||||
},
|
||||
"scroll": {
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package forks
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"sort"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/params"
|
||||
)
|
||||
|
||||
// CollectSortedForkHeights returns a sorted set of block numbers that one or more forks are activated on
|
||||
func CollectSortedForkHeights(config *params.ChainConfig) ([]uint64, map[uint64]bool, map[string]uint64) {
|
||||
type nameFork struct {
|
||||
name string
|
||||
block *big.Int
|
||||
}
|
||||
|
||||
forkHeightNameMap := make(map[uint64]string)
|
||||
|
||||
for _, fork := range []nameFork{
|
||||
{name: "homestead", block: config.HomesteadBlock},
|
||||
{name: "daoFork", block: config.DAOForkBlock},
|
||||
{name: "eip150", block: config.EIP150Block},
|
||||
{name: "eip155", block: config.EIP155Block},
|
||||
{name: "eip158", block: config.EIP158Block},
|
||||
{name: "byzantium", block: config.ByzantiumBlock},
|
||||
{name: "constantinople", block: config.ConstantinopleBlock},
|
||||
{name: "petersburg", block: config.PetersburgBlock},
|
||||
{name: "istanbul", block: config.IstanbulBlock},
|
||||
{name: "muirGlacier", block: config.MuirGlacierBlock},
|
||||
{name: "berlin", block: config.BerlinBlock},
|
||||
{name: "london", block: config.LondonBlock},
|
||||
{name: "arrowGlacier", block: config.ArrowGlacierBlock},
|
||||
{name: "archimedes", block: config.ArchimedesBlock},
|
||||
{name: "shanghai", block: config.ShanghaiBlock},
|
||||
{name: "bernoulli", block: config.BernoulliBlock},
|
||||
{name: "curie", block: config.CurieBlock},
|
||||
} {
|
||||
if fork.block == nil {
|
||||
continue
|
||||
}
|
||||
height := fork.block.Uint64()
|
||||
|
||||
// only keep latest fork for at each height, discard the rest
|
||||
forkHeightNameMap[height] = fork.name
|
||||
}
|
||||
|
||||
forkHeightsMap := make(map[uint64]bool)
|
||||
forkNameHeightMap := make(map[string]uint64)
|
||||
|
||||
for height, name := range forkHeightNameMap {
|
||||
forkHeightsMap[height] = true
|
||||
forkNameHeightMap[name] = height
|
||||
}
|
||||
|
||||
var forkHeights []uint64
|
||||
for height := range forkHeightsMap {
|
||||
forkHeights = append(forkHeights, height)
|
||||
}
|
||||
sort.Slice(forkHeights, func(i, j int) bool {
|
||||
return forkHeights[i] < forkHeights[j]
|
||||
})
|
||||
return forkHeights, forkHeightsMap, forkNameHeightMap
|
||||
}
|
||||
|
||||
// BlocksUntilFork returns the number of blocks until the next fork
|
||||
// returns 0 if there is no fork scheduled for the future
|
||||
func BlocksUntilFork(blockHeight uint64, forkHeights []uint64) uint64 {
|
||||
for _, forkHeight := range forkHeights {
|
||||
if forkHeight > blockHeight {
|
||||
return forkHeight - blockHeight
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// BlockRange returns the block range of the hard fork
|
||||
// Need ensure the forkHeights is incremental
|
||||
func BlockRange(currentForkHeight uint64, forkHeights []uint64) (from, to uint64) {
|
||||
to = math.MaxInt64
|
||||
for _, height := range forkHeights {
|
||||
if currentForkHeight < height {
|
||||
to = height
|
||||
return
|
||||
}
|
||||
from = height
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package forks
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/params"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCollectSortedForkBlocks(t *testing.T) {
|
||||
l, m, n := CollectSortedForkHeights(¶ms.ChainConfig{
|
||||
ArchimedesBlock: big.NewInt(0),
|
||||
ShanghaiBlock: big.NewInt(3),
|
||||
BernoulliBlock: big.NewInt(3),
|
||||
CurieBlock: big.NewInt(4),
|
||||
})
|
||||
require.Equal(t, l, []uint64{
|
||||
0,
|
||||
3,
|
||||
4,
|
||||
})
|
||||
require.Equal(t, map[uint64]bool{
|
||||
3: true,
|
||||
4: true,
|
||||
0: true,
|
||||
}, m)
|
||||
require.Equal(t, map[string]uint64{
|
||||
"archimedes": 0,
|
||||
"bernoulli": 3,
|
||||
"curie": 4,
|
||||
}, n)
|
||||
}
|
||||
|
||||
func TestBlocksUntilFork(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
block uint64
|
||||
forks []uint64
|
||||
expected uint64
|
||||
}{
|
||||
"NoFork": {
|
||||
block: 44,
|
||||
forks: []uint64{},
|
||||
expected: 0,
|
||||
},
|
||||
"BeforeFork": {
|
||||
block: 0,
|
||||
forks: []uint64{1, 5},
|
||||
expected: 1,
|
||||
},
|
||||
"OnFork": {
|
||||
block: 1,
|
||||
forks: []uint64{1, 5},
|
||||
expected: 4,
|
||||
},
|
||||
"OnLastFork": {
|
||||
block: 5,
|
||||
forks: []uint64{1, 5},
|
||||
expected: 0,
|
||||
},
|
||||
"AfterFork": {
|
||||
block: 5,
|
||||
forks: []uint64{1, 5},
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
require.Equal(t, test.expected, BlocksUntilFork(test.block, test.forks))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockRange(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
forkHeight uint64
|
||||
forkHeights []uint64
|
||||
expectedFrom uint64
|
||||
expectedTo uint64
|
||||
}{
|
||||
{
|
||||
name: "ToInfinite",
|
||||
forkHeight: 300,
|
||||
forkHeights: []uint64{100, 200, 300},
|
||||
expectedFrom: 300,
|
||||
expectedTo: math.MaxInt64,
|
||||
},
|
||||
{
|
||||
name: "To300",
|
||||
forkHeight: 200,
|
||||
forkHeights: []uint64{100, 200, 300},
|
||||
expectedFrom: 200,
|
||||
expectedTo: 300,
|
||||
},
|
||||
{
|
||||
name: "To200",
|
||||
forkHeight: 100,
|
||||
forkHeights: []uint64{100, 200, 300},
|
||||
expectedFrom: 100,
|
||||
expectedTo: 200,
|
||||
},
|
||||
{
|
||||
name: "To100",
|
||||
forkHeight: 0,
|
||||
forkHeights: []uint64{100, 200, 300},
|
||||
expectedFrom: 0,
|
||||
expectedTo: 100,
|
||||
},
|
||||
{
|
||||
name: "To200-1",
|
||||
forkHeight: 100,
|
||||
forkHeights: []uint64{100, 200},
|
||||
expectedFrom: 100,
|
||||
expectedTo: 200,
|
||||
},
|
||||
{
|
||||
name: "To2",
|
||||
forkHeight: 1,
|
||||
forkHeights: []uint64{1, 2},
|
||||
expectedFrom: 1,
|
||||
expectedTo: 2,
|
||||
},
|
||||
{
|
||||
name: "ToInfinite-1",
|
||||
forkHeight: 0,
|
||||
forkHeights: []uint64{0},
|
||||
expectedFrom: 0,
|
||||
expectedTo: math.MaxInt64,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
from, to := BlockRange(test.forkHeight, test.forkHeights)
|
||||
require.Equal(t, test.expectedFrom, from)
|
||||
require.Equal(t, test.expectedTo, to)
|
||||
})
|
||||
}
|
||||
}
|
||||
244
common/go.mod
244
common/go.mod
@@ -1,266 +1,132 @@
|
||||
module scroll-tech/common
|
||||
|
||||
go 1.21
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/bits-and-blooms/bitset v1.12.0
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004
|
||||
github.com/docker/docker v25.0.3+incompatible
|
||||
github.com/bits-and-blooms/bitset v1.7.0
|
||||
github.com/docker/docker v23.0.6+incompatible
|
||||
github.com/gin-contrib/pprof v1.4.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mattn/go-isatty v0.0.19
|
||||
github.com/modern-go/reflect2 v1.0.2
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20240326144132-0f0cd99f7a2e
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/testcontainers/testcontainers-go v0.28.0
|
||||
github.com/testcontainers/testcontainers-go/modules/compose v0.28.0
|
||||
github.com/testcontainers/testcontainers-go/modules/postgres v0.28.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230829000527-f883dcdc21fc
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
gorm.io/driver/postgres v1.5.0
|
||||
gorm.io/gorm v1.25.5
|
||||
gorm.io/gorm v1.25.2
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.4 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
||||
github.com/buger/goterm v1.0.4 // indirect
|
||||
github.com/bytedance/sonic v1.10.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/bytedance/sonic v1.9.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.0 // indirect
|
||||
github.com/compose-spec/compose-go/v2 v2.0.0-rc.2 // indirect
|
||||
github.com/consensys/bavard v0.1.13 // indirect
|
||||
github.com/consensys/gnark-crypto v0.12.1 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/containerd/containerd v1.7.12 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/distribution/reference v0.5.0 // indirect
|
||||
github.com/docker/buildx v0.12.0-rc2.0.20231219140829-617f538cb315 // indirect
|
||||
github.com/docker/cli v25.0.1+incompatible // indirect
|
||||
github.com/docker/compose/v2 v2.24.3 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
|
||||
github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fjl/memsize v0.0.2 // indirect
|
||||
github.com/fsnotify/fsevents v0.1.1 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.2 // indirect
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-kit/kit v0.9.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.15.5 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/graph-gophers/graphql-go v1.3.0 // indirect
|
||||
github.com/hashicorp/go-bexpr v0.1.10 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.4 // indirect
|
||||
github.com/huin/goupnp v1.3.0 // indirect
|
||||
github.com/holiman/uint256 v1.2.3 // indirect
|
||||
github.com/huin/goupnp v1.0.3 // indirect
|
||||
github.com/iden3/go-iden3-crypto v0.0.15 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/influxdata/influxdb v1.8.3 // indirect
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.4 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jackc/pgx/v5 v5.3.1 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jonboulle/clockwork v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.16 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/moby/buildkit v0.13.0-beta1.0.20231219135447-957cb50df991 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.1 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/moby/sys/symlink v0.2.0 // indirect
|
||||
github.com/moby/sys/user v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.8.1 // indirect
|
||||
github.com/onsi/gomega v1.27.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
|
||||
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/prometheus/tsdb v0.7.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/scroll-tech/zktrie v0.7.1 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
|
||||
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/scroll-tech/zktrie v0.6.0 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cobra v1.8.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/status-im/keycard-go v0.2.0 // indirect
|
||||
github.com/supranational/blst v0.3.11-0.20230124161941-ca03e11a3ff2 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
|
||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.42.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/arch v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
|
||||
golang.org/x/mod v0.16.0 // indirect
|
||||
golang.org/x/net v0.18.0 // indirect
|
||||
golang.org/x/oauth2 v0.11.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/arch v0.4.0 // indirect
|
||||
golang.org/x/crypto v0.12.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.14.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.15.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
golang.org/x/tools v0.11.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.26.7 // indirect
|
||||
k8s.io/apimachinery v0.26.7 // indirect
|
||||
k8s.io/apiserver v0.26.7 // indirect
|
||||
k8s.io/client-go v0.26.7 // indirect
|
||||
k8s.io/klog/v2 v2.90.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
||||
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
tags.cncf.io/container-device-interface v0.6.2 // indirect
|
||||
gotest.tools/v3 v3.4.0 // indirect
|
||||
)
|
||||
|
||||
919
common/go.sum
919
common/go.sum
File diff suppressed because it is too large
Load Diff
1024
common/libzkp/impl/Cargo.lock
generated
1024
common/libzkp/impl/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -8,29 +8,26 @@ edition = "2021"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[patch.crates-io]
|
||||
gobuild = { git = "https://github.com/scroll-tech/gobuild.git" }
|
||||
halo2curves = { git = "https://github.com/scroll-tech/halo2curves", branch = "v0.1.0" }
|
||||
ethers-core = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }
|
||||
ethers-providers = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }
|
||||
ethers-signers = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }
|
||||
#ethers-etherscan = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }
|
||||
#ethers = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }
|
||||
[patch."https://github.com/privacy-scaling-explorations/halo2.git"]
|
||||
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "v1.1" }
|
||||
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
|
||||
[patch."https://github.com/privacy-scaling-explorations/poseidon.git"]
|
||||
poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "main" }
|
||||
[patch."https://github.com/privacy-scaling-explorations/bls12_381"]
|
||||
bls12_381 = { git = "https://github.com/scroll-tech/bls12_381", branch = "feat/impl_scalar_field" }
|
||||
poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "scroll-dev-0220" }
|
||||
[patch."https://github.com/privacy-scaling-explorations/halo2wrong.git"]
|
||||
halo2wrong = { git = "https://github.com/scroll-tech/halo2wrong.git", branch = "halo2-ecc-snark-verifier-0323" }
|
||||
maingate = { git = "https://github.com/scroll-tech/halo2wrong", branch = "halo2-ecc-snark-verifier-0323" }
|
||||
[patch."https://github.com/privacy-scaling-explorations/halo2curves.git"]
|
||||
halo2curves = { git = "https://github.com/scroll-tech/halo2curves.git", branch = "0.3.1-derive-serde" }
|
||||
|
||||
[dependencies]
|
||||
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "v1.1" }
|
||||
prover = { git = "https://github.com/scroll-tech/zkevm-circuits.git", tag = "v0.10.0rc3", default-features = false, features = ["parallel_syn", "scroll", "shanghai"] }
|
||||
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
|
||||
prover = { git = "https://github.com/scroll-tech/zkevm-circuits.git", tag = "v0.9.8", default-features = false, features = ["parallel_syn", "scroll", "shanghai", "strict-ccc"] }
|
||||
|
||||
base64 = "0.13.0"
|
||||
env_logger = "0.9.0"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
once_cell = "1.19"
|
||||
once_cell = "1.8.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0.66"
|
||||
|
||||
@@ -1 +1 @@
|
||||
nightly-2023-12-03
|
||||
nightly-2022-12-10
|
||||
|
||||
@@ -119,7 +119,7 @@ pub unsafe extern "C" fn gen_batch_proof(
|
||||
|
||||
let chunk_hashes_proofs = chunk_hashes
|
||||
.into_iter()
|
||||
.zip(chunk_proofs)
|
||||
.zip(chunk_proofs.into_iter())
|
||||
.collect();
|
||||
|
||||
let proof = PROVER
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![feature(once_cell)]
|
||||
|
||||
mod batch;
|
||||
mod chunk;
|
||||
mod types;
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/modules/postgres"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"scroll-tech/common/database"
|
||||
)
|
||||
|
||||
// TestcontainerApps testcontainers struct
|
||||
type TestcontainerApps struct {
|
||||
postgresContainer *postgres.PostgresContainer
|
||||
l1GethContainer *testcontainers.DockerContainer
|
||||
l2GethContainer *testcontainers.DockerContainer
|
||||
|
||||
// common time stamp in nanoseconds.
|
||||
Timestamp int
|
||||
}
|
||||
|
||||
// NewTestcontainerApps returns new instance of TestcontainerApps struct
|
||||
func NewTestcontainerApps() *TestcontainerApps {
|
||||
timestamp := time.Now().Nanosecond()
|
||||
return &TestcontainerApps{
|
||||
Timestamp: timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// StartPostgresContainer starts a postgres container
|
||||
func (t *TestcontainerApps) StartPostgresContainer() error {
|
||||
if t.postgresContainer != nil && t.postgresContainer.IsRunning() {
|
||||
return nil
|
||||
}
|
||||
postgresContainer, err := postgres.RunContainer(context.Background(),
|
||||
testcontainers.WithImage("postgres"),
|
||||
postgres.WithDatabase("test_db"),
|
||||
postgres.WithPassword("123456"),
|
||||
testcontainers.WithWaitStrategy(
|
||||
wait.ForLog("database system is ready to accept connections").WithOccurrence(2).WithStartupTimeout(5*time.Second)),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("failed to start postgres container: %s", err)
|
||||
return err
|
||||
}
|
||||
t.postgresContainer = postgresContainer
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartL1GethContainer starts a L1Geth container
|
||||
func (t *TestcontainerApps) StartL1GethContainer() error {
|
||||
if t.l1GethContainer != nil && t.l1GethContainer.IsRunning() {
|
||||
return nil
|
||||
}
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: "scroll_l1geth",
|
||||
ExposedPorts: []string{"8546/tcp", "8545/tcp"},
|
||||
WaitingFor: wait.ForHTTP("/").WithPort("8545").WithStartupTimeout(100 * time.Second),
|
||||
Cmd: []string{"--log.debug", "ANY"},
|
||||
}
|
||||
genericContainerReq := testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
}
|
||||
container, err := testcontainers.GenericContainer(context.Background(), genericContainerReq)
|
||||
if err != nil {
|
||||
log.Printf("failed to start scroll_l1geth container: %s", err)
|
||||
return err
|
||||
}
|
||||
t.l1GethContainer, _ = container.(*testcontainers.DockerContainer)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartL2GethContainer starts a L2Geth container
|
||||
func (t *TestcontainerApps) StartL2GethContainer() error {
|
||||
if t.l2GethContainer != nil && t.l2GethContainer.IsRunning() {
|
||||
return nil
|
||||
}
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: "scroll_l2geth",
|
||||
ExposedPorts: []string{"8546/tcp", "8545/tcp"},
|
||||
WaitingFor: wait.ForHTTP("/").WithPort("8545").WithStartupTimeout(100 * time.Second),
|
||||
}
|
||||
genericContainerReq := testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
}
|
||||
container, err := testcontainers.GenericContainer(context.Background(), genericContainerReq)
|
||||
if err != nil {
|
||||
log.Printf("failed to start scroll_l2geth container: %s", err)
|
||||
return err
|
||||
}
|
||||
t.l2GethContainer, _ = container.(*testcontainers.DockerContainer)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDBEndPoint returns the endpoint of the running postgres container
|
||||
func (t *TestcontainerApps) GetDBEndPoint() (string, error) {
|
||||
if t.postgresContainer == nil || !t.postgresContainer.IsRunning() {
|
||||
return "", fmt.Errorf("postgres is not running")
|
||||
}
|
||||
return t.postgresContainer.ConnectionString(context.Background(), "sslmode=disable")
|
||||
}
|
||||
|
||||
// GetL1GethEndPoint returns the endpoint of the running L1Geth container
|
||||
func (t *TestcontainerApps) GetL1GethEndPoint() (string, error) {
|
||||
if t.l1GethContainer == nil || !t.l1GethContainer.IsRunning() {
|
||||
return "", fmt.Errorf("l1 geth is not running")
|
||||
}
|
||||
endpoint, err := t.l1GethContainer.PortEndpoint(context.Background(), "8546/tcp", "ws")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
// GetL2GethEndPoint returns the endpoint of the running L2Geth container
|
||||
func (t *TestcontainerApps) GetL2GethEndPoint() (string, error) {
|
||||
if t.l2GethContainer == nil || !t.l2GethContainer.IsRunning() {
|
||||
return "", fmt.Errorf("l2 geth is not running")
|
||||
}
|
||||
endpoint, err := t.l2GethContainer.PortEndpoint(context.Background(), "8546/tcp", "ws")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
// GetGormDBClient returns a gorm.DB by connecting to the running postgres container
|
||||
func (t *TestcontainerApps) GetGormDBClient() (*gorm.DB, error) {
|
||||
endpoint, err := t.GetDBEndPoint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbCfg := &database.Config{
|
||||
DSN: endpoint,
|
||||
DriverName: "postgres",
|
||||
MaxOpenNum: 200,
|
||||
MaxIdleNum: 20,
|
||||
}
|
||||
return database.InitDB(dbCfg)
|
||||
}
|
||||
|
||||
// GetL1GethClient returns a ethclient by dialing running L1Geth
|
||||
func (t *TestcontainerApps) GetL1GethClient() (*ethclient.Client, error) {
|
||||
endpoint, err := t.GetL1GethEndPoint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := ethclient.Dial(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// GetL2GethClient returns a ethclient by dialing running L2Geth
|
||||
func (t *TestcontainerApps) GetL2GethClient() (*ethclient.Client, error) {
|
||||
endpoint, err := t.GetL2GethEndPoint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := ethclient.Dial(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Free stops all running containers
|
||||
func (t *TestcontainerApps) Free() {
|
||||
ctx := context.Background()
|
||||
if t.postgresContainer != nil && t.postgresContainer.IsRunning() {
|
||||
if err := t.postgresContainer.Terminate(ctx); err != nil {
|
||||
log.Printf("failed to stop postgres container: %s", err)
|
||||
}
|
||||
}
|
||||
if t.l1GethContainer != nil && t.l1GethContainer.IsRunning() {
|
||||
if err := t.l1GethContainer.Terminate(ctx); err != nil {
|
||||
log.Printf("failed to stop scroll_l1geth container: %s", err)
|
||||
}
|
||||
}
|
||||
if t.l2GethContainer != nil && t.l2GethContainer.IsRunning() {
|
||||
if err := t.l2GethContainer.Terminate(ctx); err != nil {
|
||||
log.Printf("failed to stop scroll_l2geth container: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// TestNewTestcontainerApps tests NewTestcontainerApps
|
||||
func TestNewTestcontainerApps(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
endpoint string
|
||||
gormDBclient *gorm.DB
|
||||
ethclient *ethclient.Client
|
||||
)
|
||||
|
||||
// test start testcontainers
|
||||
testApps := NewTestcontainerApps()
|
||||
assert.NoError(t, testApps.StartPostgresContainer())
|
||||
endpoint, err = testApps.GetDBEndPoint()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, endpoint)
|
||||
gormDBclient, err = testApps.GetGormDBClient()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, gormDBclient)
|
||||
|
||||
assert.NoError(t, testApps.StartL1GethContainer())
|
||||
endpoint, err = testApps.GetL1GethEndPoint()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, endpoint)
|
||||
ethclient, err = testApps.GetL1GethClient()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, ethclient)
|
||||
|
||||
assert.NoError(t, testApps.StartL2GethContainer())
|
||||
endpoint, err = testApps.GetL2GethEndPoint()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, endpoint)
|
||||
ethclient, err = testApps.GetL2GethClient()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, ethclient)
|
||||
|
||||
// test free testcontainers
|
||||
testApps.Free()
|
||||
endpoint, err = testApps.GetDBEndPoint()
|
||||
assert.EqualError(t, err, "postgres is not running")
|
||||
assert.Empty(t, endpoint)
|
||||
|
||||
endpoint, err = testApps.GetL1GethEndPoint()
|
||||
assert.EqualError(t, err, "l1 geth is not running")
|
||||
assert.Empty(t, endpoint)
|
||||
|
||||
endpoint, err = testApps.GetL2GethEndPoint()
|
||||
assert.EqualError(t, err, "l2 geth is not running")
|
||||
assert.Empty(t, endpoint)
|
||||
}
|
||||
4
common/testdata/blockTrace_03.json
vendored
4
common/testdata/blockTrace_03.json
vendored
@@ -31,11 +31,9 @@
|
||||
{
|
||||
"type": 2,
|
||||
"nonce": 2,
|
||||
"txHash": "0xfc4325f39825616a241d0c52d536c892e21b6df32bb75d8bdc70de54ae175318",
|
||||
"txHash": "0x6b50040f5f14bad253f202b0775d6742131bcaee6b992f05578386f00e53b7e4",
|
||||
"gas": 1152994,
|
||||
"gasPrice": "0x3b9b0a17",
|
||||
"gasTipCap": "0x3b9b0a17",
|
||||
"gasFeeCap": "0x3b9b0a17",
|
||||
"from": "0x1c5a77d9fa7ef466951b2f01f724bca3a5820b63",
|
||||
"to": null,
|
||||
"chainId": "0xcf55",
|
||||
|
||||
995
common/testdata/blockTrace_delegate.json
vendored
Normal file
995
common/testdata/blockTrace_delegate.json
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user