Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6301feb30 | ||
|
|
4b3ec1b5a0 | ||
|
|
534b0fe31d | ||
|
|
0c77e6fd1d | ||
|
|
27fa54c6dc | ||
|
|
fbde7cd175 | ||
|
|
b3c2d5915c | ||
|
|
117a2deea9 | ||
|
|
bb8c861bfd | ||
|
|
d5a9f999b3 | ||
|
|
cdeb43177c | ||
|
|
67c937418e | ||
|
|
802f80057b | ||
|
|
64a89d8a46 | ||
|
|
cfbad8092d | ||
|
|
72eea46bab | ||
|
|
3c6a9787fd | ||
|
|
24fc6358d6 | ||
|
|
d674df1ef0 | ||
|
|
87aa87cb51 | ||
|
|
4d7781e2b0 | ||
|
|
e3b4fad3c7 | ||
|
|
9160dded11 | ||
|
|
347984a547 | ||
|
|
041276da81 | ||
|
|
95e7090087 | ||
|
|
891f4c7ef3 | ||
|
|
dd6be9ccba | ||
|
|
de38c531d5 | ||
|
|
b79c57d5ac | ||
|
|
7a242a4c71 | ||
|
|
a31c9226ec | ||
|
|
12675f85c2 | ||
|
|
78089d3fd8 | ||
|
|
6123fa40e8 | ||
|
|
361dbd73a0 | ||
|
|
d13144ca90 | ||
|
|
71348321ae | ||
|
|
6215f7e66f |
@@ -0,0 +1,203 @@
|
||||
name: Test the stack.
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
stack-orchestrator-ref:
|
||||
required: false
|
||||
type: string
|
||||
ipld-eth-beacon-db-ref:
|
||||
required: false
|
||||
type: string
|
||||
ssz-data-ref:
|
||||
required: false
|
||||
type: string
|
||||
secrets:
|
||||
GHA_KEY:
|
||||
required: true
|
||||
|
||||
env:
|
||||
stack-orchestrator-ref: ${{ inputs.stack-orchestrator-ref || '7fb664270a0ba09e2caa3095e8c91f3fdb5b38af' }}
|
||||
ipld-eth-beacon-db-ref: ${{ inputs.ipld-eth-beacon-db-ref || '6b38fe9b18f7b19a803c626b742cafdccc1a2365' }}
|
||||
ssz-data-ref: ${{ inputs.ssz-data-ref || 'main' }}
|
||||
GOPATH: /tmp/go
|
||||
jobs:
|
||||
build:
|
||||
name: Run Docker Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-beacon-indexer"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.stack-orchestrator-ref }}
|
||||
path: "./stack-orchestrator/"
|
||||
repository: vulcanize/stack-orchestrator
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.ipld-eth-beacon-db-ref }}
|
||||
repository: vulcanize/ipld-eth-beacon-db
|
||||
path: "./ipld-eth-beacon-db/"
|
||||
ssh-key: ${{secrets.GHA_KEY}}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_ipld_eth_beacon_db=$GITHUB_WORKSPACE/ipld-eth-beacon-db/ > ./config.sh
|
||||
echo vulcanize_ipld_eth_beacon_indexer=$GITHUB_WORKSPACE/ipld-eth-beacon-indexer >> ./config.sh
|
||||
echo eth_beacon_config_file=$GITHUB_WORKSPACE/ipld-eth-beacon-indexer/config/cicd/boot.ipld-eth-beacon-indexer.json >> ./config.sh
|
||||
echo eth_beacon_capture_mode=boot >> ./config.sh
|
||||
cat ./config.sh
|
||||
|
||||
- name: Run docker compose
|
||||
run: |
|
||||
docker-compose \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-db.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/latest/docker-compose-lighthouse.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-indexer.yml" \
|
||||
--env-file ./config.sh \
|
||||
up -d --build
|
||||
|
||||
- name: Check to make sure HEALTH file is present
|
||||
shell: bash
|
||||
run: |
|
||||
until $(docker compose \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-db.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-indexer.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/latest/docker-compose-lighthouse.yml" \
|
||||
--env-file ./config.sh cp ipld-eth-beacon-indexer:/root/HEALTH ./HEALTH) ; do sleep 10; done
|
||||
cat ./HEALTH
|
||||
if [[ "$(cat ./HEALTH)" -eq "0" ]]; then echo "Application boot successful" && (exit 0); else docker compose -f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-indexer.yml" cp ipld-eth-beacon-indexer:/root/ipld-eth-beacon-indexer.log . && cat ipld-eth-beacon-indexer.log && (exit 1); fi
|
||||
|
||||
unit-test:
|
||||
name: Run Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
## IF you want to update the default branch for `pull_request runs, do it after the ||`
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-beacon-indexer"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.stack-orchestrator-ref }}
|
||||
path: "./stack-orchestrator/"
|
||||
repository: vulcanize/stack-orchestrator
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.ipld-eth-beacon-db-ref }}
|
||||
repository: vulcanize/ipld-eth-beacon-db
|
||||
path: "./ipld-eth-beacon-db/"
|
||||
ssh-key: ${{ secrets.GHA_KEY }}
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.ssz-data-ref }}
|
||||
repository: vulcanize/ssz-data
|
||||
path: "./ipld-eth-beacon-indexer/pkg/beaconclient/ssz-data"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_ipld_eth_beacon_db=$GITHUB_WORKSPACE/ipld-eth-beacon-db/ > ./config.sh
|
||||
echo vulcanize_ipld_eth_beacon_indexer=$GITHUB_WORKSPACE/ipld-eth-beacon-indexer >> ./config.sh
|
||||
cat ./config.sh
|
||||
|
||||
- name: Run docker compose
|
||||
run: |
|
||||
docker-compose \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-db.yml" \
|
||||
--env-file ./config.sh \
|
||||
up -d --build
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.18.0"
|
||||
check-latest: true
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@latest
|
||||
which ginkgo
|
||||
|
||||
- name: Run the tests using Make
|
||||
run: |
|
||||
cd ipld-eth-beacon-indexer
|
||||
make unit-test-ci
|
||||
|
||||
integration-test:
|
||||
name: Run Integration Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-beacon-indexer"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.stack-orchestrator-ref }}
|
||||
path: "./stack-orchestrator/"
|
||||
repository: vulcanize/stack-orchestrator
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.ipld-eth-beacon-db-ref }}
|
||||
repository: vulcanize/ipld-eth-beacon-db
|
||||
path: "./ipld-eth-beacon-db/"
|
||||
ssh-key: ${{secrets.GHA_KEY}}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_ipld_eth_beacon_db=$GITHUB_WORKSPACE/ipld-eth-beacon-db/ > ./config.sh
|
||||
echo vulcanize_ipld_eth_beacon_indexer=$GITHUB_WORKSPACE/ipld-eth-beacon-indexer >> ./config.sh
|
||||
cat ./config.sh
|
||||
|
||||
- name: Run docker compose
|
||||
run: |
|
||||
docker-compose \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-db.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/latest/docker-compose-lighthouse.yml" \
|
||||
--env-file ./config.sh \
|
||||
up -d --build
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.18.0"
|
||||
check-latest: true
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@latest
|
||||
which ginkgo
|
||||
|
||||
- name: Run the tests using Make
|
||||
run: |
|
||||
cd ipld-eth-beacon-indexer
|
||||
make integration-test-ci
|
||||
|
||||
golangci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.18.0"
|
||||
- uses: actions/checkout@v3
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
args: --timeout 90s --disable deadcode,unused
|
||||
# args: --timeout 90s --disable deadcode,
|
||||
@@ -0,0 +1,29 @@
|
||||
name: Notion Sync
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
issues:
|
||||
types:
|
||||
[
|
||||
opened,
|
||||
edited,
|
||||
labeled,
|
||||
unlabeled,
|
||||
assigned,
|
||||
unassigned,
|
||||
milestoned,
|
||||
demilestoned,
|
||||
reopened,
|
||||
closed,
|
||||
]
|
||||
|
||||
jobs:
|
||||
notion_job:
|
||||
runs-on: ubuntu-latest
|
||||
name: Add GitHub Issues to Notion
|
||||
steps:
|
||||
- name: Add GitHub Issues to Notion
|
||||
uses: vulcanize/notion-github-action@v1.2.4-issueid
|
||||
with:
|
||||
notion-token: ${{ secrets.NOTION_TOKEN }}
|
||||
notion-db: ${{ secrets.NOTION_DATABASE }}
|
||||
+28
-132
@@ -3,12 +3,16 @@ name: Test Application On PR
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
foundry-test-ref:
|
||||
description: "The branch, commit or sha from foundry-test to checkout"
|
||||
stack-orchestrator-ref:
|
||||
description: "The branch, commit or sha from stack-orchestrator to checkout"
|
||||
required: false
|
||||
default: "main"
|
||||
ipld-eth-db-ref:
|
||||
description: "The branch, commit or sha from ipld-eth-db to checkout"
|
||||
ipld-eth-beacon-db-ref:
|
||||
description: "The branch, commit or sha from ipld-eth-beacon-db to checkout"
|
||||
required: false
|
||||
default: "main"
|
||||
ssz-data-ref:
|
||||
description: "The branch, commit or sha from ssz-data to checkout"
|
||||
required: false
|
||||
default: "main"
|
||||
pull_request:
|
||||
@@ -18,134 +22,26 @@ on:
|
||||
- "!LICENSE"
|
||||
- "!.github/workflows/**"
|
||||
- ".github/workflows/on-pr.yml"
|
||||
- ".github/workflows/tests.yml"
|
||||
- "**"
|
||||
schedule:
|
||||
- cron: '0 13 * * *' # Must be single quotes!!
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Run Docker Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
|
||||
unit-test:
|
||||
name: Run Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
## IF you want to update the default branch for `pull_request runs, do it after the ||`
|
||||
env:
|
||||
foundry-test-ref: ${{ github.event.inputs.foundry-test-ref || 'c17752de64f208f286f02379b80d2a935237c860'}}
|
||||
ipld-eth-db-ref: ${{ github.event.inputs.ipld-eth-db-ref || '05600e51d2163e1c5e2a872cb54606bc0a380d12' }}
|
||||
GOPATH: /tmp/go
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-ethcl-indexer"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.foundry-test-ref }}
|
||||
path: "./foundry-test/"
|
||||
repository: vulcanize/foundry-test
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.ipld-eth-db-ref }}
|
||||
repository: vulcanize/ipld-eth-db
|
||||
path: "./ipld-eth-db/"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_ipld_eth_db=$GITHUB_WORKSPACE/ipld-eth-db/ > ./config.sh
|
||||
echo vulcanize_ipld_ethcl_indexer=$GITHUB_WORKSPACE/ipld-ethcl-indexer >> ./config.sh
|
||||
cat ./config.sh
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.17.0"
|
||||
check-latest: true
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@latest
|
||||
which ginkgo
|
||||
|
||||
- name: Run the tests using Make
|
||||
run: |
|
||||
cd ipld-ethcl-indexer
|
||||
make unit-test-ci
|
||||
|
||||
integration-test:
|
||||
name: Run Integration Tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
foundry-test-ref: feature/build-stack
|
||||
ipld-eth-db-ref: main
|
||||
GOPATH: /tmp/go
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-ethcl-indexer"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.foundry-test-ref }}
|
||||
path: "./foundry-test/"
|
||||
repository: vulcanize/foundry-test
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.ipld-eth-db-ref }}
|
||||
repository: vulcanize/ipld-eth-db
|
||||
path: "./ipld-eth-db/"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_ipld_eth_db=$GITHUB_WORKSPACE/ipld-eth-db/ > ./config.sh
|
||||
echo vulcanize_ipld_ethcl_indexer=$GITHUB_WORKSPACE/ipld-ethcl-indexer >> ./config.sh
|
||||
cat ./config.sh
|
||||
|
||||
- name: Run docker compose
|
||||
run: |
|
||||
docker-compose \
|
||||
-f "$GITHUB_WORKSPACE/foundry-test/docker/local/docker-compose-db.yml" \
|
||||
-f "$GITHUB_WORKSPACE/foundry-test/docker/latest/docker-compose-lighthouse.yml" \
|
||||
--env-file ./config.sh \
|
||||
up -d --build
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.17.0"
|
||||
check-latest: true
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@latest
|
||||
which ginkgo
|
||||
|
||||
- name: Run the tests using Make
|
||||
run: |
|
||||
cd ipld-ethcl-indexer
|
||||
make integration-test-ci
|
||||
|
||||
golangci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.17.0"
|
||||
- uses: actions/checkout@v3
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
args: --disable errcheck
|
||||
trigger-tests:
|
||||
if: github.event_name != 'schedule'
|
||||
uses: ./.github/workflows/generic-testing.yml
|
||||
with:
|
||||
stack-orchestrator-ref: ${{ github.event.inputs.stack-orchestrator-ref }}
|
||||
ipld-eth-beacon-db-ref: ${{ github.event.inputs.ipld-eth-beacon-db-ref }}
|
||||
ssz-data-ref: ${{ github.event.inputs.ssz-data-ref }}
|
||||
secrets:
|
||||
GHA_KEY: ${{secrets.GHA_KEY}}
|
||||
system-testing:
|
||||
uses: ./.github/workflows/system-tests.yml
|
||||
with:
|
||||
stack-orchestrator-ref: ${{ github.event.inputs.stack-orchestrator-ref }}
|
||||
ipld-eth-beacon-db-ref: ${{ github.event.inputs.ipld-eth-beacon-db-ref }}
|
||||
secrets:
|
||||
GHA_KEY: ${{secrets.GHA_KEY}}
|
||||
BC_ADDRESS: ${{secrets.BC_ADDRESS}}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Publish Docker image
|
||||
on:
|
||||
release:
|
||||
types: [published, edited]
|
||||
jobs:
|
||||
trigger-tests:
|
||||
uses: ./.github/workflows/generic-testing.yml
|
||||
with:
|
||||
stack-orchestrator-ref: ${{ github.event.inputs.stack-orchestrator-ref }}
|
||||
ipld-eth-beacon-db-ref: ${{ github.event.inputs.ipld-eth-beacon-db-ref }}
|
||||
ssz-data-ref: ${{ github.event.inputs.ssz-data-ref }}
|
||||
secrets:
|
||||
GHA_KEY: ${{secrets.GHA_KEY}}
|
||||
system-testing:
|
||||
uses: ./.github/workflows/system-tests.yml
|
||||
with:
|
||||
stack-orchestrator-ref: ${{ github.event.inputs.stack-orchestrator-ref }}
|
||||
ipld-eth-beacon-db-ref: ${{ github.event.inputs.ipld-eth-beacon-db-ref }}
|
||||
secrets:
|
||||
GHA_KEY: ${{secrets.GHA_KEY}}
|
||||
BC_ADDRESS: ${{secrets.BC_ADDRESS}}
|
||||
build:
|
||||
name: Run docker build
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- trigger-tests
|
||||
- system-testing
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Get the version
|
||||
id: vars
|
||||
run: echo ::set-output name=sha::$(echo ${GITHUB_SHA:0:7})
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
- name: Tag docker image
|
||||
run: docker tag vulcanize/ipld-eth-beacon-indexer docker.pkg.github.com/vulcanize/ipld-eth-beacon-indexer/ipld-eth-beacon-indexer:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Login
|
||||
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login https://docker.pkg.github.com -u vulcanize --password-stdin
|
||||
- name: Docker Push
|
||||
run: docker push docker.pkg.github.com/vulcanize/ipld-eth-beacon-indexer/ipld-eth-beacon-indexer:${{steps.vars.outputs.sha}}
|
||||
push_to_registries:
|
||||
name: Push Docker image to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Get the version
|
||||
id: vars
|
||||
run: |
|
||||
echo ::set-output name=sha::$(echo ${GITHUB_SHA:0:7})
|
||||
echo ::set-output name=tag::$(echo ${GITHUB_REF#refs/tags/})
|
||||
- name: Docker Login to Github Registry
|
||||
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login https://docker.pkg.github.com -u vulcanize --password-stdin
|
||||
- name: Docker Pull
|
||||
run: docker pull docker.pkg.github.com/vulcanize/ipld-eth-beacon-indexer/ipld-eth-beacon-indexer:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Login to Docker Registry
|
||||
run: echo ${{ secrets.VULCANIZEJENKINS_PAT }} | docker login -u vulcanizejenkins --password-stdin
|
||||
- name: Tag docker image
|
||||
run: docker tag docker.pkg.github.com/vulcanize/ipld-eth-beacon-indexer/ipld-eth-beacon-indexer:${{steps.vars.outputs.sha}} vulcanize/ipld-eth-beacon-indexer:${{steps.vars.outputs.tag}}
|
||||
- name: Docker Push to Docker Hub
|
||||
run: docker push vulcanize/ipld-eth-beacon-indexer:${{steps.vars.outputs.tag}}
|
||||
@@ -0,0 +1,95 @@
|
||||
name: System Testing for the stack.
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
stack-orchestrator-ref:
|
||||
required: false
|
||||
type: string
|
||||
ipld-eth-beacon-db-ref:
|
||||
required: false
|
||||
type: string
|
||||
secrets:
|
||||
GHA_KEY:
|
||||
required: true
|
||||
BC_ADDRESS:
|
||||
required: true
|
||||
env:
|
||||
stack-orchestrator-ref: ${{ inputs.stack-orchestrator-ref || '7fb664270a0ba09e2caa3095e8c91f3fdb5b38af' }}
|
||||
ipld-eth-beacon-db-ref: ${{ inputs.ipld-eth-beacon-db-ref || '6b38fe9b18f7b19a803c626b742cafdccc1a2365' }}
|
||||
GOPATH: /tmp/go
|
||||
bc_protocol: "http"
|
||||
bc_address: ${{secrets.BC_ADDRESS}}
|
||||
bc_port: 5052
|
||||
db_host: localhost
|
||||
db_port: 8076
|
||||
db_name: vulcanize_testing
|
||||
db_user: vdbm
|
||||
db_password: password
|
||||
db_driver: "pgx"
|
||||
|
||||
jobs:
|
||||
system-testing:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-beacon-indexer"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.stack-orchestrator-ref }}
|
||||
path: "./stack-orchestrator/"
|
||||
repository: vulcanize/stack-orchestrator
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.ipld-eth-beacon-db-ref }}
|
||||
repository: vulcanize/ipld-eth-beacon-db
|
||||
path: "./ipld-eth-beacon-db/"
|
||||
ssh-key: ${{secrets.GHA_KEY}}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_ipld_eth_beacon_db=$(pwd)/ipld-eth-beacon-db > ./config.sh
|
||||
cat ./config.sh
|
||||
|
||||
- name: Run docker compose
|
||||
id: compose
|
||||
shell: bash
|
||||
run: |
|
||||
ls "./stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-db.yml"
|
||||
whoami
|
||||
/usr/local/bin/docker-compose \
|
||||
-f "./stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-db.yml" \
|
||||
--env-file ./config.sh \
|
||||
up -d --build
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.18.0"
|
||||
check-latest: true
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@latest
|
||||
which ginkgo
|
||||
|
||||
- name: Run the tests using Make
|
||||
run: |
|
||||
sleep 20
|
||||
cd ipld-eth-beacon-indexer
|
||||
make system-test-ci
|
||||
|
||||
- name: Clean up the docker containers
|
||||
if: always() && steps.compose.outcome == 'success'
|
||||
shell: bash
|
||||
run: |
|
||||
/usr/local/bin/docker-compose \
|
||||
-f "./stack-orchestrator/docker/local/docker-compose-ipld-eth-beacon-db.yml" \
|
||||
--env-file ./config.sh \
|
||||
down -v
|
||||
@@ -3,3 +3,11 @@ ipld-ethcl-indexer
|
||||
ipld-ethcl-indexer.log
|
||||
report.json
|
||||
cover.profile
|
||||
temp/*
|
||||
.vscode/*
|
||||
pkg/beaconclient/ssz-data/
|
||||
*.test
|
||||
ipld-eth-beacon-indexer.log
|
||||
ipld-eth-beacon-indexer
|
||||
config/local.ipld-eth-beacon-indexer-config.json
|
||||
config/docker.ipld-eth-beacon-indexer-config.json
|
||||
|
||||
+8
-7
@@ -1,7 +1,7 @@
|
||||
FROM golang:1.18-alpine as builder
|
||||
|
||||
WORKDIR /go/src/github.com/vulcanize/ipld-ethcl-indexer
|
||||
RUN apk --no-cache add ca-certificates make git g++ linux-headers
|
||||
WORKDIR /go/src/github.com/vulcanize/ipld-eth-beacon-indexer
|
||||
RUN apk --no-cache add ca-certificates make git g++ linux-headers libstdc++
|
||||
|
||||
ENV GO111MODULE=on
|
||||
COPY go.mod .
|
||||
@@ -9,12 +9,13 @@ COPY go.sum .
|
||||
RUN go mod tidy; go mod download
|
||||
COPY . .
|
||||
|
||||
RUN GCO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o ipld-ethcl-indexer .
|
||||
RUN chmod +x ipld-ethcl-indexer
|
||||
RUN GCO_ENABLED=0 GOOS=linux go build -race -ldflags="-s -w" -o ipld-eth-beacon-indexer .
|
||||
RUN chmod +x ipld-eth-beacon-indexer
|
||||
|
||||
FROM frolvlad/alpine-bash:latest
|
||||
RUN apk --no-cache add ca-certificates
|
||||
RUN apk --no-cache add ca-certificates libstdc++ busybox-extras gettext libintl
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /go/src/github.com/vulcanize/ipld-ethcl-indexer/ipld-ethcl-indexer /root/ipld-ethcl-indexer
|
||||
COPY --from=builder /go/src/github.com/vulcanize/ipld-eth-beacon-indexer/ipld-eth-beacon-indexer /root/ipld-eth-beacon-indexer
|
||||
ADD entrypoint.sh .
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
ADD ipld-eth-beacon-config-docker.json .
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
|
||||
@@ -30,6 +30,17 @@ integration-test-ci:
|
||||
--cover --coverprofile=cover.profile \
|
||||
--race --trace --json-report=report.json
|
||||
|
||||
.PHONY: integration-test-ci-no-race
|
||||
integration-test-ci-no-race:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter integration \
|
||||
--procs=4 --compilers=4 \
|
||||
--randomize-all --randomize-suites \
|
||||
--fail-on-pending --keep-going \
|
||||
--cover --coverprofile=cover.profile \
|
||||
--trace --json-report=report.json
|
||||
|
||||
.PHONY: integration-test-local
|
||||
integration-test-local:
|
||||
go vet ./...
|
||||
@@ -38,28 +49,76 @@ integration-test-local:
|
||||
--procs=4 --compilers=4 \
|
||||
--randomize-all --randomize-suites \
|
||||
--fail-on-pending --keep-going \
|
||||
--race --trace
|
||||
--trace --race
|
||||
|
||||
.PHONY: integration-test-local-no-race
|
||||
integration-test-local-no-race:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter integration \
|
||||
--procs=4 --compilers=4 \
|
||||
--randomize-all --randomize-suites \
|
||||
--fail-on-pending --keep-going \
|
||||
--trace
|
||||
|
||||
.PHONY: unit-test-local
|
||||
unit-test-local:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter unit \
|
||||
--procs=4 --compilers=4 \
|
||||
$(GINKGO) -r --label-filter 'unit && !flaky' \
|
||||
--randomize-all --randomize-suites \
|
||||
--flake-attempts=3 \
|
||||
--fail-on-pending --keep-going \
|
||||
--race --trace
|
||||
--trace
|
||||
|
||||
.PHONY: unit-test-local-bellatrix
|
||||
unit-test-local-bellatrix:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter 'unit && !flaky && bellatrix' \
|
||||
--randomize-all --randomize-suites \
|
||||
--flake-attempts=3 \
|
||||
--fail-on-pending --keep-going \
|
||||
--trace
|
||||
|
||||
.PHONY: unit-test-ci
|
||||
unit-test-ci:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter unit \
|
||||
--procs=4 --compilers=4 \
|
||||
--randomize-all --randomize-suites
|
||||
--flake-attempts=3 \
|
||||
--fail-on-pending --keep-going \
|
||||
--cover --coverprofile=cover.profile \
|
||||
--trace --json-report=report.json
|
||||
|
||||
.PHONY: system-test-ci
|
||||
system-test-ci:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter system \
|
||||
--randomize-all --randomize-suites \
|
||||
--fail-on-pending --keep-going \
|
||||
--cover --coverprofile=cover.profile \
|
||||
--race --trace --json-report=report.json
|
||||
--trace --json-report=report.json
|
||||
|
||||
.PHONY: system-test-local
|
||||
system-test-local:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter system \
|
||||
--randomize-all --randomize-suites \
|
||||
--fail-on-pending --keep-going \
|
||||
--trace
|
||||
|
||||
.PHONY: e2e-test-local
|
||||
e2e-test-local:
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r --label-filter e2e \
|
||||
--randomize-all --randomize-suites \
|
||||
--fail-on-pending --keep-going \
|
||||
--trace
|
||||
|
||||
|
||||
.PHONY: build
|
||||
@@ -70,4 +129,4 @@ build:
|
||||
## Build docker image
|
||||
.PHONY: docker-build
|
||||
docker-build:
|
||||
docker build -t vulcanize/ipld-ethcl-indexer .
|
||||
docker build -t vulcanize/ipld-eth-beacon-indexer .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- [ipld-ethcl-indexer](#ipld-ethcl-indexer)
|
||||
- [ipld-eth-beacon-indexer](#ipld-eth-beacon-indexer)
|
||||
- [Running the Application](#running-the-application)
|
||||
- [Development Patterns](#development-patterns)
|
||||
- [Logging](#logging)
|
||||
@@ -8,28 +8,46 @@
|
||||
|
||||
<small><i><a href='http://ecotrust-canada.github.io/markdown-toc/'>Table of contents generated with markdown-toc</a></i></small>
|
||||
|
||||
# ipld-ethcl-indexer
|
||||
# ipld-eth-beacon-indexer
|
||||
|
||||
This application will capture all the `BeaconState`'s and `SignedBeaconBlock`'s from the consensus chain on Ethereum. This application is going to connect to the lighthouse client, but hypothetically speaking, it should be interchangeable with any eth2 beacon node.
|
||||
|
||||
To learn more about the applications individual components, please read the [application components](/application_component.md).
|
||||
|
||||
# Running the Application
|
||||
# Quick Start
|
||||
|
||||
To run the application, utilize the following command, and update the values as needed.
|
||||
## Running the Application
|
||||
|
||||
To run the application, do as follows:
|
||||
|
||||
1. Setup the prerequisite applications.
|
||||
a. Run a beacon client (such as lighthouse).
|
||||
b. Run a postgres DB for eth-beacon.
|
||||
c. You can utilize the `stack-orchestrator` [repository](https://github.com/vulcanize/stack-orchestrato).
|
||||
|
||||
```
|
||||
./wrapper.sh -e skip \
|
||||
-d ../docker/local/docker-compose-ipld-eth-beacon-db.yml \
|
||||
-d ../docker/latest/docker-compose-lighthouse.yml \
|
||||
-v remove \
|
||||
-p ../local-config.sh
|
||||
|
||||
```
|
||||
|
||||
2. Run the start up command.
|
||||
|
||||
```
|
||||
go run main.go capture head --db.address localhost \
|
||||
--db.password password \
|
||||
--db.port 8077 \
|
||||
--db.username vdbm \
|
||||
--db.name vulcanize_testing \
|
||||
--db.driver PGX \
|
||||
--bc.address localhost \
|
||||
--bc.port 5052 \
|
||||
--log.level info
|
||||
go run -race main.go capture full --config ./example.ipld-eth-beacon-indexer-config.json
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run tests, you will need to clone another repository which contains all the ssz files.
|
||||
|
||||
1. `git clone git@github.com:vulcanize/ssz-data.git pkg/beaconclient/ssz-data`
|
||||
2. To run unit tests, make sure you have a DB running: `make unit-test-local`
|
||||
3. To run integration tests, make sure you have a lighthouse client and a DB running: `make integration-test-local-no-race` .
|
||||
|
||||
# Development Patterns
|
||||
|
||||
This section will cover some generic development patterns utilizes.
|
||||
@@ -58,9 +76,18 @@ This project utilizes `ginkgo` for testing. A few notes on testing:
|
||||
- All test packages are named `{base_package}_test`. This ensures we only test the public methods.
|
||||
- If there is a need to test a private method, please include why in the testing file.
|
||||
- Unit tests must contain the `Label("unit")`.
|
||||
- Unit tests should not rely on any running service. If a running service is needed. Utilize an integration test.
|
||||
- Unit tests should not rely on any running service (except for a postgres DB). If a running service is needed. Utilize an integration test.
|
||||
- Integration tests must contain the `Label("integration")`.
|
||||
|
||||
#### Understanding Testing Components
|
||||
|
||||
A few notes about the testing components.
|
||||
|
||||
- The `TestEvents` map contains several events for testers to leverage when testing.
|
||||
- Any object ending in `-dummy` is not a real object. You will also notice it has a present field called `MimicConfig`. This object will use an existing SSZ object, and update the parameters from the `Head` and `MimicConfig`.
|
||||
- This is done because creating an empty or minimal `SignedBeaconBlock` and `BeaconState` is fairly challenging.
|
||||
- By slightly modifying an existing object, we can test re-org, malformed objects, and other negative conditions.
|
||||
|
||||
# Contribution
|
||||
|
||||
If you want to contribute please make sure you do the following:
|
||||
|
||||
@@ -22,6 +22,33 @@ The `database` package allows us to interact with a postgres DB. We utilize the
|
||||
|
||||
This package will contain code to interact with the beacon client.
|
||||
|
||||
### Known Gaps
|
||||
|
||||
Known Gaps tracking is handled within this package. The columns are as follows:
|
||||
|
||||
- StartSlot - The start slot for known_gaps, inclusive.
|
||||
- EndSlot - The end slot for known_gaps, inclusive.
|
||||
- CheckedOut - Indicates if any process is currently processing this entry.
|
||||
- ErrorMessage - Captures any error message that might have occurred when previously processing this entry.
|
||||
- EntryTime - The time this range was added to the DB. This can help us catch ranges that have not been processed for a long time due to some error.
|
||||
- EntryProcess - The entry process that added this process. Potential options are StartUp, Error, HeadGap.
|
||||
- This can help us understand how a specific entry was added. It can be useful for debugging the application.
|
||||
- StartUp - Gaps found when we started the application.
|
||||
- Error - Indicates that the entry was added due to an error with processing.
|
||||
- HeadGap - Indicates that gaps where found when keeping up with Head.
|
||||
|
||||
## `pkg/version`
|
||||
|
||||
A generic package which can be utilized to easily version our applications.
|
||||
|
||||
## `pkg/gracefulshutdown`
|
||||
|
||||
A generic package that can be used to shutdown various services within an application.
|
||||
|
||||
## `pkg/loghelper`
|
||||
|
||||
This package contains useful functions for logging.
|
||||
|
||||
## `internal/shutdown`
|
||||
|
||||
This package is used to shutdown the `ipld-eth-beacon-indexer`. It calls the `pkg/gracefulshutdown` package.
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/boot"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/shutdown"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// bootCmd represents the boot command
|
||||
var bootCmd = &cobra.Command{
|
||||
Use: "boot",
|
||||
Short: "Run the boot command then exit",
|
||||
Long: `Run the application to boot and exit. Primarily used for testing.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
bootApp()
|
||||
},
|
||||
}
|
||||
|
||||
func bootApp() {
|
||||
|
||||
// Boot the application
|
||||
log.Info("Starting the application in boot mode.")
|
||||
ctx := context.Background()
|
||||
|
||||
Bc, Db, err := boot.BootApplicationWithRetry(ctx, viper.GetString("db.address"), viper.GetInt("db.port"), viper.GetString("db.name"), viper.GetString("db.username"), viper.GetString("db.password"), viper.GetString("db.driver"),
|
||||
viper.GetString("bc.address"), viper.GetInt("bc.port"), viper.GetString("bc.connectionProtocol"), viper.GetString("bc.type"), viper.GetInt("bc.bootRetryInterval"), viper.GetInt("bc.bootMaxRetry"),
|
||||
viper.GetInt("kg.increment"), "boot", viper.GetBool("t.skipSync"), viper.GetInt("bc.uniqueNodeIdentifier"), viper.GetBool("bc.checkDb"),
|
||||
viper.GetBool("bc.performBeaconBlockProcessing"), viper.GetBool("bc.performBeaconStateProcessing"))
|
||||
if err != nil {
|
||||
StopApplicationPreBoot(err, Db)
|
||||
}
|
||||
|
||||
log.Info("Boot complete, we are going to shutdown.")
|
||||
|
||||
notifierCh := make(chan os.Signal, 1)
|
||||
|
||||
go func() {
|
||||
notifierCh <- syscall.SIGTERM
|
||||
}()
|
||||
|
||||
err = shutdown.ShutdownBoot(ctx, notifierCh, maxWaitSecondsShutdown, Db, Bc)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Ungracefully Shutdown ipld-eth-beacon-indexer!")
|
||||
} else {
|
||||
log.Info("Gracefully shutdown ipld-eth-beacon-indexer")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
captureCmd.AddCommand(bootCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// bootCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// bootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
+111
-33
@@ -1,10 +1,23 @@
|
||||
/*
|
||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -13,16 +26,30 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
dbUsername string
|
||||
dbPassword string
|
||||
dbName string
|
||||
dbAddress string
|
||||
dbDriver string
|
||||
dbPort int
|
||||
bcAddress string
|
||||
bcPort int
|
||||
bcConnectionProtocol string
|
||||
maxWaitSecondsShutdown time.Duration = time.Duration(5) * time.Second
|
||||
dbUsername string
|
||||
dbPassword string
|
||||
dbName string
|
||||
dbAddress string
|
||||
dbDriver string
|
||||
dbPort int
|
||||
bcAddress string
|
||||
bcPort int
|
||||
bcBootRetryInterval int
|
||||
bcBootMaxRetry int
|
||||
bcConnectionProtocol string
|
||||
bcType string
|
||||
bcMaxHistoricProcessWorker int
|
||||
bcUniqueNodeIdentifier int
|
||||
bcCheckDb bool
|
||||
kgMaxWorker int
|
||||
kgTableIncrement int
|
||||
kgProcessGaps bool
|
||||
pmMetrics bool
|
||||
pmAddress string
|
||||
pmPort int
|
||||
maxWaitSecondsShutdown time.Duration = time.Duration(20) * time.Second
|
||||
notifierCh chan os.Signal = make(chan os.Signal, 1)
|
||||
testDisregardSync bool
|
||||
)
|
||||
|
||||
// captureCmd represents the capture command
|
||||
@@ -47,31 +74,50 @@ func init() {
|
||||
captureCmd.PersistentFlags().StringVarP(&dbName, "db.name", "n", "", "Database name connect to DB(required)")
|
||||
captureCmd.PersistentFlags().StringVarP(&dbDriver, "db.driver", "", "", "Database Driver to connect to DB(required)")
|
||||
captureCmd.PersistentFlags().IntVarP(&dbPort, "db.port", "", 0, "Port to connect to DB(required)")
|
||||
err := captureCmd.MarkPersistentFlagRequired("db.username")
|
||||
exitErr(err)
|
||||
err = captureCmd.MarkPersistentFlagRequired("db.password")
|
||||
exitErr(err)
|
||||
err = captureCmd.MarkPersistentFlagRequired("db.address")
|
||||
exitErr(err)
|
||||
err = captureCmd.MarkPersistentFlagRequired("db.port")
|
||||
exitErr(err)
|
||||
err = captureCmd.MarkPersistentFlagRequired("db.name")
|
||||
exitErr(err)
|
||||
err = captureCmd.MarkPersistentFlagRequired("db.driver")
|
||||
exitErr(err)
|
||||
//err := captureCmd.MarkPersistentFlagRequired("db.username")
|
||||
// exitErr(err)
|
||||
// err = captureCmd.MarkPersistentFlagRequired("db.password")
|
||||
// exitErr(err)
|
||||
// err = captureCmd.MarkPersistentFlagRequired("db.address")
|
||||
// exitErr(err)
|
||||
// err = captureCmd.MarkPersistentFlagRequired("db.port")
|
||||
// exitErr(err)
|
||||
// err = captureCmd.MarkPersistentFlagRequired("db.name")
|
||||
// exitErr(err)
|
||||
// err = captureCmd.MarkPersistentFlagRequired("db.driver")
|
||||
// exitErr(err)
|
||||
|
||||
//// Beacon Client Specific
|
||||
captureCmd.PersistentFlags().StringVarP(&bcAddress, "bc.address", "l", "", "Address to connect to beacon node (required if username is set)")
|
||||
captureCmd.PersistentFlags().IntVarP(&bcPort, "bc.port", "r", 0, "Port to connect to beacon node (required if username is set)")
|
||||
captureCmd.PersistentFlags().StringVarP(&bcAddress, "bc.address", "l", "", "Address to connect to beacon node (required)")
|
||||
captureCmd.PersistentFlags().StringVarP(&bcType, "bc.type", "", "lighthouse", "The beacon client we are using, options are prysm and lighthouse.")
|
||||
captureCmd.PersistentFlags().IntVarP(&bcPort, "bc.port", "r", 0, "Port to connect to beacon node (required )")
|
||||
captureCmd.PersistentFlags().StringVarP(&bcConnectionProtocol, "bc.connectionProtocol", "", "http", "protocol for connecting to the beacon node.")
|
||||
err = captureCmd.MarkPersistentFlagRequired("bc.address")
|
||||
exitErr(err)
|
||||
err = captureCmd.MarkPersistentFlagRequired("bc.port")
|
||||
exitErr(err)
|
||||
captureCmd.PersistentFlags().IntVarP(&bcBootRetryInterval, "bc.bootRetryInterval", "", 30, "The amount of time to wait between retries while booting the application")
|
||||
captureCmd.PersistentFlags().IntVarP(&bcBootMaxRetry, "bc.bootMaxRetry", "", 5, "The amount of time to wait between retries while booting the application")
|
||||
captureCmd.PersistentFlags().IntVarP(&bcMaxHistoricProcessWorker, "bc.maxHistoricProcessWorker", "", 30, "The number of workers that should be actively processing slots from the eth-beacon.historic_process table. Be careful of system memory.")
|
||||
captureCmd.PersistentFlags().IntVarP(&bcUniqueNodeIdentifier, "bc.uniqueNodeIdentifier", "", 0, "The unique identifier of this application. Each application connecting to the DB should have a unique identifier.")
|
||||
captureCmd.PersistentFlags().BoolVarP(&bcCheckDb, "bc.checkDb", "", true, "Should we check to see if the slot exists in the DB before writing it?")
|
||||
// err = captureCmd.MarkPersistentFlagRequired("bc.address")
|
||||
// exitErr(err)
|
||||
// err = captureCmd.MarkPersistentFlagRequired("bc.port")
|
||||
// exitErr(err)
|
||||
|
||||
//// Known Gaps specific
|
||||
captureCmd.PersistentFlags().BoolVarP(&kgProcessGaps, "kg.processKnownGaps", "", true, "Should we process the slots within the eth-beacon.known_gaps table.")
|
||||
captureCmd.PersistentFlags().IntVarP(&kgTableIncrement, "kg.increment", "", 10000, "The max slots within a single entry to the known_gaps table.")
|
||||
captureCmd.PersistentFlags().IntVarP(&kgMaxWorker, "kg.maxKnownGapsWorker", "", 30, "The number of workers that should be actively processing slots from the eth-beacon.known_gaps table. Be careful of system memory.")
|
||||
|
||||
// Prometheus Specific
|
||||
captureCmd.PersistentFlags().BoolVarP(&pmMetrics, "pm.metrics", "", true, "Should we capture prometheus metrics.")
|
||||
captureCmd.PersistentFlags().StringVarP(&pmAddress, "pm.address", "", "localhost", "Address to send the prometheus metrics.")
|
||||
captureCmd.PersistentFlags().IntVarP(&pmPort, "pm.port", "", 9000, "The port to send prometheus metrics.")
|
||||
|
||||
//// Testing Specific
|
||||
captureCmd.PersistentFlags().BoolVar(&testDisregardSync, "t.skipSync", false, "Should we disregard the head sync?")
|
||||
|
||||
// Bind Flags with Viper
|
||||
//// DB Flags
|
||||
err = viper.BindPFlag("db.username", captureCmd.PersistentFlags().Lookup("db.username"))
|
||||
err := viper.BindPFlag("db.username", captureCmd.PersistentFlags().Lookup("db.username"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("db.password", captureCmd.PersistentFlags().Lookup("db.password"))
|
||||
exitErr(err)
|
||||
@@ -84,21 +130,53 @@ func init() {
|
||||
err = viper.BindPFlag("db.driver", captureCmd.PersistentFlags().Lookup("db.driver"))
|
||||
exitErr(err)
|
||||
|
||||
// LH specific
|
||||
//// Testing Specific
|
||||
err = viper.BindPFlag("t.skipSync", captureCmd.PersistentFlags().Lookup("t.skipSync"))
|
||||
exitErr(err)
|
||||
|
||||
//// LH specific
|
||||
err = viper.BindPFlag("bc.address", captureCmd.PersistentFlags().Lookup("bc.address"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.type", captureCmd.PersistentFlags().Lookup("bc.type"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.port", captureCmd.PersistentFlags().Lookup("bc.port"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.connectionProtocol", captureCmd.PersistentFlags().Lookup("bc.connectionProtocol"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.bootRetryInterval", captureCmd.PersistentFlags().Lookup("bc.bootRetryInterval"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.bootMaxRetry", captureCmd.PersistentFlags().Lookup("bc.bootMaxRetry"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.maxHistoricProcessWorker", captureCmd.PersistentFlags().Lookup("bc.maxHistoricProcessWorker"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.uniqueNodeIdentifier", captureCmd.PersistentFlags().Lookup("bc.uniqueNodeIdentifier"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("bc.checkDb", captureCmd.PersistentFlags().Lookup("bc.checkDb"))
|
||||
exitErr(err)
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
//// Known Gap Specific
|
||||
err = viper.BindPFlag("kg.processKnownGaps", captureCmd.PersistentFlags().Lookup("kg.processKnownGaps"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("kg.increment", captureCmd.PersistentFlags().Lookup("kg.increment"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("kg.processKnownGaps", captureCmd.PersistentFlags().Lookup("kg.maxKnownGapsWorker"))
|
||||
exitErr(err)
|
||||
|
||||
// Prometheus Specific
|
||||
err = viper.BindPFlag("pm.metrics", captureCmd.PersistentFlags().Lookup("pm.metrics"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("pm.address", captureCmd.PersistentFlags().Lookup("pm.address"))
|
||||
exitErr(err)
|
||||
err = viper.BindPFlag("pm.port", captureCmd.PersistentFlags().Lookup("pm.port"))
|
||||
exitErr(err)
|
||||
}
|
||||
|
||||
// Helper function to catch any errors.
|
||||
// We need to capture these errors for the linter.
|
||||
func exitErr(err error) {
|
||||
if err != nil {
|
||||
fmt.Println("Error: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"strconv"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/boot"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/shutdown"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// fullCmd represents the full command
|
||||
var fullCmd = &cobra.Command{
|
||||
Use: "full",
|
||||
Short: "Capture all components of the application (head and historical)",
|
||||
Long: `Capture all components of the application (head and historical)`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
startFullProcessing()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
captureCmd.AddCommand(fullCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// fullCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// fullCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
// Start the application to track at head and historical processing.
|
||||
func startFullProcessing() {
|
||||
// Boot the application
|
||||
log.Info("Starting the application in head tracking mode.")
|
||||
ctx := context.Background()
|
||||
|
||||
Bc, Db, err := boot.BootApplicationWithRetry(ctx, viper.GetString("db.address"), viper.GetInt("db.port"), viper.GetString("db.name"), viper.GetString("db.username"), viper.GetString("db.password"), viper.GetString("db.driver"),
|
||||
viper.GetString("bc.address"), viper.GetInt("bc.port"), viper.GetString("bc.connectionProtocol"), viper.GetString("bc.type"), viper.GetInt("bc.bootRetryInterval"), viper.GetInt("bc.bootMaxRetry"),
|
||||
viper.GetInt("kg.increment"), "head", viper.GetBool("t.skipSync"), viper.GetInt("bc.uniqueNodeIdentifier"), viper.GetBool("bc.checkDb"),
|
||||
viper.GetBool("bc.performBeaconBlockProcessing"), viper.GetBool("bc.performBeaconStateProcessing"))
|
||||
if err != nil {
|
||||
StopApplicationPreBoot(err, Db)
|
||||
}
|
||||
|
||||
if viper.GetBool("pm.metrics") {
|
||||
addr := viper.GetString("pm.address") + ":" + strconv.Itoa(viper.GetInt("pm.port"))
|
||||
serveProm(addr)
|
||||
}
|
||||
|
||||
log.Info("The Beacon Client has booted successfully!")
|
||||
// Capture head blocks
|
||||
go Bc.CaptureHead()
|
||||
|
||||
hpContext, hpCancel := context.WithCancel(context.Background())
|
||||
|
||||
errG, _ := errgroup.WithContext(context.Background())
|
||||
errG.Go(func() error {
|
||||
errs := Bc.CaptureHistoric(hpContext, viper.GetInt("bc.maxHistoricProcessWorker"), beaconclient.Slot(viper.GetUint64("bc.minimumSlot")))
|
||||
if len(errs) != 0 {
|
||||
if len(errs) != 0 {
|
||||
log.WithFields(log.Fields{"errs": errs}).Error("All errors when processing historic events")
|
||||
return fmt.Errorf("Application ended because there were too many error when attempting to process historic")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
kgCtx, KgCancel := context.WithCancel(context.Background())
|
||||
if viper.GetBool("kg.processKnownGaps") {
|
||||
go func() {
|
||||
errG := new(errgroup.Group)
|
||||
errG.Go(func() error {
|
||||
errs := Bc.ProcessKnownGaps(kgCtx, viper.GetInt("kg.maxKnownGapsWorker"), beaconclient.Slot(viper.GetUint64("kg.minimumSlot")))
|
||||
if len(errs) != 0 {
|
||||
log.WithFields(log.Fields{"errs": errs}).Error("All errors when processing knownGaps")
|
||||
return fmt.Errorf("Application ended because there were too many error when attempting to process knownGaps")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err := errG.Wait(); err != nil {
|
||||
loghelper.LogError(err).Error("Error with knownGaps processing")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Shutdown when the time is right.
|
||||
err = shutdown.ShutdownFull(ctx, KgCancel, hpCancel, notifierCh, maxWaitSecondsShutdown, Db, Bc)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Ungracefully Shutdown ipld-eth-beacon-indexer!")
|
||||
} else {
|
||||
log.Info("Gracefully shutdown ipld-eth-beacon-indexer")
|
||||
}
|
||||
|
||||
}
|
||||
+75
-19
@@ -1,18 +1,36 @@
|
||||
/*
|
||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"fmt"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/internal/boot"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/internal/shutdown"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/boot"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/shutdown"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// headCmd represents the head command
|
||||
@@ -31,28 +49,66 @@ func startHeadTracking() {
|
||||
log.Info("Starting the application in head tracking mode.")
|
||||
ctx := context.Background()
|
||||
|
||||
BC, DB, err := boot.BootApplicationWithRetry(ctx, dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol)
|
||||
Bc, Db, err := boot.BootApplicationWithRetry(ctx, viper.GetString("db.address"), viper.GetInt("db.port"), viper.GetString("db.name"), viper.GetString("db.username"), viper.GetString("db.password"), viper.GetString("db.driver"),
|
||||
viper.GetString("bc.address"), viper.GetInt("bc.port"), viper.GetString("bc.connectionProtocol"), viper.GetString("bc.type"), viper.GetInt("bc.bootRetryInterval"), viper.GetInt("bc.bootMaxRetry"),
|
||||
viper.GetInt("kg.increment"), "head", viper.GetBool("t.skipSync"), viper.GetInt("bc.uniqueNodeIdentifier"), viper.GetBool("bc.checkDb"),
|
||||
viper.GetBool("bc.performBeaconBlockProcessing"), viper.GetBool("bc.performBeaconStateProcessing"))
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to Start application")
|
||||
StopApplicationPreBoot(err, Db)
|
||||
}
|
||||
|
||||
if viper.GetBool("pm.metrics") {
|
||||
addr := viper.GetString("pm.address") + ":" + strconv.Itoa(viper.GetInt("pm.port"))
|
||||
serveProm(addr)
|
||||
}
|
||||
|
||||
log.Info("The Beacon Client has booted successfully!")
|
||||
// Capture head blocks
|
||||
go BC.CaptureHead()
|
||||
go Bc.CaptureHead()
|
||||
kgCtx, KgCancel := context.WithCancel(context.Background())
|
||||
if viper.GetBool("kg.processKnownGaps") {
|
||||
go func() {
|
||||
errG := new(errgroup.Group)
|
||||
errG.Go(func() error {
|
||||
errs := Bc.ProcessKnownGaps(kgCtx, viper.GetInt("kg.maxKnownGapsWorker"), beaconclient.Slot(viper.GetUint64("kg.minimumSlot")))
|
||||
if len(errs) != 0 {
|
||||
log.WithFields(log.Fields{"errs": errs}).Error("All errors when processing knownGaps")
|
||||
return fmt.Errorf("Application ended because there were too many error when attempting to process knownGaps")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err := errG.Wait(); err != nil {
|
||||
loghelper.LogError(err).Error("Error with knownGaps processing")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Shutdown when the time is right.
|
||||
shutdown.ShutdownServices(ctx, time.Duration(maxWaitSecondsShutdown), DB, BC)
|
||||
err = shutdown.ShutdownHeadTracking(ctx, KgCancel, notifierCh, maxWaitSecondsShutdown, Db, Bc)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Ungracefully Shutdown ipld-eth-beacon-indexer!")
|
||||
} else {
|
||||
log.Info("Gracefully shutdown ipld-eth-beacon-indexer")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
captureCmd.AddCommand(headCmd)
|
||||
}
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Start prometheus server
|
||||
func serveProm(addr string) {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// headCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// headCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
srv := http.Server{
|
||||
Addr: addr,
|
||||
Handler: mux,
|
||||
}
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
loghelper.LogError(err).WithField("endpoint", addr).Error("Error with prometheus")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
+96
-4
@@ -1,13 +1,36 @@
|
||||
/*
|
||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/boot"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/shutdown"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// historicCmd represents the historic command
|
||||
@@ -16,10 +39,70 @@ var historicCmd = &cobra.Command{
|
||||
Short: "Capture the historic blocks and states.",
|
||||
Long: `Capture the historic blocks and states.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("historic called")
|
||||
startHistoricProcessing()
|
||||
},
|
||||
}
|
||||
|
||||
// Start the application to process historical slots.
|
||||
func startHistoricProcessing() {
|
||||
// Boot the application
|
||||
log.Info("Starting the application in head tracking mode.")
|
||||
ctx := context.Background()
|
||||
|
||||
Bc, Db, err := boot.BootApplicationWithRetry(ctx, viper.GetString("db.address"), viper.GetInt("db.port"), viper.GetString("db.name"), viper.GetString("db.username"), viper.GetString("db.password"), viper.GetString("db.driver"),
|
||||
viper.GetString("bc.address"), viper.GetInt("bc.port"), viper.GetString("bc.connectionProtocol"), viper.GetString("bc.type"), viper.GetInt("bc.bootRetryInterval"), viper.GetInt("bc.bootMaxRetry"),
|
||||
viper.GetInt("kg.increment"), "historic", viper.GetBool("t.skipSync"), viper.GetInt("bc.uniqueNodeIdentifier"), viper.GetBool("bc.checkDb"),
|
||||
viper.GetBool("bc.performBeaconBlockProcessing"), viper.GetBool("bc.performBeaconStateProcessing"))
|
||||
if err != nil {
|
||||
StopApplicationPreBoot(err, Db)
|
||||
}
|
||||
|
||||
if viper.GetBool("pm.metrics") {
|
||||
addr := viper.GetString("pm.address") + ":" + strconv.Itoa(viper.GetInt("pm.port"))
|
||||
serveProm(addr)
|
||||
}
|
||||
|
||||
hpContext, hpCancel := context.WithCancel(context.Background())
|
||||
|
||||
errG, _ := errgroup.WithContext(context.Background())
|
||||
errG.Go(func() error {
|
||||
errs := Bc.CaptureHistoric(hpContext, viper.GetInt("bc.maxHistoricProcessWorker"), beaconclient.Slot(viper.GetUint64("bc.minimumSlot")))
|
||||
if len(errs) != 0 {
|
||||
if len(errs) != 0 {
|
||||
log.WithFields(log.Fields{"errs": errs}).Error("All errors when processing historic events")
|
||||
return fmt.Errorf("Application ended because there were too many error when attempting to process historic")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
kgContext, kgCancel := context.WithCancel(context.Background())
|
||||
if viper.GetBool("kg.processKnownGaps") {
|
||||
go func() {
|
||||
errG := new(errgroup.Group)
|
||||
errG.Go(func() error {
|
||||
errs := Bc.ProcessKnownGaps(kgContext, viper.GetInt("kg.maxKnownGapsWorker"), beaconclient.Slot(viper.GetUint64("kg.minimumSlot")))
|
||||
if len(errs) != 0 {
|
||||
log.WithFields(log.Fields{"errs": errs}).Error("All errors when processing knownGaps")
|
||||
return fmt.Errorf("Application ended because there were too many error when attempting to process knownGaps")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err := errG.Wait(); err != nil {
|
||||
loghelper.LogError(err).Error("Error with knownGaps processing")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Shutdown when the time is right.
|
||||
err = shutdown.ShutdownHistoricProcessing(ctx, kgCancel, hpCancel, notifierCh, maxWaitSecondsShutdown, Db, Bc)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Ungracefully Shutdown ipld-eth-beacon-indexer!")
|
||||
} else {
|
||||
log.Info("Gracefully shutdown ipld-eth-beacon-indexer")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
captureCmd.AddCommand(historicCmd)
|
||||
|
||||
@@ -33,3 +116,12 @@ func init() {
|
||||
// is called directly, e.g.:
|
||||
// historicCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
// Stop the application during its initial boot phases.
|
||||
func StopApplicationPreBoot(startErr error, db sql.Database) {
|
||||
loghelper.LogError(startErr).Error("Unable to Start application")
|
||||
if db != nil {
|
||||
db.Close()
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
+21
-8
@@ -1,7 +1,19 @@
|
||||
/*
|
||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
@@ -20,7 +32,7 @@ var (
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "ipld-ethcl-indexer",
|
||||
Use: "ipld-eth-beacon-indexer",
|
||||
Short: "This application will keep track of all BeaconState's and SignedBeaconBlock's on the Beacon Chain.",
|
||||
Long: `This is an application that will capture the BeaconState's and SignedBeaconBlock's on the Beacon Chain.
|
||||
It can either do this will keeping track of head, or backfilling historic data.`,
|
||||
@@ -35,6 +47,7 @@ It can either do this will keeping track of head, or backfilling historic data.`
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
fmt.Println("Err when executing rootCmd", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -114,9 +127,9 @@ func init() {
|
||||
// will be global for your application.
|
||||
|
||||
// Optional Flags
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.ipld-ethcl-indexer.yaml)")
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.ipld-eth-beacon-indexer.yaml)")
|
||||
rootCmd.PersistentFlags().String("log.level", log.InfoLevel.String(), "log level (trace, debug, info, warn, error, fatal, panic)")
|
||||
rootCmd.PersistentFlags().String("log.file", "ipld-ethcl-indexer.log", "file path for logging")
|
||||
rootCmd.PersistentFlags().String("log.file", "ipld-eth-beacon-indexer.log", "file path for logging")
|
||||
rootCmd.PersistentFlags().Bool("log.output", true, "Should we log to STDOUT")
|
||||
rootCmd.PersistentFlags().String("log.format", "json", "json or text")
|
||||
|
||||
@@ -147,10 +160,10 @@ func initConfig() {
|
||||
home, err := os.UserHomeDir()
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".ipld-ethcl-indexer" (without extension).
|
||||
// Search config in home directory with name ".ipld-eth-beacon-indexer" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
viper.SetConfigType("yaml")
|
||||
viper.SetConfigName(".ipld-ethcl-indexer")
|
||||
viper.SetConfigName(".ipld-eth-beacon-indexer")
|
||||
}
|
||||
|
||||
viper.AutomaticEnv() // read in environment variables that match
|
||||
|
||||
+17
-2
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
@@ -5,7 +20,7 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
v "github.com/vulcanize/ipld-ethcl-indexer/pkg/version"
|
||||
v "github.com/vulcanize/ipld-eth-beacon-indexer/pkg/version"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -32,7 +47,7 @@ to quickly create a Cobra application.`,
|
||||
Patch: Patch,
|
||||
Meta: Meta,
|
||||
}
|
||||
log.Infof("ipld-ethcl-indexer version: %s", version.GetVersionWithMeta())
|
||||
log.Infof("ipld-eth-beacon-indexer version: %s", version.GetVersionWithMeta())
|
||||
fmt.Println(version.GetVersionWithMeta())
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"db": {
|
||||
"address": "ipld-eth-beacon-db",
|
||||
"password": "password",
|
||||
"port": 5432,
|
||||
"username": "vdbm",
|
||||
"name": "vulcanize_testing",
|
||||
"driver": "PGX"
|
||||
},
|
||||
"bc": {
|
||||
"address": "lighthouse",
|
||||
"port": 5052,
|
||||
"type": "lighthouse",
|
||||
"bootRetryInterval": 30,
|
||||
"bootMaxRetry": 5,
|
||||
"maxHistoricProcessWorker": 2,
|
||||
"connectionProtocol": "http",
|
||||
"uniqueNodeIdentifier": 100,
|
||||
"checkDb": true
|
||||
},
|
||||
"t": {
|
||||
"skipSync": true
|
||||
},
|
||||
"log": {
|
||||
"level": "debug",
|
||||
"output": true,
|
||||
"file": "./ipld-eth-beacon-indexer.log",
|
||||
"format": "json"
|
||||
},
|
||||
"kg": {
|
||||
"increment": 10000,
|
||||
"processKnownGaps": true,
|
||||
"maxKnownGapsWorker": 2
|
||||
},
|
||||
"pm": {
|
||||
"address": "localhost",
|
||||
"port": 9000,
|
||||
"metrics": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../ipld-eth-beacon-config.json
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"db": {
|
||||
"address": "localhost",
|
||||
"password": "secret12",
|
||||
"port": 45432,
|
||||
"username": "postgres",
|
||||
"name": "postgres",
|
||||
"driver": "PGX"
|
||||
},
|
||||
"bc": {
|
||||
"address": "localhost",
|
||||
"port": 8001,
|
||||
"type": "lighthouse",
|
||||
"bootRetryInterval": 30,
|
||||
"bootMaxRetry": 5,
|
||||
"maxHistoricProcessWorker": 2,
|
||||
"connectionProtocol": "http",
|
||||
"uniqueNodeIdentifier": 100,
|
||||
"checkDb": true
|
||||
},
|
||||
"t": {
|
||||
"skipSync": true
|
||||
},
|
||||
"log": {
|
||||
"level": "debug",
|
||||
"output": true,
|
||||
"file": "./ipld-eth-beacon-indexer.log",
|
||||
"format": "json"
|
||||
},
|
||||
"kg": {
|
||||
"increment": 10000,
|
||||
"processKnownGaps": true,
|
||||
"maxKnownGapsWorker": 2
|
||||
},
|
||||
"pm": {
|
||||
"address": "localhost",
|
||||
"port": 9000,
|
||||
"metrics": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
version: "3.2"
|
||||
services:
|
||||
ipld-eth-beacon-db:
|
||||
hostname: ipld-eth-beacon-db
|
||||
env_file:
|
||||
- docker.env
|
||||
restart: always
|
||||
build:
|
||||
dockerfile: ../ipld-eth-beacon-db/Dockerfile
|
||||
context: ../ipld-eth-beacon-db
|
||||
image: cerc/ipld-eth-beacon-db:local
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "5432"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
volumes:
|
||||
- vdb_db_eth-beacon_db:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432"
|
||||
command: ["postgres", "-c", "log_min_duration_statement=250"]
|
||||
|
||||
ipld-eth-beacon-indexer:
|
||||
hostname: ipld-eth-beacon-indexer
|
||||
env_file:
|
||||
- docker.env
|
||||
restart: always
|
||||
build:
|
||||
dockerfile: ./Dockerfile
|
||||
context: .
|
||||
depends_on:
|
||||
- ipld-eth-beacon-db
|
||||
image: cerc/ipld-eth-beacon-indexer:local
|
||||
|
||||
volumes:
|
||||
vdb_db_eth-beacon_db:
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
POSTGRES_HOST=ipld-eth-beacon-db
|
||||
POSTGRES_PASSWORD=CHANGEME
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=ethbeacondb
|
||||
POSTGRES_DB=ethbeacondb
|
||||
|
||||
LIGHTHOUSE_HOST=host.docker.internal
|
||||
LIGHTHOUSE_PORT=5052
|
||||
LIGHTHOUSE_PROTOCOL=http
|
||||
|
||||
CAPTURE_MODE=head
|
||||
LOG_LEVEL=debug
|
||||
|
||||
BC_MAX_HISTORIC_PROCESS_WORKER=2
|
||||
BC_UNIQUE_NODE_IDENTIFIER=100
|
||||
BC_CHECK_DB=true
|
||||
BC_BEACON_STATE_PROCESSING_ENABLED=false
|
||||
BC_BEACON_BLOCK_PROCESSING_ENABLED=true
|
||||
BC_MINIMUM_SLOT=4700013
|
||||
|
||||
KG_INCREMENT=10000
|
||||
KG_PROCESS_KNOWN_GAPS_ENABLED=true
|
||||
KG_MAX_KNOWN_GAPS_WORKER=2
|
||||
KG_MINIMUM_SLOT=4700013
|
||||
|
||||
PROM_HOST=host.docker.internal
|
||||
PROM_PORT=9000
|
||||
PROM_METRICS_ENABLED=false
|
||||
+22
-25
@@ -1,31 +1,28 @@
|
||||
#!/bin/bash
|
||||
echo "Starting ipld-ethcl-indexer"
|
||||
|
||||
echo /root/ipld-ethcl-indexer capture head --db.address $DB_ADDRESS \
|
||||
--db.password $DB_PASSWORD \
|
||||
--db.port $DB_PORT \
|
||||
--db.username $DB_USER \
|
||||
--db.name $DB_NAME \
|
||||
--db.driver $DB_DRIVER \
|
||||
--bc.address $BC_ADDRESS \
|
||||
--bc.port $BC_PORT \
|
||||
--log.level $LOG_LEVEL
|
||||
sleep 10
|
||||
echo "Starting ipld-eth-beacon-indexer"
|
||||
|
||||
/root/ipld-ethcl-indexer capture head --db.address $DB_ADDRESS \
|
||||
--db.password $DB_PASSWORD \
|
||||
--db.port $DB_PORT \
|
||||
--db.username $DB_USER \
|
||||
--db.name $DB_NAME \
|
||||
--db.driver $DB_DRIVER \
|
||||
--bc.address $BC_ADDRESS \
|
||||
--bc.port $BC_PORT \
|
||||
--log.level $LOG_LEVEL
|
||||
cat /root/ipld-eth-beacon-config-docker.json | envsubst > /root/ipld-eth-beacon-config.json
|
||||
|
||||
rv=$?
|
||||
echo /root/ipld-eth-beacon-indexer capture ${CAPTURE_MODE} --config /root/ipld-eth-beacon-config.json > /root/ipld-eth-beacon-indexer.output
|
||||
|
||||
if [ $rv != 0 ]; then
|
||||
echo "ipld-ethcl-indexer startup failed"
|
||||
exit 1
|
||||
if [ ${CAPTURE_MODE} == "boot" ]; then
|
||||
/root/ipld-eth-beacon-indexer capture ${CAPTURE_MODE} --config /root/ipld-eth-beacon-config.json > /root/ipld-eth-beacon-indexer.output
|
||||
rv=$?
|
||||
|
||||
if [ $rv != 0 ]; then
|
||||
echo "ipld-eth-beacon-indexer boot failed"
|
||||
else
|
||||
echo "ipld-eth-beacon-indexer boot succeeded"
|
||||
fi
|
||||
|
||||
echo $rv > /root/HEALTH
|
||||
echo $rv
|
||||
cat /root/ipld-eth-beacon-indexer.output
|
||||
|
||||
tail -f /dev/null
|
||||
else
|
||||
exec /root/ipld-eth-beacon-indexer capture ${CAPTURE_MODE} --config /root/ipld-eth-beacon-config.json > /dev/null &
|
||||
tail -F ipld-eth-beacon-indexer.log
|
||||
fi
|
||||
|
||||
tail -f /dev/null
|
||||
@@ -1,54 +1,110 @@
|
||||
module github.com/vulcanize/ipld-ethcl-indexer
|
||||
module github.com/vulcanize/ipld-eth-beacon-indexer
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/jackc/pgconn v1.11.0
|
||||
github.com/onsi/ginkgo/v2 v2.1.3
|
||||
github.com/ipfs/go-ipfs-blockstore v1.2.0
|
||||
github.com/ipfs/go-ipfs-ds-help v1.1.0
|
||||
github.com/jackc/pgconn v1.13.0
|
||||
github.com/multiformats/go-multihash v0.2.1
|
||||
github.com/onsi/ginkgo/v2 v2.1.4
|
||||
github.com/onsi/gomega v1.19.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/protolambda/zrnt v0.28.0
|
||||
github.com/protolambda/ztyp v0.2.2
|
||||
github.com/r3labs/sse/v2 v2.8.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/ethereum/go-ethereum v1.10.25 // indirect
|
||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/holiman/uint256 v1.2.0 // indirect
|
||||
github.com/ipfs/bbloom v0.0.4 // indirect
|
||||
github.com/ipfs/go-block-format v0.0.3 // indirect
|
||||
github.com/ipfs/go-cid v0.3.2 // indirect
|
||||
github.com/ipfs/go-datastore v0.6.0 // indirect
|
||||
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipld-format v0.4.0 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.2.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.10.0 // indirect
|
||||
github.com/jackc/puddle v1.2.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/lib/pq v1.10.4 // indirect
|
||||
github.com/minio/sha256-simd v0.1.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
|
||||
github.com/jackc/pgtype v1.12.0 // indirect
|
||||
github.com/jackc/puddle v1.3.0 // indirect
|
||||
github.com/jbenet/goprocess v0.1.4 // indirect
|
||||
github.com/kilic/bls12-381 v0.1.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||
github.com/lib/pq v1.10.5 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.1.1 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
|
||||
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ferranbt/fastssz v0.0.0-20220303160658-88bb965b6747
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/georgysavva/scany v0.3.0
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/georgysavva/scany v1.2.0
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jackc/pgx/v4 v4.15.0
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jackc/pgx/v4 v4.17.2
|
||||
github.com/jarcoal/httpmock v1.2.0
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
|
||||
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/spf13/afero v1.9.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.11.0
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
|
||||
github.com/spf13/viper v1.13.0
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
golang.org/x/sync v0.0.0-20220907140024-f12130a52804
|
||||
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -39,7 +39,26 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
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/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -53,39 +72,54 @@ github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB0
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
|
||||
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ferranbt/fastssz v0.0.0-20220303160658-88bb965b6747 h1:K2Bt7NSX8x/5MD2RiO7cPLy21dBgnQ84r9uR0QYoHrE=
|
||||
github.com/ferranbt/fastssz v0.0.0-20220303160658-88bb965b6747/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4=
|
||||
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.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/georgysavva/scany v0.3.0 h1:MA1aEqPbnNuiek59gMpNPqQrXXroyFj5jCADlETdxiA=
|
||||
github.com/georgysavva/scany v0.3.0/go.mod h1:q8QyrfXjmBk9iJD00igd4lbkAKEXAH/zIYoZ0z/Wan4=
|
||||
github.com/ethereum/go-ethereum v1.10.25 h1:5dFrKJDnYf8L6/5o42abCE6a9yJm9cs4EJVRyYMr55s=
|
||||
github.com/ethereum/go-ethereum v1.10.25/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/georgysavva/scany v1.2.0 h1:/rO39YZ5HT3lzDp3lNkkE30Mu95ebEtQ7F1/GluLc8Y=
|
||||
github.com/georgysavva/scany v1.2.0/go.mod h1:vGBpL5XRLOocMFFa55pj0P04DrL3I7qKVRL49K6Eu5o=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -114,7 +148,6 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@@ -128,6 +161,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/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.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -141,21 +176,67 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
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/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
|
||||
github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc=
|
||||
github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
|
||||
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
|
||||
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
|
||||
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
|
||||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
|
||||
github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
|
||||
github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
|
||||
github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
|
||||
github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
|
||||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
|
||||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
|
||||
github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw=
|
||||
github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE=
|
||||
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
|
||||
github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q=
|
||||
github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU=
|
||||
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
|
||||
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=
|
||||
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
|
||||
github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM=
|
||||
github.com/ipfs/go-ipld-format v0.4.0 h1:yqJSaJftjmjc9jEOFYlpkwOLVKv68OD27jFLlSghBlQ=
|
||||
github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM=
|
||||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
|
||||
github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
|
||||
github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
|
||||
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
|
||||
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||
github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=
|
||||
github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
@@ -169,8 +250,8 @@ github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpT
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.11.0 h1:HiHArx4yFbwl91X3qqIHtUFoiIfLNJXCQRsnzkiwwaQ=
|
||||
github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
|
||||
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
@@ -187,8 +268,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:
|
||||
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns=
|
||||
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
|
||||
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
@@ -200,8 +281,8 @@ github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkAL
|
||||
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
|
||||
github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38=
|
||||
github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
|
||||
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
@@ -210,40 +291,61 @@ github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
|
||||
github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w=
|
||||
github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw=
|
||||
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
|
||||
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw=
|
||||
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
|
||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc=
|
||||
github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk=
|
||||
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
|
||||
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
|
||||
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
|
||||
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
|
||||
github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
@@ -254,80 +356,161 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
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.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/maxatome/go-testdeep v1.11.0 h1:Tgh5efyCYyJFGUYiT0qxBSIDeXw0F5zSoatlou685kk=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
|
||||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
|
||||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
|
||||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
|
||||
github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI=
|
||||
github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8=
|
||||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
|
||||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108=
|
||||
github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
|
||||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
|
||||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0=
|
||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc h1:zAsgcP8MhzAbhMnB1QQ2O7ZhWYVGYSR2iVcjzQuPV+o=
|
||||
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc/go.mod h1:S8xSOnV3CgpNrWd0GQ/OoQfMtlg2uPRSuTzcSGrzwK8=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e h1:ugvwIKDzqL6ODJciRPMm+9xFQ5AlOYHeMpCOeEuP7LA=
|
||||
github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w=
|
||||
github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M=
|
||||
github.com/protolambda/zrnt v0.28.0 h1:vdEL8JDqJ3wdzgqgh6Fhz1Wr3+AMGbUZ2nqoNt6QVX0=
|
||||
github.com/protolambda/zrnt v0.28.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw=
|
||||
github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY=
|
||||
github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU=
|
||||
github.com/r3labs/sse/v2 v2.8.1 h1:lZH+W4XOLIq88U5MIHOsLec7+R62uhz3bIi2yn0Sg8o=
|
||||
github.com/r3labs/sse/v2 v2.8.1/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
|
||||
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
|
||||
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44=
|
||||
github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk=
|
||||
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
|
||||
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
|
||||
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||
github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
|
||||
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
|
||||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
@@ -339,17 +522,32 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/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-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -361,8 +559,9 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -396,16 +595,19 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -421,7 +623,6 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
@@ -431,9 +632,13 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7 h1:1WGATo9HAhkWMbfyuVU0tEFP88OIkUvwaHFveQPvzCQ=
|
||||
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -443,6 +648,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
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=
|
||||
@@ -453,10 +660,14 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.0.0-20220907140024-f12130a52804 h1:0SH2R3f1b1VmIMG7BXbEZCBUu2dKmHschSmjqGUrW8A=
|
||||
golang.org/x/sync v0.0.0-20220907140024-f12130a52804/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -469,13 +680,11 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -489,24 +698,38 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd h1:AZeIEzg+8RCELJYq8w+ODLVxFgLMMigSwO/ffKPEd9U=
|
||||
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -520,6 +743,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -562,6 +786,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
@@ -569,10 +794,11 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -669,27 +895,33 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
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.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
|
||||
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
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/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/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.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
|
||||
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
@@ -700,6 +932,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
||||
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
+113
-52
@@ -1,53 +1,37 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package boot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/beaconclient"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/database/sql/postgres"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql/postgres"
|
||||
)
|
||||
|
||||
var (
|
||||
maxRetry = 5 // Max times to try to connect to the DB or BC at boot.
|
||||
retryInterval = 30 // The time to wait between each try.
|
||||
DB sql.Database = &postgres.DB{}
|
||||
BC *beaconclient.BeaconClient = &beaconclient.BeaconClient{}
|
||||
DB sql.Database = &postgres.DB{}
|
||||
BC *beaconclient.BeaconClient = &beaconclient.BeaconClient{}
|
||||
)
|
||||
|
||||
// A simple wrapper to create a DB object to use.
|
||||
func SetupPostgresDb(dbHostname string, dbPort int, dbName string, dbUsername string, dbPassword string, driverName string) (sql.Database, error) {
|
||||
log.Debug("Resolving Driver Type")
|
||||
DbDriver, err := postgres.ResolveDriverType(driverName)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"driver_name_provided": driverName,
|
||||
}).Error("Can't resolve driver type")
|
||||
}
|
||||
log.Info("Using Driver:", DbDriver)
|
||||
|
||||
postgresConfig := postgres.Config{
|
||||
Hostname: dbHostname,
|
||||
Port: dbPort,
|
||||
DatabaseName: dbName,
|
||||
Username: dbUsername,
|
||||
Password: dbPassword,
|
||||
Driver: DbDriver,
|
||||
}
|
||||
DB, err = postgres.NewPostgresDB(postgresConfig)
|
||||
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to connect to the DB")
|
||||
return nil, err
|
||||
}
|
||||
return DB, err
|
||||
|
||||
}
|
||||
|
||||
// This function will perform some boot operations. If any steps fail, the application will fail to start.
|
||||
// Keep in mind that the DB connection can be lost later in the lifecycle of the application or
|
||||
// it might not be able to connect to the beacon client.
|
||||
@@ -56,38 +40,115 @@ func SetupPostgresDb(dbHostname string, dbPort int, dbName string, dbUsername st
|
||||
//
|
||||
// 2. Connect to the database.
|
||||
//
|
||||
func BootApplication(ctx context.Context, dbHostname string, dbPort int, dbName string, dbUsername string, dbPassword string, driverName string, bcAddress string, bcPort int, bcConnectionProtocol string) (*beaconclient.BeaconClient, sql.Database, error) {
|
||||
// 3. Make sure the node is synced, unless disregardSync is true.
|
||||
func BootApplication(ctx context.Context, dbHostname string, dbPort int, dbName string, dbUsername string, dbPassword string, driverName string,
|
||||
bcAddress string, bcPort int, bcConnectionProtocol string, bcKgTableIncrement int, disregardSync bool, uniqueNodeIdentifier int, checkDb bool, performBeaconBlockProcessing bool, performBeaconStateProcessing bool) (*beaconclient.BeaconClient, sql.Database, error) {
|
||||
log.Info("Booting the Application")
|
||||
|
||||
log.Debug("Creating the Beacon Client")
|
||||
BC = beaconclient.CreateBeaconClient(ctx, bcConnectionProtocol, bcAddress, bcPort)
|
||||
Bc, err := beaconclient.CreateBeaconClient(ctx, bcConnectionProtocol, bcAddress, bcPort, bcKgTableIncrement, uniqueNodeIdentifier, checkDb, performBeaconBlockProcessing, performBeaconStateProcessing)
|
||||
if err != nil {
|
||||
return Bc, nil, err
|
||||
}
|
||||
|
||||
log.Debug("Checking Beacon Client")
|
||||
err := BC.CheckBeaconClient()
|
||||
err = Bc.CheckBeaconClient()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Debug("Setting up DB connection")
|
||||
DB, err := SetupPostgresDb(dbHostname, dbPort, dbName, dbUsername, dbPassword, driverName)
|
||||
DB, err = postgres.SetupPostgresDb(dbHostname, dbPort, dbName, dbUsername, dbPassword, driverName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return BC, DB, nil
|
||||
|
||||
Bc.Db = DB
|
||||
|
||||
var status bool
|
||||
if !disregardSync {
|
||||
status, err = Bc.CheckHeadSync()
|
||||
if err != nil {
|
||||
log.Error("Unable to get the nodes sync status")
|
||||
return Bc, DB, err
|
||||
}
|
||||
if status {
|
||||
log.Error("The node is still syncing..")
|
||||
err = fmt.Errorf("The node is still syncing.")
|
||||
return Bc, DB, err
|
||||
}
|
||||
} else {
|
||||
log.Warn("We are not checking to see if the node has synced to head.")
|
||||
}
|
||||
return Bc, DB, nil
|
||||
}
|
||||
|
||||
// Add retry logic to ensure that we are give the Beacon Client and the DB time to start.
|
||||
func BootApplicationWithRetry(ctx context.Context, dbHostname string, dbPort int, dbName string, dbUsername string, dbPassword string, driverName string, bcAddress string, bcPort int, bcConnectionProtocol string) (*beaconclient.BeaconClient, sql.Database, error) {
|
||||
func BootApplicationWithRetry(ctx context.Context, dbHostname string, dbPort int, dbName string, dbUsername string, dbPassword string, driverName string,
|
||||
bcAddress string, bcPort int, bcConnectionProtocol string, bcType string, bcRetryInterval int, bcMaxRetry int, bcKgTableIncrement int,
|
||||
startUpMode string, disregardSync bool, uniqueNodeIdentifier int, checkDb bool, performBeaconBlockProcessing bool, performBeaconStateProcessing bool) (*beaconclient.BeaconClient, sql.Database, error) {
|
||||
var err error
|
||||
for i := 0; i < maxRetry; i++ {
|
||||
BC, DB, err = BootApplication(ctx, dbHostname, dbPort, dbName, dbUsername, dbPassword, driverName, bcAddress, bcPort, bcConnectionProtocol)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"retryNumber": i,
|
||||
}).Warn("Unable to boot application. Going to try again")
|
||||
time.Sleep(time.Duration(retryInterval) * time.Second)
|
||||
|
||||
if bcMaxRetry < 0 {
|
||||
i := 0
|
||||
for {
|
||||
BC, DB, err = BootApplication(ctx, dbHostname, dbPort, dbName, dbUsername, dbPassword, driverName,
|
||||
bcAddress, bcPort, bcConnectionProtocol, bcKgTableIncrement, disregardSync, uniqueNodeIdentifier, checkDb,
|
||||
performBeaconBlockProcessing, performBeaconStateProcessing)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"retryNumber": i,
|
||||
"err": err,
|
||||
}).Warn("Unable to boot application. Going to try again")
|
||||
time.Sleep(time.Duration(bcRetryInterval) * time.Second)
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < bcMaxRetry; i++ {
|
||||
BC, DB, err = BootApplication(ctx, dbHostname, dbPort, dbName, dbUsername, dbPassword, driverName,
|
||||
bcAddress, bcPort, bcConnectionProtocol, bcKgTableIncrement, disregardSync, uniqueNodeIdentifier, checkDb,
|
||||
performBeaconBlockProcessing, performBeaconStateProcessing)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"retryNumber": i,
|
||||
"err": err,
|
||||
}).Warn("Unable to boot application. Going to try again")
|
||||
time.Sleep(time.Duration(bcRetryInterval) * time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
switch strings.ToLower(startUpMode) {
|
||||
case "head":
|
||||
BC.PerformHeadTracking = true
|
||||
case "historic":
|
||||
log.Debug("Performing additional boot steps for historical processing")
|
||||
BC.PerformHistoricalProcessing = true
|
||||
// This field is not currently used.
|
||||
// The idea is, that if we are doing historially processing and we get a slot
|
||||
// greater than this slot, then we would rerun this function.
|
||||
// this would ensure that we have the slots necessary for processing
|
||||
// within the beacon server.
|
||||
|
||||
// We can implement this feature if we notice any errors.
|
||||
headSlot, err := BC.GetLatestSlotInBeaconServer(bcType)
|
||||
if err != nil {
|
||||
return BC, DB, err
|
||||
}
|
||||
BC.UpdateLatestSlotInBeaconServer(int64(headSlot))
|
||||
// Add another switch case for bcType if its ever needed.
|
||||
case "boot":
|
||||
log.Debug("Running application in boot mode.")
|
||||
default:
|
||||
log.WithFields(log.Fields{
|
||||
"startUpMode": startUpMode,
|
||||
}).Error("The startUpMode provided is not handled.")
|
||||
}
|
||||
|
||||
return BC, DB, err
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package boot_test
|
||||
|
||||
import (
|
||||
|
||||
+63
-19
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package boot_test
|
||||
|
||||
import (
|
||||
@@ -5,45 +20,74 @@ import (
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/internal/boot"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/boot"
|
||||
)
|
||||
|
||||
var _ = Describe("Boot", func() {
|
||||
var (
|
||||
dbAddress string = "localhost"
|
||||
dbPort int = 8077
|
||||
dbName string = "vulcanize_testing"
|
||||
dbUsername string = "vdbm"
|
||||
dbPassword string = "password"
|
||||
dbDriver string = "PGX"
|
||||
bcAddress string = "localhost"
|
||||
bcPort int = 5052
|
||||
bcConnectionProtocol string = "http"
|
||||
dbAddress string = "localhost"
|
||||
dbPort int = 8076
|
||||
dbName string = "vulcanize_testing"
|
||||
dbUsername string = "vdbm"
|
||||
dbPassword string = "password"
|
||||
dbDriver string = "PGX"
|
||||
bcAddress string = "localhost"
|
||||
bcPort int = 5052
|
||||
bcConnectionProtocol string = "http"
|
||||
bcType string = "lighthouse"
|
||||
bcBootRetryInterval int = 1
|
||||
bcBootMaxRetry int = 5
|
||||
bcKgTableIncrement int = 10
|
||||
bcUniqueIdentifier int = 100
|
||||
bcCheckDb bool = false
|
||||
bcProcessBeaconBlocks bool = true
|
||||
bcProcessBeaconState bool = true
|
||||
)
|
||||
Describe("Booting the application", Label("integration"), func() {
|
||||
Context("When the DB and BC are both up and running", func() {
|
||||
Context("When the DB and BC are both up and running, we skip checking for a synced head, and we are processing head", func() {
|
||||
It("Should connect successfully", func() {
|
||||
_, db, err := boot.BootApplicationWithRetry(context.Background(), dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol)
|
||||
_, db, err := boot.BootApplicationWithRetry(context.Background(), dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol, bcType, bcBootRetryInterval, bcBootMaxRetry, bcKgTableIncrement, "head", true, bcUniqueIdentifier, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
defer db.Close()
|
||||
Expect(err).To(BeNil())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("When the DB and BC are both up and running, we skip checking for a synced head, and we are processing historic ", func() {
|
||||
It("Should connect successfully", func() {
|
||||
_, db, err := boot.BootApplicationWithRetry(context.Background(), dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol, bcType, bcBootRetryInterval, bcBootMaxRetry, bcKgTableIncrement, "historic", true, bcUniqueIdentifier, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
defer db.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("When the DB and BC are both up and running, and we check for a synced head", func() {
|
||||
It("Should not connect successfully", func() {
|
||||
_, db, err := boot.BootApplicationWithRetry(context.Background(), dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol, bcType, bcBootRetryInterval, bcBootMaxRetry, bcKgTableIncrement, "head", false, bcUniqueIdentifier, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
defer db.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("When the DB and BC are both up and running, we skip checking for a synced head, but the unique identifier is 0", func() {
|
||||
It("Should not connect successfully", func() {
|
||||
_, db, err := boot.BootApplicationWithRetry(context.Background(), dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol, bcType, bcBootRetryInterval, bcBootMaxRetry, bcKgTableIncrement, "head", false, 0, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
defer db.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("When the DB is running but not the BC", func() {
|
||||
It("Should not connect successfully", func() {
|
||||
_, _, err := boot.BootApplication(context.Background(), dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, "hi", 100, bcConnectionProtocol)
|
||||
Expect(err).ToNot(BeNil())
|
||||
_, _, err := boot.BootApplication(context.Background(), dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, "hi", 100, bcConnectionProtocol, bcKgTableIncrement, true, bcUniqueIdentifier, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("When the BC is running but not the DB", func() {
|
||||
It("Should not connect successfully", func() {
|
||||
_, _, err := boot.BootApplication(context.Background(), "hi", 10, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol)
|
||||
Expect(err).ToNot(BeNil())
|
||||
_, _, err := boot.BootApplication(context.Background(), "hi", 10, dbName, dbUsername, dbPassword, dbDriver, bcAddress, bcPort, bcConnectionProtocol, bcKgTableIncrement, true, bcUniqueIdentifier, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("When neither the BC or DB are running", func() {
|
||||
It("Should not connect successfully", func() {
|
||||
_, _, err := boot.BootApplication(context.Background(), "hi", 10, dbName, dbUsername, dbPassword, dbDriver, "hi", 100, bcConnectionProtocol)
|
||||
Expect(err).ToNot(BeNil())
|
||||
_, _, err := boot.BootApplication(context.Background(), "hi", 10, dbName, dbUsername, dbPassword, dbDriver, "hi", 100, bcConnectionProtocol, bcKgTableIncrement, true, bcUniqueIdentifier, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+100
-20
@@ -1,39 +1,119 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package shutdown
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/beaconclient"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/gracefulshutdown"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/gracefulshutdown"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// Shutdown all the internal services for the application.
|
||||
func ShutdownServices(ctx context.Context, waitTime time.Duration, DB sql.Database, BC *beaconclient.BeaconClient) {
|
||||
successCh, errCh := gracefulshutdown.Shutdown(ctx, waitTime, map[string]gracefulshutdown.Operation{
|
||||
"database": func(ctx context.Context) error {
|
||||
err := DB.Close()
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to close the DB")
|
||||
}
|
||||
return err
|
||||
},
|
||||
func ShutdownServices(ctx context.Context, notifierCh chan os.Signal, waitTime time.Duration, DB sql.Database, BC *beaconclient.BeaconClient, shutdownOperations map[string]gracefulshutdown.Operation) error {
|
||||
//successCh, errCh := gracefulshutdown.Shutdown(ctx, notifierCh, waitTime, )
|
||||
successCh, errCh := gracefulshutdown.Shutdown(ctx, notifierCh, waitTime, shutdownOperations)
|
||||
|
||||
select {
|
||||
case <-successCh:
|
||||
return nil
|
||||
case err := <-errCh:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper function for shutting down the head tracking process.
|
||||
func ShutdownHeadTracking(ctx context.Context, kgCancel context.CancelFunc, notifierCh chan os.Signal, waitTime time.Duration, DB sql.Database, BC *beaconclient.BeaconClient) error {
|
||||
return ShutdownServices(ctx, notifierCh, waitTime, DB, BC, map[string]gracefulshutdown.Operation{
|
||||
// Combining DB shutdown with BC because BC needs DB open to cleanly shutdown.
|
||||
"beaconClient": func(ctx context.Context) error {
|
||||
defer DB.Close()
|
||||
err := BC.StopHeadTracking()
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to trigger shutdown of head tracking")
|
||||
}
|
||||
if BC.KnownGapsProcess != (beaconclient.KnownGapsProcessing{}) {
|
||||
err = BC.StopKnownGapsProcessing(kgCancel)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to stop processing known gaps")
|
||||
}
|
||||
}
|
||||
return err
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Wrapper function for shutting down the head tracking process.
|
||||
func ShutdownHistoricProcessing(ctx context.Context, kgCancel, hpCancel context.CancelFunc, notifierCh chan os.Signal, waitTime time.Duration, DB sql.Database, BC *beaconclient.BeaconClient) error {
|
||||
return ShutdownServices(ctx, notifierCh, waitTime, DB, BC, map[string]gracefulshutdown.Operation{
|
||||
// Combining DB shutdown with BC because BC needs DB open to cleanly shutdown.
|
||||
"beaconClient": func(ctx context.Context) error {
|
||||
defer DB.Close()
|
||||
err := BC.StopHistoric(hpCancel)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to stop processing historic")
|
||||
}
|
||||
if BC.KnownGapsProcess != (beaconclient.KnownGapsProcessing{}) {
|
||||
err = BC.StopKnownGapsProcessing(kgCancel)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to stop processing known gaps")
|
||||
}
|
||||
}
|
||||
return err
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Shutdown the head and historical processing
|
||||
func ShutdownFull(ctx context.Context, kgCancel, hpCancel context.CancelFunc, notifierCh chan os.Signal, waitTime time.Duration, DB sql.Database, BC *beaconclient.BeaconClient) error {
|
||||
return ShutdownServices(ctx, notifierCh, waitTime, DB, BC, map[string]gracefulshutdown.Operation{
|
||||
// Combining DB shutdown with BC because BC needs DB open to cleanly shutdown.
|
||||
"beaconClient": func(ctx context.Context) error {
|
||||
defer DB.Close()
|
||||
err := BC.StopHistoric(hpCancel)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to stop processing historic")
|
||||
}
|
||||
if BC.KnownGapsProcess != (beaconclient.KnownGapsProcessing{}) {
|
||||
err = BC.StopKnownGapsProcessing(kgCancel)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to stop processing known gaps")
|
||||
}
|
||||
}
|
||||
err = BC.StopHeadTracking()
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to trigger shutdown of head tracking")
|
||||
}
|
||||
|
||||
return err
|
||||
},
|
||||
})
|
||||
|
||||
select {
|
||||
case _ = <-successCh:
|
||||
log.Info("Gracefully Shutdown ipld-ethcl-indexer!")
|
||||
case err := <-errCh:
|
||||
loghelper.LogError(err).Error("Ungracefully Shutdown ipld-ethcl-indexer!")
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper function for shutting down the application in boot mode.
|
||||
func ShutdownBoot(ctx context.Context, notifierCh chan os.Signal, waitTime time.Duration, DB sql.Database, BC *beaconclient.BeaconClient) error {
|
||||
return ShutdownServices(ctx, notifierCh, waitTime, DB, BC, map[string]gracefulshutdown.Operation{
|
||||
// Combining DB shutdown with BC because BC needs DB open to cleanly shutdown.
|
||||
"Database": func(ctx context.Context) error {
|
||||
return DB.Close()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package shutdown_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestShutdown(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Shutdown Suite")
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//go:build !race
|
||||
// +build !race
|
||||
|
||||
package shutdown_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/r3labs/sse/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/boot"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/internal/shutdown"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/gracefulshutdown"
|
||||
)
|
||||
|
||||
var (
|
||||
dbAddress string = "localhost"
|
||||
dbPort int = 8076
|
||||
dbName string = "vulcanize_testing"
|
||||
dbUsername string = "vdbm"
|
||||
dbPassword string = "password"
|
||||
dbDriver string = "PGX"
|
||||
bcAddress string = "localhost"
|
||||
bcPort int = 5052
|
||||
bcConnectionProtocol string = "http"
|
||||
bcType string = "lighthouse"
|
||||
bcBootRetryInterval int = 1
|
||||
bcBootMaxRetry int = 5
|
||||
bcKgTableIncrement int = 10
|
||||
bcUniqueIdentifier int = 100
|
||||
bcCheckDb bool = false
|
||||
bcProcessBeaconBlocks bool = true
|
||||
bcProcessBeaconState bool = true
|
||||
maxWaitSecondsShutdown time.Duration = time.Duration(1) * time.Second
|
||||
DB sql.Database
|
||||
BC *beaconclient.BeaconClient
|
||||
err error
|
||||
ctx context.Context
|
||||
notifierCh chan os.Signal
|
||||
)
|
||||
|
||||
var _ = Describe("Shutdown", func() {
|
||||
BeforeEach(func() {
|
||||
ctx = context.Background()
|
||||
BC, DB, err = boot.BootApplicationWithRetry(ctx, dbAddress, dbPort, dbName, dbUsername, dbPassword, dbDriver, bcAddress,
|
||||
bcPort, bcConnectionProtocol, bcType, bcBootRetryInterval, bcBootMaxRetry, bcKgTableIncrement, "head", true, bcUniqueIdentifier, bcCheckDb, bcProcessBeaconBlocks, bcProcessBeaconState)
|
||||
notifierCh = make(chan os.Signal, 1)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
Describe("Run Shutdown Function for head tracking,", Label("integration"), func() {
|
||||
Context("When Channels are empty,", func() {
|
||||
It("Should Shutdown Successfully.", func() {
|
||||
go func() {
|
||||
_, cancel := context.WithCancel(context.Background())
|
||||
log.Debug("Starting shutdown chan")
|
||||
err = shutdown.ShutdownHeadTracking(ctx, cancel, notifierCh, maxWaitSecondsShutdown, DB, BC)
|
||||
log.Debug("We have completed the shutdown...")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}()
|
||||
})
|
||||
})
|
||||
Context("When the Channels are not empty,", func() {
|
||||
It("Should try to clear them and shutdown gracefully.", func() {
|
||||
shutdownCh := make(chan bool)
|
||||
//log.SetLevel(log.DebugLevel)
|
||||
go func() {
|
||||
_, cancel := context.WithCancel(context.Background())
|
||||
log.Debug("Starting shutdown chan")
|
||||
err = shutdown.ShutdownHeadTracking(ctx, cancel, notifierCh, maxWaitSecondsShutdown, DB, BC)
|
||||
log.Debug("We have completed the shutdown...")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
shutdownCh <- true
|
||||
}()
|
||||
|
||||
messageAddCh := make(chan bool)
|
||||
go func() {
|
||||
log.Debug("Adding messages to Channels")
|
||||
BC.HeadTracking.MessagesCh <- &sse.Event{}
|
||||
//BC.FinalizationTracking.MessagesCh <- &sse.Event{}
|
||||
BC.ReOrgTracking.MessagesCh <- &sse.Event{}
|
||||
log.Debug("Message adding complete")
|
||||
messageAddCh <- true
|
||||
}()
|
||||
|
||||
go func() {
|
||||
<-messageAddCh
|
||||
log.Debug("Calling SIGTERM")
|
||||
notifierCh <- syscall.SIGTERM
|
||||
log.Debug("Reading messages from channel")
|
||||
<-BC.HeadTracking.MessagesCh
|
||||
//<-BC.FinalizationTracking.MessagesCh
|
||||
<-BC.ReOrgTracking.MessagesCh
|
||||
}()
|
||||
<-shutdownCh
|
||||
|
||||
})
|
||||
It("Should try to clear them, if it can't, shutdown within a given time frame.", func() {
|
||||
shutdownCh := make(chan bool)
|
||||
//log.SetLevel(log.DebugLevel)
|
||||
go func() {
|
||||
log.Debug("Starting shutdown chan")
|
||||
_, cancel := context.WithCancel(context.Background())
|
||||
err = shutdown.ShutdownHeadTracking(ctx, cancel, notifierCh, maxWaitSecondsShutdown, DB, BC)
|
||||
log.Debug("We have completed the shutdown...")
|
||||
Expect(err).To(MatchError(gracefulshutdown.TimeoutErr(maxWaitSecondsShutdown.String())))
|
||||
shutdownCh <- true
|
||||
}()
|
||||
|
||||
go func() {
|
||||
log.Debug("Adding messages to Channels")
|
||||
BC.HeadTracking.MessagesCh <- &sse.Event{}
|
||||
//BC.FinalizationTracking.MessagesCh <- &sse.Event{}
|
||||
BC.ReOrgTracking.MessagesCh <- &sse.Event{}
|
||||
log.Debug("Message adding complete")
|
||||
log.Debug("Calling SIGHUP")
|
||||
notifierCh <- syscall.SIGTERM
|
||||
}()
|
||||
|
||||
<-shutdownCh
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"db": {
|
||||
"address": "${POSTGRES_HOST}",
|
||||
"password": "${POSTGRES_PASSWORD}",
|
||||
"port": ${POSTGRES_PORT},
|
||||
"username": "${POSTGRES_USER}",
|
||||
"name": "${POSTGRES_DB}",
|
||||
"driver": "PGX"
|
||||
},
|
||||
"bc": {
|
||||
"address": "${LIGHTHOUSE_HOST}",
|
||||
"port": ${LIGHTHOUSE_PORT},
|
||||
"type": "lighthouse",
|
||||
"bootRetryInterval": 30,
|
||||
"bootMaxRetry": 5,
|
||||
"maxHistoricProcessWorker": ${BC_MAX_HISTORIC_PROCESS_WORKER},
|
||||
"connectionProtocol": "${LIGHTHOUSE_PROTOCOL}",
|
||||
"uniqueNodeIdentifier": ${BC_UNIQUE_NODE_IDENTIFIER},
|
||||
"checkDb": ${BC_CHECK_DB},
|
||||
"performBeaconStateProcessing": ${BC_BEACON_STATE_PROCESSING_ENABLED},
|
||||
"performBeaconBlockProcessing": ${BC_BEACON_BLOCK_PROCESSING_ENABLED},
|
||||
"minimumSlot": ${BC_MINIMUM_SLOT}
|
||||
},
|
||||
"t": {
|
||||
"skipSync": true
|
||||
},
|
||||
"log": {
|
||||
"level": "${LOG_LEVEL}",
|
||||
"output": true,
|
||||
"file": "./ipld-eth-beacon-indexer.log",
|
||||
"format": "json"
|
||||
},
|
||||
"kg": {
|
||||
"increment": ${KG_INCREMENT},
|
||||
"processKnownGaps": ${KG_PROCESS_KNOWN_GAPS_ENABLED},
|
||||
"maxKnownGapsWorker": ${KG_MAX_KNOWN_GAPS_WORKER},
|
||||
"minimumSlot": ${KG_MINIMUM_SLOT}
|
||||
},
|
||||
"pm": {
|
||||
"address": "${PROM_HOST}",
|
||||
"port": ${PROM_PORT},
|
||||
"metrics": ${PROM_METRICS_ENABLED}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,25 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
/*
|
||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package main
|
||||
|
||||
import "github.com/vulcanize/ipld-ethcl-indexer/cmd"
|
||||
import "github.com/vulcanize/ipld-eth-beacon-indexer/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
|
||||
@@ -1,31 +1,77 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/r3labs/sse"
|
||||
"github.com/r3labs/sse/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TODO: Use prysms config values instead of hardcoding them here.
|
||||
var (
|
||||
bcHealthEndpoint = "/eth/v1/node/health" // Endpoint used for the healthcheck
|
||||
bcHeadTopicEndpoint = "/eth/v1/events?topics=head" // Endpoint used to subscribe to the head of the chain
|
||||
bcReorgTopicEndpoint = "/eth/v1/events?topics=chain_reorg" // Endpoint used to subscribe to the head of the chain
|
||||
bcFinalizedTopicEndpoint = "/eth/v1/events?topics=finalized_checkpoint" // Endpoint used to subscribe to the head of the chain
|
||||
bcBlockQueryEndpoint = "/eth/v2/beacon/blocks/" // Endpoint to query individual Blocks
|
||||
bcStateQueryEndpoint = "/eth/v2/debug/beacon/states/" // Endpoint to query individual States
|
||||
bcHealthEndpoint = "/eth/v1/node/health" // Endpoint used for the healthcheck
|
||||
BcHeadTopicEndpoint = "/eth/v1/events?topics=head" // Endpoint used to subscribe to the head of the chain
|
||||
bcReorgTopicEndpoint = "/eth/v1/events?topics=chain_reorg" // Endpoint used to subscribe to the head of the chain
|
||||
BcBlockQueryEndpoint = "/eth/v2/beacon/blocks/" // Endpoint to query individual Blocks
|
||||
BcStateQueryEndpoint = "/eth/v2/debug/beacon/states/" // Endpoint to query individual States
|
||||
BcSyncStatusEndpoint = "/eth/v1/node/syncing" // The endpoint to check to see if the beacon server is still trying to sync to head.
|
||||
LhDbInfoEndpoint = "/lighthouse/database/info" // The endpoint for the LIGHTHOUSE server to get the database information.
|
||||
BcBlockRootEndpoint = func(slot string) string {
|
||||
return "/eth/v1/beacon/blocks/" + slot + "/root"
|
||||
}
|
||||
bcSlotsPerEpoch uint64 = 32 // Number of slots in a single Epoch
|
||||
//bcSlotPerHistoricalVector = 8192 // The number of slots in a historic vector.
|
||||
//bcFinalizedTopicEndpoint = "/eth/v1/events?topics=finalized_checkpoint" // Endpoint used to subscribe to the head of the chain
|
||||
)
|
||||
|
||||
// A struct that capture the Beacon Server that the Beacon Client will be interacting with and querying.
|
||||
type BeaconClient struct {
|
||||
Context context.Context // A context generic context with multiple uses.
|
||||
ServerEndpoint string // What is the endpoint of the beacon server.
|
||||
PerformHeadTracking bool // Should we track head?
|
||||
PerformHistoricalProcessing bool // Should we perform historical processing?
|
||||
HeadTracking *SseEvents[Head] // Track the head block
|
||||
ReOrgTracking *SseEvents[ChainReorg] // Track all Reorgs
|
||||
FinalizationTracking *SseEvents[FinalizedCheckpoint] // Track all finalization checkpoints
|
||||
Context context.Context // A context generic context with multiple uses.
|
||||
ServerEndpoint string // What is the endpoint of the beacon server.
|
||||
Db sql.Database // Database object used for reads and writes.
|
||||
Metrics *BeaconClientMetrics // An object used to keep track of certain BeaconClient Metrics.
|
||||
KnownGapTableIncrement int // The max number of slots within a single known_gaps table entry.
|
||||
UniqueNodeIdentifier int // The unique identifier within the cluster of this individual node.
|
||||
KnownGapsProcess KnownGapsProcessing // object keeping track of knowngaps processing
|
||||
CheckDb bool // Should we check the DB to see if the slot exists before processing it?
|
||||
PerformBeaconStateProcessing bool // Should we process BeaconStates?
|
||||
PerformBeaconBlockProcessing bool // Should we process BeaconBlocks?
|
||||
|
||||
// Used for Head Tracking
|
||||
|
||||
PerformHeadTracking bool // Should we track head?
|
||||
StartingSlot Slot // If we're performing head tracking. What is the first slot we processed.
|
||||
PreviousSlot Slot // Whats the previous slot we processed
|
||||
PreviousBlockRoot string // Whats the previous block root, used to check the next blocks parent.
|
||||
HeadTracking *SseEvents[Head] // Track the head block
|
||||
ReOrgTracking *SseEvents[ChainReorg] // Track all Reorgs
|
||||
//FinalizationTracking *SseEvents[FinalizedCheckpoint] // Track all finalization checkpoints
|
||||
|
||||
// Used for Historical Processing
|
||||
|
||||
// The latest available slot within the Beacon Server. We can't query any slot greater than this.
|
||||
// This value is lazily updated. Therefore at times it will be outdated.
|
||||
LatestSlotInBeaconServer int64
|
||||
PerformHistoricalProcessing bool // Should we perform historical processing?
|
||||
HistoricalProcess HistoricProcessing // object keeping track of historical processing
|
||||
}
|
||||
|
||||
// A struct to keep track of relevant the head event topic.
|
||||
@@ -34,7 +80,7 @@ type SseEvents[P ProcessedEvents] struct {
|
||||
MessagesCh chan *sse.Event // Contains all the messages from the SSE Channel
|
||||
ErrorCh chan *SseError // Contains any errors while SSE streaming occurred
|
||||
ProcessCh chan *P // Used to capture processed data in its proper struct.
|
||||
SseClient *sse.Client // sse.Client object that is used to interact with the SSE stream
|
||||
sseClient *sse.Client // sse.Client object that is used to interact with the SSE stream
|
||||
}
|
||||
|
||||
// An object to capture any errors when turning an SSE message to JSON.
|
||||
@@ -44,16 +90,33 @@ type SseError struct {
|
||||
}
|
||||
|
||||
// A Function to create the BeaconClient.
|
||||
func CreateBeaconClient(ctx context.Context, connectionProtocol string, bcAddress string, bcPort int) *BeaconClient {
|
||||
func CreateBeaconClient(ctx context.Context, connectionProtocol string, bcAddress string, bcPort int,
|
||||
bcKgTableIncrement int, uniqueNodeIdentifier int, checkDb bool, performBeaconBlockProcessing bool, performBeaconStateProcessing bool) (*BeaconClient, error) {
|
||||
if uniqueNodeIdentifier == 0 {
|
||||
uniqueNodeIdentifier := rand.Int()
|
||||
log.WithField("randomUniqueNodeIdentifier", uniqueNodeIdentifier).Warn("No uniqueNodeIdentifier provided, we are going to use a randomly generated one.")
|
||||
}
|
||||
|
||||
metrics, err := CreateBeaconClientMetrics()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endpoint := fmt.Sprintf("%s://%s:%d", connectionProtocol, bcAddress, bcPort)
|
||||
log.Info("Creating the BeaconClient")
|
||||
return &BeaconClient{
|
||||
Context: ctx,
|
||||
ServerEndpoint: endpoint,
|
||||
HeadTracking: createSseEvent[Head](endpoint, bcHeadTopicEndpoint),
|
||||
ReOrgTracking: createSseEvent[ChainReorg](endpoint, bcReorgTopicEndpoint),
|
||||
FinalizationTracking: createSseEvent[FinalizedCheckpoint](endpoint, bcFinalizedTopicEndpoint),
|
||||
}
|
||||
Context: ctx,
|
||||
ServerEndpoint: endpoint,
|
||||
KnownGapTableIncrement: bcKgTableIncrement,
|
||||
HeadTracking: createSseEvent[Head](endpoint, BcHeadTopicEndpoint),
|
||||
ReOrgTracking: createSseEvent[ChainReorg](endpoint, bcReorgTopicEndpoint),
|
||||
Metrics: metrics,
|
||||
UniqueNodeIdentifier: uniqueNodeIdentifier,
|
||||
CheckDb: checkDb,
|
||||
PerformBeaconBlockProcessing: performBeaconBlockProcessing,
|
||||
PerformBeaconStateProcessing: performBeaconStateProcessing,
|
||||
//FinalizationTracking: createSseEvent[FinalizedCheckpoint](endpoint, bcFinalizedTopicEndpoint),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Create all the channels to handle a SSE events
|
||||
@@ -61,13 +124,43 @@ func createSseEvent[P ProcessedEvents](baseEndpoint string, path string) *SseEve
|
||||
endpoint := baseEndpoint + path
|
||||
sseEvents := &SseEvents[P]{
|
||||
Endpoint: endpoint,
|
||||
MessagesCh: make(chan *sse.Event),
|
||||
MessagesCh: make(chan *sse.Event, 1),
|
||||
ErrorCh: make(chan *SseError),
|
||||
ProcessCh: make(chan *P),
|
||||
SseClient: func(endpoint string) *sse.Client {
|
||||
log.WithFields(log.Fields{"endpoint": endpoint}).Info("Creating SSE client")
|
||||
return sse.NewClient(endpoint)
|
||||
}(endpoint),
|
||||
}
|
||||
return sseEvents
|
||||
}
|
||||
|
||||
func (se *SseEvents[P]) Connect() error {
|
||||
if nil == se.sseClient {
|
||||
se.initClient()
|
||||
}
|
||||
return se.sseClient.SubscribeChanRaw(se.MessagesCh)
|
||||
}
|
||||
|
||||
func (se *SseEvents[P]) Disconnect() {
|
||||
if nil == se.sseClient {
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{"endpoint": se.Endpoint}).Info("Disconnecting and destroying SSE client")
|
||||
se.sseClient.Unsubscribe(se.MessagesCh)
|
||||
se.sseClient.Connection.CloseIdleConnections()
|
||||
se.sseClient = nil
|
||||
}
|
||||
|
||||
func (se *SseEvents[P]) initClient() {
|
||||
if nil != se.sseClient {
|
||||
se.Disconnect()
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{"endpoint": se.Endpoint}).Info("Creating SSE client")
|
||||
client := sse.NewClient(se.Endpoint)
|
||||
client.ReconnectNotify = func(err error, duration time.Duration) {
|
||||
log.WithFields(log.Fields{"endpoint": se.Endpoint}).Debug("Reconnecting SSE client")
|
||||
}
|
||||
client.OnDisconnect(func(c *sse.Client) {
|
||||
log.WithFields(log.Fields{"endpoint": se.Endpoint}).Debug("SSE client disconnected")
|
||||
})
|
||||
se.sseClient = client
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This file will call all the functions to start and stop capturing the head of the beacon chain.
|
||||
|
||||
package beaconclient
|
||||
@@ -5,48 +20,16 @@ package beaconclient
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ferranbt/fastssz/spectests"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// This function will perform all the heavy lifting for tracking the head of the chain.
|
||||
func (bc *BeaconClient) CaptureHead() {
|
||||
log.Info("We are tracking the head of the chain.")
|
||||
bc.tempHelper()
|
||||
// go bc.handleHead()
|
||||
// go bc.handleFinalizedCheckpoint()
|
||||
// go bc.handleReorgs()
|
||||
// bc.captureEventTopic()
|
||||
}
|
||||
|
||||
// A temporary helper function to see the output of beacon block and states.
|
||||
func (bc *BeaconClient) tempHelper() {
|
||||
slot := "3200"
|
||||
blockEndpoint := bc.ServerEndpoint + bcBlockQueryEndpoint + slot
|
||||
stateEndpoint := bc.ServerEndpoint + bcStateQueryEndpoint + slot
|
||||
// Query
|
||||
log.Info("Get")
|
||||
blockSsz, _ := querySsz(blockEndpoint, slot)
|
||||
stateSsz, _ := querySsz(stateEndpoint, slot)
|
||||
// Transform
|
||||
log.Info("Tranform")
|
||||
stateObj := new(spectests.BeaconState)
|
||||
err := stateObj.UnmarshalSSZ(stateSsz)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(slot, err).Error("Unable to unmarshal the SSZ response from the Beacon Node Successfully!")
|
||||
}
|
||||
|
||||
blockObj := new(spectests.SignedBeaconBlock)
|
||||
err = blockObj.UnmarshalSSZ(blockSsz)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(slot, err).Error("Unable to unmarshal the SSZ response from the Beacon Node Successfully!")
|
||||
}
|
||||
|
||||
// Check
|
||||
log.Info("Check")
|
||||
log.Info("State Slot: ", stateObj.Slot)
|
||||
log.Info("Block Slot: ", blockObj.Block.Slot)
|
||||
go bc.handleHead()
|
||||
go bc.handleReorg()
|
||||
bc.captureEventTopic()
|
||||
}
|
||||
|
||||
// Stop the head tracking service.
|
||||
@@ -54,14 +37,11 @@ func (bc *BeaconClient) StopHeadTracking() error {
|
||||
log.Info("We are going to stop tracking the head of chain because of the shutdown signal.")
|
||||
chHead := make(chan bool)
|
||||
chReorg := make(chan bool)
|
||||
chFinal := make(chan bool)
|
||||
|
||||
go bc.HeadTracking.finishProcessingChannel(chHead)
|
||||
go bc.ReOrgTracking.finishProcessingChannel(chReorg)
|
||||
go bc.FinalizationTracking.finishProcessingChannel(chFinal)
|
||||
|
||||
<-chHead
|
||||
<-chFinal
|
||||
<-chReorg
|
||||
log.Info("Successfully stopped the head tracking service.")
|
||||
return nil
|
||||
@@ -70,8 +50,8 @@ func (bc *BeaconClient) StopHeadTracking() error {
|
||||
// This function closes the SSE subscription, but waits until the MessagesCh is empty
|
||||
func (se *SseEvents[ProcessedEvents]) finishProcessingChannel(finish chan<- bool) {
|
||||
loghelper.LogEndpoint(se.Endpoint).Info("Received a close event.")
|
||||
se.SseClient.Unsubscribe(se.MessagesCh)
|
||||
for len(se.MessagesCh) != 0 && len(se.ProcessCh) != 0 {
|
||||
se.Disconnect()
|
||||
for len(se.MessagesCh) != 0 || len(se.ProcessCh) != 0 {
|
||||
time.Sleep(time.Duration(shutdownWaitInterval) * time.Millisecond)
|
||||
}
|
||||
loghelper.LogEndpoint(se.Endpoint).Info("Done processing all messages, ready for shutdown")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,179 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This file will call all the functions to start and stop capturing the head of the beacon chain.
|
||||
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// This function will perform all the heavy lifting for tracking the head of the chain.
|
||||
func (bc *BeaconClient) CaptureHistoric(ctx context.Context, maxWorkers int, minimumSlot Slot) []error {
|
||||
log.Info("We are starting the historical processing service.")
|
||||
bc.HistoricalProcess = HistoricProcessing{db: bc.Db, metrics: bc.Metrics, uniqueNodeIdentifier: bc.UniqueNodeIdentifier}
|
||||
errs := handleBatchProcess(ctx, maxWorkers, bc.HistoricalProcess, bc.SlotProcessingDetails(), bc.Metrics.IncrementHistoricSlotProcessed, minimumSlot)
|
||||
log.Debug("Exiting Historical")
|
||||
return errs
|
||||
}
|
||||
|
||||
// This function will perform all the necessary clean up tasks for stopping historical processing.
|
||||
func (bc *BeaconClient) StopHistoric(cancel context.CancelFunc) error {
|
||||
log.Info("We are stopping the historical processing service.")
|
||||
cancel()
|
||||
err := bc.HistoricalProcess.releaseDbLocks()
|
||||
if err != nil {
|
||||
loghelper.LogError(err).WithField("uniqueIdentifier", bc.UniqueNodeIdentifier).Error("We were unable to remove the locks from the eth_beacon.historic_processing table. Manual Intervention is needed!")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// An interface to enforce any batch processing. Currently there are two use cases for this.
|
||||
//
|
||||
// 1. Historic Processing
|
||||
//
|
||||
// 2. Known Gaps Processing
|
||||
type BatchProcessing interface {
|
||||
getSlotRange(context.Context, chan<- slotsToProcess, Slot) []error // Write the slots to process in a channel, return an error if you cant get the next slots to write.
|
||||
handleProcessingErrors(context.Context, <-chan batchHistoricError) // Custom logic to handle errors.
|
||||
removeTableEntry(context.Context, <-chan slotsToProcess) error // With the provided start and end slot, remove the entry from the database.
|
||||
releaseDbLocks() error // Update the checked_out column to false for whatever table is being updated.
|
||||
}
|
||||
|
||||
/// ^^^
|
||||
// Might be better to remove the interface and create a single struct that historicalProcessing
|
||||
// and knownGapsProcessing can use. The struct would contain all the SQL strings that they need.
|
||||
// And the only difference in logic for processing would be within the error handling.
|
||||
// Which can be a function we pass into handleBatchProcess()
|
||||
|
||||
// A struct to pass around indicating a table entry for slots to process.
|
||||
type slotsToProcess struct {
|
||||
startSlot Slot // The start slot
|
||||
endSlot Slot // The end slot
|
||||
}
|
||||
|
||||
type batchHistoricError struct {
|
||||
err error // The error that occurred when attempting to a slot
|
||||
errProcess string // The process that caused the error.
|
||||
slot Slot // The slot which the error is for.
|
||||
}
|
||||
|
||||
// Wrapper function for the BatchProcessing interface.
|
||||
// This function will take the structure that needs batch processing.
|
||||
// It follows a generic format.
|
||||
// Get new entries from any given table.
|
||||
// 1. Add it to the slotsCh.
|
||||
//
|
||||
// 2. Run the maximum specified workers to handle individual slots. We need a maximum because we don't want
|
||||
// To store too many SSZ objects in memory.
|
||||
//
|
||||
// 3. Process the slots and send the err to the ErrCh. Each structure can define how it wants its own errors handled.
|
||||
//
|
||||
// 4. Remove the slot entry from the DB.
|
||||
//
|
||||
// 5. Handle any errors.
|
||||
func handleBatchProcess(ctx context.Context, maxWorkers int, bp BatchProcessing, spd SlotProcessingDetails, incrementTracker func(uint64), minimumSlot Slot) []error {
|
||||
slotsCh := make(chan slotsToProcess)
|
||||
workCh := make(chan Slot)
|
||||
processedCh := make(chan slotsToProcess)
|
||||
errCh := make(chan batchHistoricError)
|
||||
finalErrCh := make(chan []error, 1)
|
||||
|
||||
// Checkout Rows with same node Identifier.
|
||||
err := bp.releaseDbLocks()
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error(("We are unable to un-checkout entries at the start!"))
|
||||
}
|
||||
|
||||
// Start workers
|
||||
for w := 1; w <= maxWorkers; w++ {
|
||||
log.WithFields(log.Fields{"maxWorkers": maxWorkers}).Debug("Starting batch processing workers")
|
||||
|
||||
go processSlotRangeWorker(ctx, workCh, errCh, spd, incrementTracker)
|
||||
}
|
||||
|
||||
// Process all ranges and send each individual slot to the worker.
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case slots := <-slotsCh:
|
||||
if slots.startSlot > slots.endSlot {
|
||||
log.Error("We received a batch process request where the startSlot is greater than the end slot.")
|
||||
errCh <- batchHistoricError{
|
||||
err: fmt.Errorf("We received a startSlot where the start was greater than the end."),
|
||||
errProcess: "RangeOrder",
|
||||
slot: slots.startSlot,
|
||||
}
|
||||
errCh <- batchHistoricError{
|
||||
err: fmt.Errorf("We received a endSlot where the start was greater than the end."),
|
||||
errProcess: "RangeOrder",
|
||||
slot: slots.endSlot,
|
||||
}
|
||||
} else if slots.startSlot == slots.endSlot {
|
||||
log.WithField("slot", slots.startSlot).Debug("Added new slot to workCh")
|
||||
workCh <- slots.startSlot
|
||||
processedCh <- slots
|
||||
} else {
|
||||
for i := slots.startSlot; i <= slots.endSlot; i++ {
|
||||
workCh <- i
|
||||
log.WithField("slot", i).Debug("Added new slot to workCh")
|
||||
}
|
||||
processedCh <- slots
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
// Remove entries, end the application if a row cannot be removed..
|
||||
go func() {
|
||||
errG := new(errgroup.Group)
|
||||
errG.Go(func() error {
|
||||
return bp.removeTableEntry(ctx, processedCh)
|
||||
})
|
||||
if err := errG.Wait(); err != nil {
|
||||
finalErrCh <- []error{err}
|
||||
}
|
||||
}()
|
||||
// Process errors from slot processing.
|
||||
go bp.handleProcessingErrors(ctx, errCh)
|
||||
|
||||
// Get slots from the DB.
|
||||
go func() {
|
||||
errs := bp.getSlotRange(ctx, slotsCh, minimumSlot) // Periodically adds new entries....
|
||||
if errs != nil {
|
||||
finalErrCh <- errs
|
||||
}
|
||||
finalErrCh <- nil
|
||||
log.Debug("We are stopping the processing of adding new entries")
|
||||
}()
|
||||
log.Debug("Waiting for shutdown signal from channel")
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Debug("Received shutdown signal from channel")
|
||||
return nil
|
||||
case errs := <-finalErrCh:
|
||||
log.Debug("Finishing the batchProcess")
|
||||
return errs
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
package beaconclient_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/jarcoal/httpmock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
)
|
||||
|
||||
var (
|
||||
kgCheckCheckedOutStmt = `SELECT * FROM eth_beacon.known_gaps WHERE checked_out=true `
|
||||
hpCheckCheckedOutStmt = `SELECT * FROM eth_beacon.historic_process WHERE checked_out=true `
|
||||
)
|
||||
|
||||
var _ = Describe("Capturehistoric", func() {
|
||||
|
||||
Describe("Run the application in historic mode", Label("unit", "behavioral", "historical"), func() {
|
||||
Context("Phase0 + Altairs: When we need to process a multiple blocks in a multiple entries in the eth_beacon.historic_process table.", Label("deb"), func() {
|
||||
It("Successfully Process the Blocks", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "99")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 100, 101, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 2, 0, 0, 0)
|
||||
// Run Two seperate processes
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 2375703, 2375703, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 3, 0, 0, 0)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
validatePopularBatchBlocks(bc)
|
||||
})
|
||||
})
|
||||
Context("When the start block is greater than the endBlock", func() {
|
||||
It("Should Add two entries to the knownGaps table", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "99")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 101, 100, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 0, 0, 2, 0)
|
||||
})
|
||||
})
|
||||
Context("Processing the Genesis block", Label("genesis"), func() {
|
||||
It("Should Process properly", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "100")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 0, 0, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 1, 0, 0, 0)
|
||||
validateSlot(bc, BeaconNodeTester.TestEvents["0"].HeadMessage, 0, "proposed")
|
||||
if bc.PerformBeaconBlockProcessing {
|
||||
validateSignedBeaconBlock(bc, BeaconNodeTester.TestEvents["0"].HeadMessage, BeaconNodeTester.TestEvents["0"].CorrectParentRoot, BeaconNodeTester.TestEvents["0"].CorrectEth1DataBlockHash, BeaconNodeTester.TestEvents["0"].CorrectSignedBeaconBlockMhKey, BeaconNodeTester.TestEvents["0"].CorrectExecutionPayloadHeader)
|
||||
}
|
||||
if bc.PerformBeaconStateProcessing {
|
||||
validateBeaconState(bc, BeaconNodeTester.TestEvents["0"].HeadMessage, BeaconNodeTester.TestEvents["0"].CorrectBeaconStateMhKey)
|
||||
}
|
||||
})
|
||||
})
|
||||
Context("When there is a skipped slot", func() {
|
||||
It("Should process the slot properly.", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "3797055")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 3797056, 3797056, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 1, 0, 0, 0)
|
||||
validateSlot(bc, BeaconNodeTester.TestEvents["3797056"].HeadMessage, 118658, "skipped")
|
||||
})
|
||||
})
|
||||
})
|
||||
Describe("Running the Application to process Known Gaps", Label("unit", "behavioral", "knownGaps"), func() {
|
||||
Context("Phase0 + Altairs: When we need to process a multiple blocks in a multiple entries in the eth_beacon.known_gaps table.", func() {
|
||||
It("Successfully Process the Blocks", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "99")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
BeaconNodeTester.writeEventToKnownGaps(bc, 100, 101)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 2, 0, 0, 0)
|
||||
// Run Two seperate processes
|
||||
BeaconNodeTester.writeEventToKnownGaps(bc, 2375703, 2375703)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 3, 0, 0, 0)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
validatePopularBatchBlocks(bc)
|
||||
})
|
||||
})
|
||||
Context("When the start block is greater than the endBlock", func() {
|
||||
It("Should Add two entries to the knownGaps table", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "104")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
BeaconNodeTester.writeEventToKnownGaps(bc, 101, 100)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 2, 0, 2, 0)
|
||||
})
|
||||
})
|
||||
Context("When theres a reprocessing error", Label("reprocessingError", "flaky"), func() {
|
||||
It("Should update the reprocessing error.", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "99")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
// We dont have an entry in the BeaconNodeTester for this slot
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 105, 105, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 0, 0, 1, 0)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 0, 0, 1, 1)
|
||||
})
|
||||
})
|
||||
})
|
||||
Describe("Running the application in Historic, Head, and KnownGaps mode", Label("unit", "historical", "full"), func() {
|
||||
Context("When it recieves a head, historic and known Gaps message (in order)", func() {
|
||||
It("Should process them all successfully.", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "2375702")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
// Head
|
||||
BeaconNodeTester.testProcessBlock(bc, BeaconNodeTester.TestEvents["2375703"].HeadMessage, 74240, maxRetry, 1, 0, 0)
|
||||
|
||||
// Historical
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 100, 100, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 2, 0, 0, 0)
|
||||
|
||||
// Known Gaps
|
||||
BeaconNodeTester.writeEventToKnownGaps(bc, 101, 101)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 3, 0, 0, 0)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
validatePopularBatchBlocks(bc)
|
||||
})
|
||||
})
|
||||
Context("When it recieves a historic, head and known Gaps message (in order)", func() {
|
||||
It("Should process them all successfully.", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "2375702")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
// Historical
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 100, 100, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 1, 0, 0, 0)
|
||||
|
||||
// Head
|
||||
BeaconNodeTester.testProcessBlock(bc, BeaconNodeTester.TestEvents["2375703"].HeadMessage, 74240, maxRetry, 1, 0, 0)
|
||||
|
||||
// Known Gaps
|
||||
BeaconNodeTester.writeEventToKnownGaps(bc, 101, 101)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 3, 0, 0, 0)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
validatePopularBatchBlocks(bc)
|
||||
})
|
||||
})
|
||||
Context("When it recieves a known Gaps, historic and head message (in order)", func() {
|
||||
It("Should process them all successfully.", func() {
|
||||
bc := setUpTest(BeaconNodeTester.TestConfig, "2375702")
|
||||
BeaconNodeTester.SetupBeaconNodeMock(BeaconNodeTester.TestEvents, BeaconNodeTester.TestConfig.protocol, BeaconNodeTester.TestConfig.address, BeaconNodeTester.TestConfig.port, BeaconNodeTester.TestConfig.dummyParentRoot)
|
||||
defer httpmock.DeactivateAndReset()
|
||||
// Known Gaps
|
||||
BeaconNodeTester.writeEventToKnownGaps(bc, 101, 101)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 1, 0, 0, 0)
|
||||
|
||||
// Historical
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 100, 100, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 2, 0, 0, 0)
|
||||
|
||||
// Head
|
||||
BeaconNodeTester.testProcessBlock(bc, BeaconNodeTester.TestEvents["2375703"].HeadMessage, 74240, maxRetry, 1, 0, 0)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
validatePopularBatchBlocks(bc)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// This function will write an even to the eth_beacon.known_gaps table
|
||||
func (tbc TestBeaconNode) writeEventToKnownGaps(bc *beaconclient.BeaconClient, startSlot, endSlot int) {
|
||||
log.Debug("We are writing the necessary events to batch process")
|
||||
insertKnownGapsStmt := `INSERT INTO eth_beacon.known_gaps (start_slot, end_slot)
|
||||
VALUES ($1, $2);`
|
||||
res, err := bc.Db.Exec(context.Background(), insertKnownGapsStmt, startSlot, endSlot)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
rows, err := res.RowsAffected()
|
||||
if rows != 1 {
|
||||
Fail("We didnt write...")
|
||||
}
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// This function will write an even to the eth_beacon.known_gaps table
|
||||
func (tbc TestBeaconNode) writeEventToHistoricProcess(bc *beaconclient.BeaconClient, startSlot, endSlot, priority int) {
|
||||
log.Debug("We are writing the necessary events to batch process")
|
||||
insertHistoricProcessingStmt := `INSERT INTO eth_beacon.historic_process (start_slot, end_slot, priority)
|
||||
VALUES ($1, $2, $3);`
|
||||
res, err := bc.Db.Exec(context.Background(), insertHistoricProcessingStmt, startSlot, endSlot, priority)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
rows, err := res.RowsAffected()
|
||||
if rows != 1 {
|
||||
Fail("We didnt write...")
|
||||
}
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// Start the CaptureHistoric function, and check for the correct inserted slots.
|
||||
func (tbc TestBeaconNode) runHistoricalProcess(bc *beaconclient.BeaconClient, maxWorkers int, expectedInserts, expectedReorgs, expectedKnownGaps, expectedKnownGapsReprocessError uint64) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go bc.CaptureHistoric(ctx, maxWorkers, 0)
|
||||
validateMetrics(bc, expectedInserts, expectedReorgs, expectedKnownGaps, expectedKnownGapsReprocessError)
|
||||
log.Debug("Calling the stop function for historical processing..")
|
||||
err := bc.StopHistoric(cancel)
|
||||
time.Sleep(5 * time.Second)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
validateAllRowsCheckedOut(bc.Db, hpCheckCheckedOutStmt)
|
||||
}
|
||||
|
||||
// Wrapper function that processes knownGaps
|
||||
func (tbc TestBeaconNode) runKnownGapsProcess(bc *beaconclient.BeaconClient, maxWorkers int, expectedInserts, expectedReorgs, expectedKnownGaps, expectedKnownGapsReprocessError uint64) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go bc.ProcessKnownGaps(ctx, maxWorkers, 0)
|
||||
validateMetrics(bc, expectedInserts, expectedReorgs, expectedKnownGaps, expectedKnownGapsReprocessError)
|
||||
err := bc.StopKnownGapsProcessing(cancel)
|
||||
time.Sleep(5 * time.Second)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
validateAllRowsCheckedOut(bc.Db, kgCheckCheckedOutStmt)
|
||||
}
|
||||
|
||||
func validateMetrics(bc *beaconclient.BeaconClient, expectedInserts, expectedReorgs, expectedKnownGaps, expectedKnownGapsReprocessError uint64) {
|
||||
curRetry := 0
|
||||
value := atomic.LoadUint64(&bc.Metrics.SlotInserts)
|
||||
for value != expectedInserts {
|
||||
time.Sleep(1 * time.Second)
|
||||
curRetry = curRetry + 1
|
||||
if curRetry == maxRetry {
|
||||
Fail(fmt.Sprintf("Too many retries have occurred. The number of inserts expected %d, the number that actually occurred, %d", expectedInserts, atomic.LoadUint64(&bc.Metrics.SlotInserts)))
|
||||
}
|
||||
value = atomic.LoadUint64(&bc.Metrics.SlotInserts)
|
||||
}
|
||||
curRetry = 0
|
||||
value = atomic.LoadUint64(&bc.Metrics.KnownGapsInserts)
|
||||
for value != expectedKnownGaps {
|
||||
time.Sleep(1 * time.Second)
|
||||
curRetry = curRetry + 1
|
||||
if curRetry == maxRetry {
|
||||
Fail(fmt.Sprintf("Too many retries have occurred. The number of knownGaps expected %d, the number that actually occurred, %d", expectedKnownGaps, atomic.LoadUint64(&bc.Metrics.KnownGapsInserts)))
|
||||
}
|
||||
value = atomic.LoadUint64(&bc.Metrics.KnownGapsInserts)
|
||||
}
|
||||
curRetry = 0
|
||||
value = atomic.LoadUint64(&bc.Metrics.KnownGapsReprocessError)
|
||||
for value != expectedKnownGapsReprocessError {
|
||||
time.Sleep(1 * time.Second)
|
||||
curRetry = curRetry + 1
|
||||
if curRetry == maxRetry {
|
||||
Fail(fmt.Sprintf("Too many retries have occurred. The number of knownGapsReprocessingErrors expected %d, the number that actually occurred, %d", expectedKnownGapsReprocessError, value))
|
||||
}
|
||||
log.Debug("&bc.Metrics.KnownGapsReprocessError: ", &bc.Metrics.KnownGapsReprocessError)
|
||||
value = atomic.LoadUint64(&bc.Metrics.KnownGapsReprocessError)
|
||||
}
|
||||
curRetry = 0
|
||||
value = atomic.LoadUint64(&bc.Metrics.ReorgInserts)
|
||||
for value != expectedReorgs {
|
||||
time.Sleep(1 * time.Second)
|
||||
curRetry = curRetry + 1
|
||||
if curRetry == maxRetry {
|
||||
Fail(fmt.Sprintf("Too many retries have occurred. The number of Reorgs expected %d, the number that actually occurred, %d", expectedReorgs, atomic.LoadUint64(&bc.Metrics.ReorgInserts)))
|
||||
}
|
||||
value = atomic.LoadUint64(&bc.Metrics.ReorgInserts)
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper function to validate a few popular blocks
|
||||
func validatePopularBatchBlocks(bc *beaconclient.BeaconClient) {
|
||||
validateSlot(bc, BeaconNodeTester.TestEvents["100"].HeadMessage, 3, "proposed")
|
||||
if bc.PerformBeaconBlockProcessing {
|
||||
validateSignedBeaconBlock(bc, BeaconNodeTester.TestEvents["100"].HeadMessage, BeaconNodeTester.TestEvents["100"].CorrectParentRoot, BeaconNodeTester.TestEvents["100"].CorrectEth1DataBlockHash, BeaconNodeTester.TestEvents["100"].CorrectSignedBeaconBlockMhKey, BeaconNodeTester.TestEvents["100"].CorrectExecutionPayloadHeader)
|
||||
}
|
||||
if bc.PerformBeaconStateProcessing {
|
||||
validateBeaconState(bc, BeaconNodeTester.TestEvents["100"].HeadMessage, BeaconNodeTester.TestEvents["100"].CorrectBeaconStateMhKey)
|
||||
}
|
||||
|
||||
validateSlot(bc, BeaconNodeTester.TestEvents["101"].HeadMessage, 3, "proposed")
|
||||
if bc.PerformBeaconBlockProcessing {
|
||||
validateSignedBeaconBlock(bc, BeaconNodeTester.TestEvents["101"].HeadMessage, BeaconNodeTester.TestEvents["100"].HeadMessage.Block, BeaconNodeTester.TestEvents["101"].CorrectEth1DataBlockHash, BeaconNodeTester.TestEvents["101"].CorrectSignedBeaconBlockMhKey, BeaconNodeTester.TestEvents["101"].CorrectExecutionPayloadHeader)
|
||||
}
|
||||
if bc.PerformBeaconStateProcessing {
|
||||
validateBeaconState(bc, BeaconNodeTester.TestEvents["101"].HeadMessage, BeaconNodeTester.TestEvents["101"].CorrectBeaconStateMhKey)
|
||||
}
|
||||
|
||||
validateSlot(bc, BeaconNodeTester.TestEvents["2375703"].HeadMessage, 74240, "proposed")
|
||||
if bc.PerformBeaconBlockProcessing {
|
||||
validateSignedBeaconBlock(bc, BeaconNodeTester.TestEvents["2375703"].HeadMessage, BeaconNodeTester.TestEvents["2375703"].CorrectParentRoot, BeaconNodeTester.TestEvents["2375703"].CorrectEth1DataBlockHash, BeaconNodeTester.TestEvents["2375703"].CorrectSignedBeaconBlockMhKey, BeaconNodeTester.TestEvents["2375703"].CorrectExecutionPayloadHeader)
|
||||
}
|
||||
if bc.PerformBeaconStateProcessing {
|
||||
validateBeaconState(bc, BeaconNodeTester.TestEvents["2375703"].HeadMessage, BeaconNodeTester.TestEvents["2375703"].CorrectBeaconStateMhKey)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all rows have checked_out as false.
|
||||
func validateAllRowsCheckedOut(db sql.Database, checkStmt string) {
|
||||
res, err := db.Exec(context.Background(), checkStmt)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
rows, err := res.RowsAffected()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rows).To(Equal(int64(0)))
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
var (
|
||||
MissingBeaconServerType error = fmt.Errorf("The beacon server type provided is not handled.")
|
||||
LighthouseMissingSlots error = fmt.Errorf("Anchor is not nil. This means lighthouse has not backfilled all the slots from Genesis to head.")
|
||||
)
|
||||
|
||||
// The sync response when checking if the node is synced.
|
||||
type Sync struct {
|
||||
Data SyncData `json:"data"`
|
||||
}
|
||||
|
||||
// The sync data
|
||||
type SyncData struct {
|
||||
IsSync bool `json:"is_syncing"`
|
||||
HeadSlot string `json:"head_slot"`
|
||||
SyncDistance string `json:"sync_distance"`
|
||||
}
|
||||
|
||||
// This function will check to see if we are synced up with the head of chain.
|
||||
// {"data":{"is_syncing":true,"head_slot":"62528","sync_distance":"3734299"}}
|
||||
func (bc BeaconClient) CheckHeadSync() (bool, error) {
|
||||
syncStatus, err := bc.QueryHeadSync()
|
||||
if err != nil {
|
||||
return true, nil
|
||||
}
|
||||
return syncStatus.Data.IsSync, nil
|
||||
}
|
||||
|
||||
func (bc BeaconClient) QueryHeadSync() (Sync, error) {
|
||||
var syncStatus Sync
|
||||
bcSync := bc.ServerEndpoint + BcSyncStatusEndpoint
|
||||
resp, err := http.Get(bcSync)
|
||||
|
||||
if err != nil {
|
||||
loghelper.LogEndpoint(bcSync).Error("Unable to check the sync status")
|
||||
return syncStatus, err
|
||||
}
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||
loghelper.LogEndpoint(bcSync).WithFields(log.Fields{"returnCode": resp.StatusCode}).Error("Error when getting the sync status")
|
||||
return syncStatus, fmt.Errorf("Querying the sync status returned a non 2xx status code, code provided: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
var body bytes.Buffer
|
||||
buf := bufio.NewWriter(&body)
|
||||
_, err = io.Copy(buf, resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return syncStatus, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body.Bytes(), &syncStatus); err != nil {
|
||||
loghelper.LogEndpoint(bcSync).WithFields(log.Fields{
|
||||
"rawMessage": body.String(),
|
||||
"err": err,
|
||||
}).Error("Unable to unmarshal sync status")
|
||||
return syncStatus, err
|
||||
}
|
||||
return syncStatus, nil
|
||||
}
|
||||
|
||||
// The response when checking the lighthouse nodes DB info: /lighthouse/database/info
|
||||
type LighthouseDatabaseInfo struct {
|
||||
SchemaVersion int `json:"schema_version"`
|
||||
Config LhDbConfig `json:"config"`
|
||||
Split LhDbSplit `json:"split"`
|
||||
Anchor LhDbAnchor `json:"anchor"`
|
||||
}
|
||||
|
||||
// The config field within the DatabaseInfo response.
|
||||
type LhDbConfig struct {
|
||||
SlotsPerRestorePoint int `json:"slots_per_restore_point"`
|
||||
SlotsPerRestorePointSetExplicitly bool `json:"slots_per_restore_point_set_explicitly"`
|
||||
BlockCacheSize int `json:"block_cache_size"`
|
||||
CompactOnInit bool `json:"compact_on_init"`
|
||||
CompactOnPrune bool `json:"compact_on_prune"`
|
||||
}
|
||||
|
||||
// The split field within the DatabaseInfo response.
|
||||
type LhDbSplit struct {
|
||||
Slot string `json:"slot"`
|
||||
StateRoot string `json:"state_root"`
|
||||
}
|
||||
|
||||
// The anchor field within the DatabaseInfo response.
|
||||
type LhDbAnchor struct {
|
||||
AnchorSlot string `json:"anchor_slot"`
|
||||
OldestBlockSlot string `json:"oldest_block_slot"`
|
||||
OldestBlockParent string `json:"oldest_block_parent"`
|
||||
StateUpperLimit string `json:"state_upper_limit"`
|
||||
StateLowerLimit string `json:"state_lower_limit"`
|
||||
}
|
||||
|
||||
// This function will notify us what the head slot is.
|
||||
func (bc BeaconClient) queryHeadSlotInBeaconServer() (int, error) {
|
||||
syncStatus, err := bc.QueryHeadSync()
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
headSlot, err := strconv.Atoi(syncStatus.Data.HeadSlot)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return headSlot, nil
|
||||
}
|
||||
|
||||
// return the lighthouse Database Info
|
||||
func (bc BeaconClient) queryLighthouseDbInfo() (LighthouseDatabaseInfo, error) {
|
||||
var dbInfo LighthouseDatabaseInfo
|
||||
|
||||
lhDbInfo := bc.ServerEndpoint + LhDbInfoEndpoint
|
||||
resp, err := http.Get(lhDbInfo)
|
||||
|
||||
if err != nil {
|
||||
loghelper.LogEndpoint(lhDbInfo).Error("Unable to get the lighthouse database information")
|
||||
return dbInfo, err
|
||||
}
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||
loghelper.LogEndpoint(lhDbInfo).WithFields(log.Fields{"returnCode": resp.StatusCode}).Error("Error when getting the lighthouse database information")
|
||||
return dbInfo, fmt.Errorf("Querying the lighthouse database information returned a non 2xx status code, code provided: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
var body bytes.Buffer
|
||||
buf := bufio.NewWriter(&body)
|
||||
_, err = io.Copy(buf, resp.Body)
|
||||
if err != nil {
|
||||
return dbInfo, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body.Bytes(), &dbInfo); err != nil {
|
||||
loghelper.LogEndpoint(lhDbInfo).WithFields(log.Fields{
|
||||
"rawMessage": body.String(),
|
||||
"err": err,
|
||||
}).Error("Unable to unmarshal the lighthouse database information")
|
||||
return dbInfo, err
|
||||
}
|
||||
return dbInfo, nil
|
||||
}
|
||||
|
||||
// This function will tell us what the latest slot is that the beacon server has available. This is important as
|
||||
// it will ensure us that we have all slots prior to the given slot.
|
||||
func (bc BeaconClient) GetLatestSlotInBeaconServer(beaconServerType string) (int, error) {
|
||||
switch strings.ToLower(beaconServerType) {
|
||||
case "lighthouse":
|
||||
headSlot, err := bc.queryHeadSlotInBeaconServer()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
lhDb, err := bc.queryLighthouseDbInfo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if lhDb.Anchor == (LhDbAnchor{}) {
|
||||
//atomic.StoreInt64(&bc.LatestSlotInBeaconServer, int64(headSlot))
|
||||
log.WithFields(log.Fields{
|
||||
"headSlot": headSlot,
|
||||
}).Info("Anchor is nil, the lighthouse client has all the nodes from genesis to head.")
|
||||
return headSlot, nil
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
"lhDb.Anchor": lhDb.Anchor,
|
||||
}).Info(LighthouseMissingSlots.Error())
|
||||
log.Info("We will add a feature down the road to wait for anchor to be null, if its needed.")
|
||||
return 0, LighthouseMissingSlots
|
||||
}
|
||||
default:
|
||||
log.WithFields(log.Fields{"BeaconServerType": beaconServerType}).Error(MissingBeaconServerType.Error())
|
||||
return 0, MissingBeaconServerType
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper function for updating the latest slot.
|
||||
func (bc BeaconClient) UpdateLatestSlotInBeaconServer(headSlot int64) {
|
||||
curr := atomic.LoadInt64(&bc.LatestSlotInBeaconServer)
|
||||
log.WithFields(log.Fields{
|
||||
"Previous Latest Slot": curr,
|
||||
"New Latest Slot": headSlot,
|
||||
}).Debug("Swapping Head Slot")
|
||||
atomic.SwapInt64(&bc.LatestSlotInBeaconServer, int64(headSlot))
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/altair"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/bellatrix"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
"github.com/protolambda/zrnt/eth2/beacon/phase0"
|
||||
"github.com/protolambda/zrnt/eth2/configs"
|
||||
"github.com/protolambda/ztyp/codec"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Eth1Data common.Eth1Data
|
||||
type Root common.Root
|
||||
type Signature common.BLSSignature
|
||||
type Slot uint64
|
||||
type Epoch uint64
|
||||
type ExecutionPayloadHeader common.ExecutionPayloadHeader
|
||||
|
||||
func ParseSlot(v string) (Slot, error) {
|
||||
slotNum, err := strconv.ParseUint(v, 10, 64)
|
||||
return Slot(slotNum), err
|
||||
}
|
||||
|
||||
func (s *Slot) Format() string {
|
||||
return strconv.FormatUint(uint64(*s), 10)
|
||||
}
|
||||
|
||||
func (s *Slot) Number() uint64 {
|
||||
return uint64(*s)
|
||||
}
|
||||
|
||||
func (s *Slot) Plus(v uint64) Slot {
|
||||
return Slot(v + s.Number())
|
||||
}
|
||||
|
||||
func (s *Slot) PlusInt(v int) Slot {
|
||||
return s.Plus(uint64(v))
|
||||
}
|
||||
|
||||
func (e *Epoch) Format() string {
|
||||
return strconv.FormatUint(uint64(*e), 10)
|
||||
}
|
||||
|
||||
type BeaconBlock struct {
|
||||
spec *common.Spec
|
||||
bellatrix *bellatrix.BeaconBlock
|
||||
altair *altair.BeaconBlock
|
||||
phase0 *phase0.BeaconBlock
|
||||
}
|
||||
|
||||
type BeaconBlockBody struct {
|
||||
spec *common.Spec
|
||||
bellatrix *bellatrix.BeaconBlockBody
|
||||
altair *altair.BeaconBlockBody
|
||||
phase0 *phase0.BeaconBlockBody
|
||||
}
|
||||
|
||||
type BeaconState struct {
|
||||
spec *common.Spec
|
||||
bellatrix *bellatrix.BeaconState
|
||||
altair *altair.BeaconState
|
||||
phase0 *phase0.BeaconState
|
||||
}
|
||||
|
||||
type SignedBeaconBlock struct {
|
||||
spec *common.Spec
|
||||
bellatrix *bellatrix.SignedBeaconBlock
|
||||
altair *altair.SignedBeaconBlock
|
||||
phase0 *phase0.SignedBeaconBlock
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) UnmarshalSSZ(ssz []byte) error {
|
||||
spec := chooseSpec(s.spec)
|
||||
|
||||
var bellatrix bellatrix.SignedBeaconBlock
|
||||
err := bellatrix.Deserialize(spec, makeDecodingReader(ssz))
|
||||
if nil == err {
|
||||
s.bellatrix = &bellatrix
|
||||
s.altair = nil
|
||||
s.phase0 = nil
|
||||
log.Info("Unmarshalled Bellatrix SignedBeaconBlock")
|
||||
return nil
|
||||
}
|
||||
|
||||
var altair altair.SignedBeaconBlock
|
||||
err = altair.Deserialize(spec, makeDecodingReader(ssz))
|
||||
if nil == err {
|
||||
s.bellatrix = nil
|
||||
s.altair = &altair
|
||||
s.phase0 = nil
|
||||
log.Info("Unmarshalled Altair SignedBeaconBlock")
|
||||
return nil
|
||||
}
|
||||
|
||||
var phase0 phase0.SignedBeaconBlock
|
||||
err = phase0.Deserialize(spec, makeDecodingReader(ssz))
|
||||
if nil == err {
|
||||
s.bellatrix = nil
|
||||
s.altair = nil
|
||||
s.phase0 = &phase0
|
||||
log.Info("Unmarshalled Phase0 SignedBeaconBlock")
|
||||
return nil
|
||||
}
|
||||
|
||||
s.bellatrix = nil
|
||||
s.altair = nil
|
||||
s.phase0 = nil
|
||||
|
||||
log.Warning("Unable to unmarshal SignedBeaconBlock")
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) MarshalSSZ() ([]byte, error) {
|
||||
spec := chooseSpec(s.spec)
|
||||
var err error
|
||||
var buf bytes.Buffer
|
||||
encodingWriter := codec.NewEncodingWriter(&buf)
|
||||
|
||||
if s.IsBellatrix() {
|
||||
err = s.bellatrix.Serialize(spec, encodingWriter)
|
||||
}
|
||||
if s.IsAltair() {
|
||||
err = s.altair.Serialize(spec, encodingWriter)
|
||||
}
|
||||
if s.IsPhase0() {
|
||||
err = s.phase0.Serialize(spec, encodingWriter)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) IsBellatrix() bool {
|
||||
return s.bellatrix != nil
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) IsAltair() bool {
|
||||
return s.altair != nil
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) IsPhase0() bool {
|
||||
return s.phase0 != nil
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) GetBellatrix() *bellatrix.SignedBeaconBlock {
|
||||
return s.bellatrix
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) GetAltair() *altair.SignedBeaconBlock {
|
||||
return s.altair
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) GetPhase0() *phase0.SignedBeaconBlock {
|
||||
return s.phase0
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) Signature() Signature {
|
||||
if s.IsBellatrix() {
|
||||
return Signature(s.bellatrix.Signature)
|
||||
}
|
||||
|
||||
if s.IsAltair() {
|
||||
return Signature(s.altair.Signature)
|
||||
}
|
||||
|
||||
if s.IsPhase0() {
|
||||
return Signature(s.phase0.Signature)
|
||||
}
|
||||
|
||||
return Signature{}
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlock) Block() *BeaconBlock {
|
||||
if s.IsBellatrix() {
|
||||
return &BeaconBlock{bellatrix: &s.bellatrix.Message, spec: s.spec}
|
||||
}
|
||||
|
||||
if s.IsAltair() {
|
||||
return &BeaconBlock{altair: &s.altair.Message, spec: s.spec}
|
||||
}
|
||||
|
||||
if s.IsPhase0() {
|
||||
return &BeaconBlock{phase0: &s.phase0.Message, spec: s.spec}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlock) IsBellatrix() bool {
|
||||
return b.bellatrix != nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlock) IsAltair() bool {
|
||||
return b.altair != nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlock) IsPhase0() bool {
|
||||
return b.phase0 != nil
|
||||
}
|
||||
|
||||
func (s *BeaconBlock) GetBellatrix() *bellatrix.BeaconBlock {
|
||||
return s.bellatrix
|
||||
}
|
||||
|
||||
func (s *BeaconBlock) GetAltair() *altair.BeaconBlock {
|
||||
return s.altair
|
||||
}
|
||||
|
||||
func (s *BeaconBlock) GetPhase0() *phase0.BeaconBlock {
|
||||
return s.phase0
|
||||
}
|
||||
|
||||
func (b *BeaconBlock) ParentRoot() Root {
|
||||
if b.IsBellatrix() {
|
||||
return Root(b.bellatrix.ParentRoot)
|
||||
}
|
||||
|
||||
if b.IsAltair() {
|
||||
return Root(b.altair.ParentRoot)
|
||||
}
|
||||
|
||||
if b.IsPhase0() {
|
||||
return Root(b.phase0.ParentRoot)
|
||||
}
|
||||
|
||||
return Root{}
|
||||
}
|
||||
|
||||
func (b *BeaconBlock) StateRoot() Root {
|
||||
if b.IsBellatrix() {
|
||||
return Root(b.bellatrix.StateRoot)
|
||||
}
|
||||
|
||||
if b.IsAltair() {
|
||||
return Root(b.altair.StateRoot)
|
||||
}
|
||||
|
||||
if b.IsPhase0() {
|
||||
return Root(b.phase0.StateRoot)
|
||||
}
|
||||
|
||||
return Root{}
|
||||
}
|
||||
|
||||
func (b *BeaconBlock) Body() *BeaconBlockBody {
|
||||
if b.IsBellatrix() {
|
||||
return &BeaconBlockBody{bellatrix: &b.bellatrix.Body, spec: b.spec}
|
||||
}
|
||||
|
||||
if b.IsAltair() {
|
||||
return &BeaconBlockBody{altair: &b.altair.Body, spec: b.spec}
|
||||
}
|
||||
|
||||
if b.IsPhase0() {
|
||||
return &BeaconBlockBody{phase0: &b.phase0.Body, spec: b.spec}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlockBody) IsBellatrix() bool {
|
||||
return b.bellatrix != nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlockBody) IsAltair() bool {
|
||||
return b.altair != nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlockBody) IsPhase0() bool {
|
||||
return b.phase0 != nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlockBody) Eth1Data() Eth1Data {
|
||||
if b.IsBellatrix() {
|
||||
return Eth1Data(b.bellatrix.Eth1Data)
|
||||
}
|
||||
|
||||
if b.IsAltair() {
|
||||
return Eth1Data(b.altair.Eth1Data)
|
||||
}
|
||||
|
||||
if b.IsPhase0() {
|
||||
return Eth1Data(b.phase0.Eth1Data)
|
||||
}
|
||||
|
||||
return Eth1Data{}
|
||||
}
|
||||
|
||||
func (b *BeaconBlockBody) ExecutionPayloadHeader() *ExecutionPayloadHeader {
|
||||
if b.IsBellatrix() {
|
||||
payloadHeader := b.bellatrix.ExecutionPayload.Header(chooseSpec(b.spec))
|
||||
return (*ExecutionPayloadHeader)(payloadHeader)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlock) HashTreeRoot() Root {
|
||||
spec := chooseSpec(b.spec)
|
||||
hashFn := tree.GetHashFn()
|
||||
|
||||
if b.IsBellatrix() {
|
||||
return Root(b.bellatrix.HashTreeRoot(spec, hashFn))
|
||||
}
|
||||
|
||||
if b.IsAltair() {
|
||||
return Root(b.altair.HashTreeRoot(spec, hashFn))
|
||||
}
|
||||
|
||||
if b.IsPhase0() {
|
||||
return Root(b.phase0.HashTreeRoot(spec, hashFn))
|
||||
}
|
||||
|
||||
return Root{}
|
||||
}
|
||||
|
||||
func (s *BeaconState) UnmarshalSSZ(ssz []byte) error {
|
||||
spec := chooseSpec(s.spec)
|
||||
|
||||
var bellatrix bellatrix.BeaconState
|
||||
err := bellatrix.Deserialize(spec, makeDecodingReader(ssz))
|
||||
if nil == err {
|
||||
s.bellatrix = &bellatrix
|
||||
s.altair = nil
|
||||
s.phase0 = nil
|
||||
log.Info("Unmarshalled Bellatrix BeaconState")
|
||||
return nil
|
||||
}
|
||||
|
||||
var altair altair.BeaconState
|
||||
err = altair.Deserialize(spec, makeDecodingReader(ssz))
|
||||
if nil == err {
|
||||
s.bellatrix = nil
|
||||
s.altair = &altair
|
||||
s.phase0 = nil
|
||||
log.Info("Unmarshalled Altair BeaconState")
|
||||
return nil
|
||||
}
|
||||
|
||||
var phase0 phase0.BeaconState
|
||||
err = phase0.Deserialize(spec, makeDecodingReader(ssz))
|
||||
if nil == err {
|
||||
s.bellatrix = nil
|
||||
s.altair = nil
|
||||
s.phase0 = &phase0
|
||||
log.Info("Unmarshalled Phase0 BeaconState")
|
||||
return nil
|
||||
}
|
||||
|
||||
s.bellatrix = nil
|
||||
s.altair = nil
|
||||
s.phase0 = nil
|
||||
|
||||
log.Warning("Unable to unmarshal BeaconState")
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *BeaconState) MarshalSSZ() ([]byte, error) {
|
||||
spec := chooseSpec(s.spec)
|
||||
var err error
|
||||
var buf bytes.Buffer
|
||||
encodingWriter := codec.NewEncodingWriter(&buf)
|
||||
|
||||
if s.IsBellatrix() {
|
||||
err = s.bellatrix.Serialize(spec, encodingWriter)
|
||||
} else if s.IsAltair() {
|
||||
err = s.altair.Serialize(spec, encodingWriter)
|
||||
} else if s.IsPhase0() {
|
||||
err = s.phase0.Serialize(spec, encodingWriter)
|
||||
} else {
|
||||
err = errors.New("BeaconState not set")
|
||||
}
|
||||
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (s *BeaconState) IsBellatrix() bool {
|
||||
return s.bellatrix != nil
|
||||
}
|
||||
|
||||
func (s *BeaconState) IsAltair() bool {
|
||||
return s.altair != nil
|
||||
}
|
||||
|
||||
func (s *BeaconState) IsPhase0() bool {
|
||||
return s.phase0 != nil
|
||||
}
|
||||
|
||||
func (s *BeaconState) HashTreeRoot() Root {
|
||||
spec := chooseSpec(s.spec)
|
||||
hashFn := tree.GetHashFn()
|
||||
|
||||
if s.IsBellatrix() {
|
||||
return Root(s.bellatrix.HashTreeRoot(spec, hashFn))
|
||||
}
|
||||
|
||||
if s.IsAltair() {
|
||||
return Root(s.altair.HashTreeRoot(spec, hashFn))
|
||||
}
|
||||
|
||||
if s.IsPhase0() {
|
||||
return Root(s.phase0.HashTreeRoot(spec, hashFn))
|
||||
}
|
||||
|
||||
return Root{}
|
||||
}
|
||||
|
||||
func (s *BeaconState) GetBellatrix() *bellatrix.BeaconState {
|
||||
return s.bellatrix
|
||||
}
|
||||
|
||||
func (s *BeaconState) GetAltair() *altair.BeaconState {
|
||||
return s.altair
|
||||
}
|
||||
|
||||
func (s *BeaconState) GetPhase0() *phase0.BeaconState {
|
||||
return s.phase0
|
||||
}
|
||||
|
||||
func chooseSpec(spec *common.Spec) *common.Spec {
|
||||
if nil == spec {
|
||||
return configs.Mainnet
|
||||
}
|
||||
return spec
|
||||
}
|
||||
|
||||
func makeDecodingReader(ssz []byte) *codec.DecodingReader {
|
||||
return codec.NewDecodingReader(bytes.NewReader(ssz), uint64(len(ssz)))
|
||||
}
|
||||
@@ -0,0 +1,651 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/jackc/pgx/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
var (
|
||||
// Statement to upsert to the eth_beacon.slots table.
|
||||
UpsertSlotsStmt string = `
|
||||
INSERT INTO eth_beacon.slots (epoch, slot, block_root, state_root, status)
|
||||
VALUES ($1, $2, $3, $4, $5) ON CONFLICT (slot, block_root) DO NOTHING`
|
||||
// Statement to upsert to the eth_beacon.signed_blocks table.
|
||||
UpsertSignedBeaconBlockStmt string = `
|
||||
INSERT INTO eth_beacon.signed_block (slot, block_root, parent_block_root, eth1_data_block_hash, mh_key)
|
||||
VALUES ($1, $2, $3, $4, $5) ON CONFLICT (slot, block_root) DO NOTHING`
|
||||
UpsertSignedBeaconBlockWithPayloadStmt string = `
|
||||
INSERT INTO eth_beacon.signed_block (slot, block_root, parent_block_root, eth1_data_block_hash, mh_key,
|
||||
payload_block_number, payload_timestamp, payload_block_hash,
|
||||
payload_parent_hash, payload_state_root, payload_receipts_root,
|
||||
payload_transactions_root)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) ON CONFLICT (slot, block_root) DO NOTHING`
|
||||
// Statement to upsert to the eth_beacon.state table.
|
||||
UpsertBeaconState string = `
|
||||
INSERT INTO eth_beacon.state (slot, state_root, mh_key)
|
||||
VALUES ($1, $2, $3) ON CONFLICT (slot, state_root) DO NOTHING`
|
||||
// Statement to upsert to the public.blocks table.
|
||||
UpsertBlocksStmt string = `
|
||||
INSERT INTO public.blocks (key, data)
|
||||
VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`
|
||||
UpdateForkedStmt string = `UPDATE eth_beacon.slots
|
||||
SET status='forked'
|
||||
WHERE slot=$1 AND block_root<>$2
|
||||
RETURNING block_root;`
|
||||
UpdateProposedStmt string = `UPDATE eth_beacon.slots
|
||||
SET status='proposed'
|
||||
WHERE slot=$1 AND block_root=$2
|
||||
RETURNING block_root;`
|
||||
CheckProposedStmt string = `SELECT slot, block_root
|
||||
FROM eth_beacon.slots
|
||||
WHERE slot=$1 AND block_root=$2;`
|
||||
// Check to see if the slot and block_root exist in eth_beacon.signed_block
|
||||
CheckSignedBeaconBlockStmt string = `SELECT slot, block_root
|
||||
FROM eth_beacon.signed_block
|
||||
WHERE slot=$1 AND block_root=$2`
|
||||
// Check to see if the slot and state_root exist in eth_beacon.state
|
||||
CheckBeaconStateStmt string = `SELECT slot, state_root
|
||||
FROM eth_beacon.state
|
||||
WHERE slot=$1 AND state_root=$2`
|
||||
// Used to get a single slot from the table if it exists
|
||||
QueryBySlotStmt string = `SELECT slot
|
||||
FROM eth_beacon.slots
|
||||
WHERE slot=$1`
|
||||
// Statement to insert known_gaps. We don't pass in timestamp, we let the server take care of that one.
|
||||
UpsertKnownGapsStmt string = `
|
||||
INSERT INTO eth_beacon.known_gaps (start_slot, end_slot, checked_out, reprocessing_error, entry_error, entry_process)
|
||||
VALUES ($1, $2, $3, $4, $5, $6) on CONFLICT (start_slot, end_slot) DO NOTHING`
|
||||
UpsertKnownGapsErrorStmt string = `
|
||||
UPDATE eth_beacon.known_gaps
|
||||
SET reprocessing_error=$3, priority=priority+1
|
||||
WHERE start_slot=$1 AND end_slot=$2;`
|
||||
// Get the highest slot if one exists
|
||||
QueryHighestSlotStmt string = "SELECT COALESCE(MAX(slot), 0) FROM eth_beacon.slots"
|
||||
)
|
||||
|
||||
// Put all functionality to prepare the write object
|
||||
// And write it in this file.
|
||||
// Remove any of it from the processslot file.
|
||||
type DatabaseWriter struct {
|
||||
Db sql.Database
|
||||
Tx sql.Tx
|
||||
Ctx context.Context
|
||||
Metrics *BeaconClientMetrics
|
||||
DbSlots *DbSlots
|
||||
DbSignedBeaconBlock *DbSignedBeaconBlock
|
||||
DbBeaconState *DbBeaconState
|
||||
rawBeaconState *[]byte
|
||||
rawSignedBeaconBlock *[]byte
|
||||
}
|
||||
|
||||
func CreateDatabaseWrite(db sql.Database, slot Slot, stateRoot string, blockRoot string, parentBlockRoot string,
|
||||
eth1DataBlockHash string, payloadHeader *ExecutionPayloadHeader, status string, rawSignedBeaconBlock *[]byte, rawBeaconState *[]byte, metrics *BeaconClientMetrics) (*DatabaseWriter, error) {
|
||||
ctx := context.Background()
|
||||
tx, err := db.Begin(ctx)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("We are unable to Begin a SQL transaction")
|
||||
}
|
||||
dw := &DatabaseWriter{
|
||||
Db: db,
|
||||
Tx: tx,
|
||||
Ctx: ctx,
|
||||
rawBeaconState: rawBeaconState,
|
||||
rawSignedBeaconBlock: rawSignedBeaconBlock,
|
||||
Metrics: metrics,
|
||||
}
|
||||
dw.prepareSlotsModel(slot, stateRoot, blockRoot, status)
|
||||
err = dw.prepareSignedBeaconBlockModel(slot, blockRoot, parentBlockRoot, eth1DataBlockHash, payloadHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = dw.prepareBeaconStateModel(slot, stateRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dw, err
|
||||
}
|
||||
|
||||
// Write functions to write each all together...
|
||||
// Should I do one atomic write?
|
||||
// Create the model for the eth_beacon.slots table
|
||||
func (dw *DatabaseWriter) prepareSlotsModel(slot Slot, stateRoot string, blockRoot string, status string) {
|
||||
dw.DbSlots = &DbSlots{
|
||||
Epoch: calculateEpoch(slot, bcSlotsPerEpoch),
|
||||
Slot: slot.Number(),
|
||||
StateRoot: stateRoot,
|
||||
BlockRoot: blockRoot,
|
||||
Status: status,
|
||||
}
|
||||
log.Debug("dw.DbSlots: ", dw.DbSlots)
|
||||
|
||||
}
|
||||
|
||||
// Create the model for the eth_beacon.signed_block table.
|
||||
func (dw *DatabaseWriter) prepareSignedBeaconBlockModel(slot Slot, blockRoot string, parentBlockRoot string, eth1DataBlockHash string,
|
||||
payloadHeader *ExecutionPayloadHeader) error {
|
||||
mhKey, err := MultihashKeyFromSSZRoot([]byte(dw.DbSlots.BlockRoot))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dw.DbSignedBeaconBlock = &DbSignedBeaconBlock{
|
||||
Slot: slot.Number(),
|
||||
BlockRoot: blockRoot,
|
||||
ParentBlock: parentBlockRoot,
|
||||
Eth1DataBlockHash: eth1DataBlockHash,
|
||||
MhKey: mhKey,
|
||||
ExecutionPayloadHeader: nil,
|
||||
}
|
||||
|
||||
if nil != payloadHeader {
|
||||
dw.DbSignedBeaconBlock.ExecutionPayloadHeader = &DbExecutionPayloadHeader{
|
||||
BlockNumber: uint64(payloadHeader.BlockNumber),
|
||||
Timestamp: uint64(payloadHeader.Timestamp),
|
||||
BlockHash: toHex(payloadHeader.BlockHash),
|
||||
ParentHash: toHex(payloadHeader.ParentHash),
|
||||
StateRoot: toHex(payloadHeader.StateRoot),
|
||||
ReceiptsRoot: toHex(payloadHeader.ReceiptsRoot),
|
||||
TransactionsRoot: toHex(payloadHeader.TransactionsRoot),
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("dw.DbSignedBeaconBlock: ", dw.DbSignedBeaconBlock)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the model for the eth_beacon.state table.
|
||||
func (dw *DatabaseWriter) prepareBeaconStateModel(slot Slot, stateRoot string) error {
|
||||
mhKey, err := MultihashKeyFromSSZRoot([]byte(dw.DbSlots.StateRoot))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dw.DbBeaconState = &DbBeaconState{
|
||||
Slot: slot.Number(),
|
||||
StateRoot: stateRoot,
|
||||
MhKey: mhKey,
|
||||
}
|
||||
log.Debug("dw.DbBeaconState: ", dw.DbBeaconState)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add all the data for a given slot to a SQL transaction.
|
||||
// Originally it wrote to each table individually.
|
||||
func (dw *DatabaseWriter) transactFullSlot() error {
|
||||
// If an error occurs, write to knownGaps table.
|
||||
log.WithFields(log.Fields{
|
||||
"slot": dw.DbSlots.Slot,
|
||||
}).Debug("Starting to write to the DB.")
|
||||
err := dw.transactSlots()
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("We couldn't write to the eth_beacon.slots table...")
|
||||
return err
|
||||
}
|
||||
log.Debug("We finished writing to the eth_beacon.slots table.")
|
||||
if dw.DbSlots.Status != "skipped" {
|
||||
//errG, _ := errgroup.WithContext(context.Background())
|
||||
//errG.Go(func() error {
|
||||
// return dw.transactSignedBeaconBlocks()
|
||||
//})
|
||||
//errG.Go(func() error {
|
||||
// return dw.transactBeaconState()
|
||||
//})
|
||||
//if err := errG.Wait(); err != nil {
|
||||
// loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("We couldn't write to the eth_beacon block or state table...")
|
||||
// return err
|
||||
//}
|
||||
// Might want to seperate writing to public.blocks so we can do this concurrently...
|
||||
// Cant concurrently write because we are using a transaction.
|
||||
err := dw.transactSignedBeaconBlocks()
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("We couldn't write to the eth_beacon block table...")
|
||||
return err
|
||||
}
|
||||
err = dw.transactBeaconState()
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("We couldn't write to the eth_beacon state table...")
|
||||
return err
|
||||
}
|
||||
}
|
||||
dw.Metrics.IncrementSlotInserts(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add data for the eth_beacon.slots table to a transaction. For now this is only one function.
|
||||
// But in the future if we need to incorporate any FK's or perform any actions to write to the
|
||||
// slots table we can do it all here.
|
||||
func (dw *DatabaseWriter) transactSlots() error {
|
||||
return dw.upsertSlots()
|
||||
}
|
||||
|
||||
// Upsert to the eth_beacon.slots table.
|
||||
func (dw *DatabaseWriter) upsertSlots() error {
|
||||
_, err := dw.Tx.Exec(dw.Ctx, UpsertSlotsStmt, dw.DbSlots.Epoch, dw.DbSlots.Slot, dw.DbSlots.BlockRoot, dw.DbSlots.StateRoot, dw.DbSlots.Status)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("Unable to write to the slot to the eth_beacon.slots table")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add the information for the signed_block to a transaction.
|
||||
func (dw *DatabaseWriter) transactSignedBeaconBlocks() error {
|
||||
if nil == dw.rawSignedBeaconBlock || len(*dw.rawSignedBeaconBlock) == 0 {
|
||||
log.Warn("Skipping writing of empty BeaconBlock.")
|
||||
return nil
|
||||
}
|
||||
|
||||
err := dw.upsertPublicBlocks(dw.DbSignedBeaconBlock.MhKey, dw.rawSignedBeaconBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dw.upsertSignedBeaconBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Upsert to public.blocks.
|
||||
func (dw *DatabaseWriter) upsertPublicBlocks(key string, data *[]byte) error {
|
||||
_, err := dw.Tx.Exec(dw.Ctx, UpsertBlocksStmt, key, *data)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("Unable to write to the slot to the public.blocks table")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Upsert to the eth_beacon.signed_block table.
|
||||
func (dw *DatabaseWriter) upsertSignedBeaconBlock() error {
|
||||
block := dw.DbSignedBeaconBlock
|
||||
var err error
|
||||
if nil != block.ExecutionPayloadHeader {
|
||||
_, err = dw.Tx.Exec(dw.Ctx,
|
||||
UpsertSignedBeaconBlockWithPayloadStmt,
|
||||
block.Slot,
|
||||
block.BlockRoot,
|
||||
block.ParentBlock,
|
||||
block.Eth1DataBlockHash,
|
||||
block.MhKey,
|
||||
block.ExecutionPayloadHeader.BlockNumber,
|
||||
block.ExecutionPayloadHeader.Timestamp,
|
||||
block.ExecutionPayloadHeader.BlockHash,
|
||||
block.ExecutionPayloadHeader.ParentHash,
|
||||
block.ExecutionPayloadHeader.StateRoot,
|
||||
block.ExecutionPayloadHeader.ReceiptsRoot,
|
||||
block.ExecutionPayloadHeader.TransactionsRoot,
|
||||
)
|
||||
} else {
|
||||
_, err = dw.Tx.Exec(dw.Ctx,
|
||||
UpsertSignedBeaconBlockStmt,
|
||||
block.Slot,
|
||||
block.BlockRoot,
|
||||
block.ParentBlock,
|
||||
block.Eth1DataBlockHash,
|
||||
block.MhKey,
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).WithFields(log.Fields{"block_root": block.BlockRoot}).Error("Unable to write to the slot to the eth_beacon.signed_block table")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add the information for the state to a transaction.
|
||||
func (dw *DatabaseWriter) transactBeaconState() error {
|
||||
if nil == dw.rawBeaconState || len(*dw.rawBeaconState) == 0 {
|
||||
log.Warn("Skipping writing of empty BeaconState.")
|
||||
return nil
|
||||
}
|
||||
|
||||
err := dw.upsertPublicBlocks(dw.DbBeaconState.MhKey, dw.rawBeaconState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dw.upsertBeaconState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Upsert to the eth_beacon.state table.
|
||||
func (dw *DatabaseWriter) upsertBeaconState() error {
|
||||
_, err := dw.Tx.Exec(dw.Ctx, UpsertBeaconState, dw.DbBeaconState.Slot, dw.DbBeaconState.StateRoot, dw.DbBeaconState.MhKey)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("Unable to write to the slot to the eth_beacon.state table")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update a given slot to be marked as forked within a transaction. Provide the slot and the latest latestBlockRoot.
|
||||
// We will mark all entries for the given slot that don't match the provided latestBlockRoot as forked.
|
||||
func transactReorgs(tx sql.Tx, ctx context.Context, slot Slot, latestBlockRoot string, metrics *BeaconClientMetrics) {
|
||||
forkCount, err := updateForked(tx, ctx, slot, latestBlockRoot)
|
||||
if err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Error("We ran into some trouble while updating all forks.")
|
||||
transactKnownGaps(tx, ctx, 1, slot, slot, err, "reorg", metrics)
|
||||
}
|
||||
proposedCount, err := updateProposed(tx, ctx, slot, latestBlockRoot)
|
||||
if err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Error("We ran into some trouble while trying to update the proposed slot.")
|
||||
transactKnownGaps(tx, ctx, 1, slot, slot, err, "reorg", metrics)
|
||||
}
|
||||
|
||||
if forkCount > 0 {
|
||||
loghelper.LogReorg(slot.Number(), latestBlockRoot).WithFields(log.Fields{
|
||||
"forkCount": forkCount,
|
||||
}).Info("Updated rows that were forked.")
|
||||
} else {
|
||||
loghelper.LogReorg(slot.Number(), latestBlockRoot).WithFields(log.Fields{
|
||||
"forkCount": forkCount,
|
||||
}).Warn("There were no forked rows to update.")
|
||||
}
|
||||
|
||||
if proposedCount == 1 {
|
||||
loghelper.LogReorg(slot.Number(), latestBlockRoot).WithFields(log.Fields{
|
||||
"proposedCount": proposedCount,
|
||||
}).Info("Updated the row that should have been marked as proposed.")
|
||||
} else if proposedCount > 1 {
|
||||
loghelper.LogReorg(slot.Number(), latestBlockRoot).WithFields(log.Fields{
|
||||
"proposedCount": proposedCount,
|
||||
}).Error("Too many rows were marked as proposed!")
|
||||
transactKnownGaps(tx, ctx, 1, slot, slot, fmt.Errorf("Too many rows were marked as unproposed."), "reorg", metrics)
|
||||
} else if proposedCount == 0 {
|
||||
transactKnownGaps(tx, ctx, 1, slot, slot, fmt.Errorf("Unable to find properly proposed row in DB"), "reorg", metrics)
|
||||
loghelper.LogReorg(slot.Number(), latestBlockRoot).Info("Updated the row that should have been marked as proposed.")
|
||||
}
|
||||
|
||||
metrics.IncrementReorgsInsert(1)
|
||||
}
|
||||
|
||||
// Wrapper function that will create a transaction and execute the function.
|
||||
func writeReorgs(db sql.Database, slot Slot, latestBlockRoot string, metrics *BeaconClientMetrics) {
|
||||
ctx := context.Background()
|
||||
tx, err := db.Begin(ctx)
|
||||
if err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Fatal("Unable to create a new transaction for reorgs")
|
||||
}
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && err != pgx.ErrTxClosed {
|
||||
loghelper.LogError(err).Error("We were unable to Rollback a transaction for reorgs")
|
||||
}
|
||||
}()
|
||||
transactReorgs(tx, ctx, slot, latestBlockRoot, metrics)
|
||||
if err = tx.Commit(ctx); err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Fatal("Unable to execute the transaction for reorgs")
|
||||
}
|
||||
}
|
||||
|
||||
// Update the slots table by marking the old slot's as forked.
|
||||
func updateForked(tx sql.Tx, ctx context.Context, slot Slot, latestBlockRoot string) (int64, error) {
|
||||
res, err := tx.Exec(ctx, UpdateForkedStmt, slot, latestBlockRoot)
|
||||
if err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Error("We are unable to update the eth_beacon.slots table with the forked slots")
|
||||
return 0, err
|
||||
}
|
||||
count, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Error("Unable to figure out how many entries were marked as forked.")
|
||||
return 0, err
|
||||
}
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Mark a slot as proposed.
|
||||
func updateProposed(tx sql.Tx, ctx context.Context, slot Slot, latestBlockRoot string) (int64, error) {
|
||||
res, err := tx.Exec(ctx, UpdateProposedStmt, slot, latestBlockRoot)
|
||||
if err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Error("We are unable to update the eth_beacon.slots table with the proposed slot.")
|
||||
return 0, err
|
||||
}
|
||||
count, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
loghelper.LogReorgError(slot.Number(), latestBlockRoot, err).Error("Unable to figure out how many entries were marked as proposed")
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, err
|
||||
}
|
||||
|
||||
// A wrapper function to call upsertKnownGaps. This function will break down the range of known_gaps into
|
||||
// smaller chunks. For example, instead of having an entry of 1-101, if we increment the entries by 10 slots, we would
|
||||
// have 10 entries as follows: 1-10, 11-20, etc...
|
||||
func transactKnownGaps(tx sql.Tx, ctx context.Context, tableIncrement int, startSlot Slot, endSlot Slot, entryError error, entryProcess string, metric *BeaconClientMetrics) {
|
||||
var entryErrorMsg string
|
||||
if entryError == nil {
|
||||
entryErrorMsg = ""
|
||||
} else {
|
||||
entryErrorMsg = entryError.Error()
|
||||
}
|
||||
if endSlot.Number()-startSlot.Number() <= uint64(tableIncrement) {
|
||||
kgModel := DbKnownGaps{
|
||||
StartSlot: startSlot.Number(),
|
||||
EndSlot: endSlot.Number(),
|
||||
CheckedOut: false,
|
||||
ReprocessingError: "",
|
||||
EntryError: entryErrorMsg,
|
||||
EntryProcess: entryProcess,
|
||||
}
|
||||
upsertKnownGaps(tx, ctx, kgModel, metric)
|
||||
} else {
|
||||
totalSlots := endSlot.Number() - startSlot.Number()
|
||||
var chunks int
|
||||
chunks = int(totalSlots / uint64(tableIncrement))
|
||||
if totalSlots%uint64(tableIncrement) != 0 {
|
||||
chunks = chunks + 1
|
||||
}
|
||||
|
||||
for i := 0; i < chunks; i++ {
|
||||
var tempStart, tempEnd Slot
|
||||
tempStart = startSlot.PlusInt(i * tableIncrement)
|
||||
if i+1 == chunks {
|
||||
tempEnd = endSlot
|
||||
} else {
|
||||
tempEnd = startSlot.PlusInt((i + 1) * tableIncrement)
|
||||
}
|
||||
kgModel := DbKnownGaps{
|
||||
StartSlot: tempStart.Number(),
|
||||
EndSlot: tempEnd.Number(),
|
||||
CheckedOut: false,
|
||||
ReprocessingError: "",
|
||||
EntryError: entryErrorMsg,
|
||||
EntryProcess: entryProcess,
|
||||
}
|
||||
upsertKnownGaps(tx, ctx, kgModel, metric)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper function, instead of adding the knownGaps entries to a transaction, it will
|
||||
// create the transaction and write it.
|
||||
func writeKnownGaps(db sql.Database, tableIncrement int, startSlot Slot, endSlot Slot, entryError error, entryProcess string, metric *BeaconClientMetrics) {
|
||||
ctx := context.Background()
|
||||
tx, err := db.Begin(ctx)
|
||||
if err != nil {
|
||||
loghelper.LogSlotRangeError(startSlot.Number(), endSlot.Number(), err).Fatal("Unable to create a new transaction for knownGaps")
|
||||
}
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && err != pgx.ErrTxClosed {
|
||||
loghelper.LogError(err).Error("We were unable to Rollback a transaction for reorgs")
|
||||
}
|
||||
}()
|
||||
transactKnownGaps(tx, ctx, tableIncrement, startSlot, endSlot, entryError, entryProcess, metric)
|
||||
if err = tx.Commit(ctx); err != nil {
|
||||
loghelper.LogSlotRangeError(startSlot.Number(), endSlot.Number(), err).Fatal("Unable to execute the transaction for knownGaps")
|
||||
}
|
||||
}
|
||||
|
||||
// A function to upsert a single entry to the eth_beacon.known_gaps table.
|
||||
func upsertKnownGaps(tx sql.Tx, ctx context.Context, knModel DbKnownGaps, metric *BeaconClientMetrics) {
|
||||
_, err := tx.Exec(ctx, UpsertKnownGapsStmt, knModel.StartSlot, knModel.EndSlot,
|
||||
knModel.CheckedOut, knModel.ReprocessingError, knModel.EntryError, knModel.EntryProcess)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"startSlot": knModel.StartSlot,
|
||||
"endSlot": knModel.EndSlot,
|
||||
}).Fatal("We are unable to write to the eth_beacon.known_gaps table!!! We will stop the application because of that.")
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"startSlot": knModel.StartSlot,
|
||||
"endSlot": knModel.EndSlot,
|
||||
}).Warn("A new gap has been added to the eth_beacon.known_gaps table.")
|
||||
metric.IncrementKnownGapsInserts(1)
|
||||
}
|
||||
|
||||
// A function to write the gap between the highest slot in the DB and the first processed slot.
|
||||
func writeStartUpGaps(db sql.Database, tableIncrement int, firstSlot Slot, metric *BeaconClientMetrics) {
|
||||
var maxSlot Slot
|
||||
err := db.QueryRow(context.Background(), QueryHighestSlotStmt).Scan(&maxSlot)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Fatal("Unable to get the max block from the DB. We must close the application or we might have undetected gaps.")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
loghelper.LogError(err).WithFields(log.Fields{
|
||||
"maxSlot": maxSlot,
|
||||
}).Fatal("Unable to get convert max block from DB to int. We must close the application or we might have undetected gaps.")
|
||||
}
|
||||
if maxSlot != firstSlot-1 {
|
||||
if maxSlot < firstSlot-1 {
|
||||
if maxSlot == 0 {
|
||||
writeKnownGaps(db, tableIncrement, maxSlot, firstSlot-1, fmt.Errorf(""), "startup", metric)
|
||||
} else {
|
||||
writeKnownGaps(db, tableIncrement, maxSlot+1, firstSlot-1, fmt.Errorf(""), "startup", metric)
|
||||
}
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
"maxSlot": maxSlot,
|
||||
"firstSlot": firstSlot,
|
||||
}).Warn("The maxSlot in the DB is greater than or equal to the first Slot we are processing.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A function to update a knownGap range with a reprocessing error.
|
||||
func updateKnownGapErrors(db sql.Database, startSlot Slot, endSlot Slot, reprocessingErr error, metric *BeaconClientMetrics) error {
|
||||
res, err := db.Exec(context.Background(), UpsertKnownGapsErrorStmt, startSlot, endSlot, reprocessingErr.Error())
|
||||
if err != nil {
|
||||
loghelper.LogSlotRangeError(startSlot.Number(), endSlot.Number(), err).Error("Unable to update reprocessing_error")
|
||||
return err
|
||||
}
|
||||
row, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
loghelper.LogSlotRangeError(startSlot.Number(), endSlot.Number(), err).Error("Unable to count rows affected when trying to update reprocessing_error.")
|
||||
return err
|
||||
}
|
||||
if row != 1 {
|
||||
loghelper.LogSlotRangeError(startSlot.Number(), endSlot.Number(), err).WithFields(log.Fields{
|
||||
"rowCount": row,
|
||||
}).Error("The rows affected by the upsert for reprocessing_error is not 1.")
|
||||
metric.IncrementKnownGapsReprocessError(1)
|
||||
return err
|
||||
}
|
||||
metric.IncrementKnownGapsReprocessError(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// A quick helper function to calculate the epoch.
|
||||
func calculateEpoch(slot Slot, slotPerEpoch uint64) uint64 {
|
||||
return slot.Number() / slotPerEpoch
|
||||
}
|
||||
|
||||
// A helper function to check to see if the slot is processed.
|
||||
func isSlotProcessed(db sql.Database, checkProcessStmt string, slot Slot) (bool, error) {
|
||||
processRow, err := db.Exec(context.Background(), checkProcessStmt, slot)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
row, err := processRow.RowsAffected()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if row > 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Check to see if this slot is in the DB. Check eth_beacon.slots, eth_beacon.signed_block
|
||||
// and eth_beacon.state. If the slot exists, return true
|
||||
func IsSlotInDb(ctx context.Context, db sql.Database, slot Slot, blockRoot string, stateRoot string) (bool, error) {
|
||||
var (
|
||||
isInBeaconState bool
|
||||
isInSignedBeaconBlock bool
|
||||
)
|
||||
errG, _ := errgroup.WithContext(context.Background())
|
||||
errG.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
var err error
|
||||
isInBeaconState, err = checkSlotAndRoot(db, CheckBeaconStateStmt, slot, stateRoot)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to check if the slot and stateroot exist in eth_beacon.state")
|
||||
}
|
||||
return err
|
||||
}
|
||||
})
|
||||
errG.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
var err error
|
||||
isInSignedBeaconBlock, err = checkSlotAndRoot(db, CheckSignedBeaconBlockStmt, slot, blockRoot)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to check if the slot and block_root exist in eth_beacon.signed_block")
|
||||
}
|
||||
return err
|
||||
}
|
||||
})
|
||||
if err := errG.Wait(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if isInBeaconState && isInSignedBeaconBlock {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Provide a statement, slot, and root, and this function will check to see
|
||||
// if the slot and root exist in the table.
|
||||
func checkSlotAndRoot(db sql.Database, statement string, slot Slot, root string) (bool, error) {
|
||||
processRow, err := db.Exec(context.Background(), statement, slot, root)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
row, err := processRow.RowsAffected()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if row > 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package beaconclient_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/pkg/errors"
|
||||
zcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
"github.com/protolambda/zrnt/eth2/configs"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ = Describe("e2emerge", Label("e2e"), func() {
|
||||
e2eConfig := TestConfig
|
||||
e2eConfig.port = 5052
|
||||
e2eConfig.performBeaconStateProcessing = false
|
||||
e2eConfig.performBeaconBlockProcessing = true
|
||||
|
||||
level, _ := log.ParseLevel("debug")
|
||||
log.SetLevel(level)
|
||||
|
||||
Describe("Run the application against a Merge testnet", func() {
|
||||
Context("When we send a TX to geth", func() {
|
||||
It("We should see the TX included in the ExecutionPayload of a BeaconBlock", func() {
|
||||
bc := setUpTest(e2eConfig, "0")
|
||||
go bc.CaptureHead()
|
||||
|
||||
tx, _ := sendTestTx()
|
||||
beaconBlock := waitForTxToBeIndexed(bc.Db, tx)
|
||||
Expect(beaconBlock).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
type SentTx struct {
|
||||
hash string
|
||||
raw []byte
|
||||
blockNo uint64
|
||||
blockHash string
|
||||
txIndex uint
|
||||
}
|
||||
|
||||
func (tx *SentTx) RawHex() string {
|
||||
return "0x" + hex.EncodeToString(tx.raw)
|
||||
}
|
||||
|
||||
func waitForTxToBeIndexed(db sql.Database, tx *SentTx) *beaconclient.DbSignedBeaconBlock {
|
||||
var beaconBlock *beaconclient.DbSignedBeaconBlock = nil
|
||||
for i := 0; i < 30; i++ {
|
||||
time.Sleep(time.Second)
|
||||
record := lookForTxInDb(db, tx)
|
||||
if nil != record {
|
||||
beaconBlock = record
|
||||
log.Debugf("Found ETH1 TX %s in SignedBeaconBlock %d/%s", tx.hash, beaconBlock.Slot, beaconBlock.BlockRoot)
|
||||
break
|
||||
}
|
||||
}
|
||||
return beaconBlock
|
||||
}
|
||||
|
||||
func lookForTxInDb(db sql.Database, tx *SentTx) *beaconclient.DbSignedBeaconBlock {
|
||||
sqlStatement := `SELECT * FROM eth_beacon.signed_block WHERE
|
||||
payload_block_number = $1 AND
|
||||
payload_block_hash = $2 AND
|
||||
payload_transactions_root = $3`
|
||||
|
||||
// We can pre-calculate the root and query on it because we are only sending a single TX at a time.
|
||||
// Otherwise we would need to lookup the root by block num+hash, then do a proof that its txs
|
||||
// root includes our TX.
|
||||
var ptxs = zcommon.PayloadTransactions{tx.raw}
|
||||
txRoot := ptxs.HashTreeRoot(configs.Mainnet, tree.GetHashFn())
|
||||
|
||||
var slot uint64
|
||||
var blockRoot, parentBlock, eth1DataBlockHash, mhKey string
|
||||
|
||||
var blockNumber, timestamp uint64
|
||||
var blockHash, parentHash, stateRoot, receiptsRoot, transactionsRoot string
|
||||
|
||||
err := db.
|
||||
QueryRow(context.Background(), sqlStatement, tx.blockNo, tx.blockHash, "0x"+hex.EncodeToString(txRoot[:])).
|
||||
Scan(&slot, &blockRoot, &parentBlock, ð1DataBlockHash, &mhKey,
|
||||
&blockNumber, ×tamp, &blockHash, &parentHash, &stateRoot,
|
||||
&receiptsRoot, &transactionsRoot)
|
||||
if nil != err {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &beaconclient.DbSignedBeaconBlock{
|
||||
Slot: slot,
|
||||
BlockRoot: blockRoot,
|
||||
ParentBlock: parentBlock,
|
||||
Eth1DataBlockHash: eth1DataBlockHash,
|
||||
MhKey: mhKey,
|
||||
ExecutionPayloadHeader: &beaconclient.DbExecutionPayloadHeader{
|
||||
BlockNumber: blockNumber,
|
||||
Timestamp: timestamp,
|
||||
BlockHash: blockHash,
|
||||
ParentHash: parentHash,
|
||||
StateRoot: stateRoot,
|
||||
ReceiptsRoot: receiptsRoot,
|
||||
TransactionsRoot: transactionsRoot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sendTestTx() (*SentTx, error) {
|
||||
ctx := context.Background()
|
||||
eth, err := createClient()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
//TODO: Pull from test config / env.
|
||||
tx, err := sendTransaction(
|
||||
ctx,
|
||||
eth,
|
||||
"0xe6ce22afe802caf5ff7d3845cec8c736ecc8d61f",
|
||||
"0xe22AD83A0dE117bA0d03d5E94Eb4E0d80a69C62a",
|
||||
10,
|
||||
"0x888814df89c4358d7ddb3fa4b0213e7331239a80e1f013eaa7b2deca2a41a218",
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
txBin, err := tx.MarshalBinary()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
for i := 0; i <= 30; i++ {
|
||||
time.Sleep(time.Second)
|
||||
receipt, _ := eth.TransactionReceipt(ctx, tx.Hash())
|
||||
if nil != receipt {
|
||||
sentTx := &SentTx{
|
||||
hash: tx.Hash().String(),
|
||||
raw: txBin,
|
||||
blockNo: receipt.BlockNumber.Uint64(),
|
||||
blockHash: receipt.BlockHash.String(),
|
||||
txIndex: receipt.TransactionIndex,
|
||||
}
|
||||
log.Debugf("Sent ETH1 TX %s (Block No: %d, Block Hash: %s)", sentTx.hash, sentTx.blockNo, sentTx.blockHash)
|
||||
return sentTx, nil
|
||||
}
|
||||
}
|
||||
|
||||
err = errors.New("Timed out waiting for TX.")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func createClient() (*ethclient.Client, error) {
|
||||
return ethclient.Dial("http://localhost:8545")
|
||||
}
|
||||
|
||||
// sendTransaction sends a transaction with 1 ETH to a specified address.
|
||||
func sendTransaction(ctx context.Context, eth *ethclient.Client, fromAddr string, toAddr string, amount int64, signingKey string) (*types.Transaction, error) {
|
||||
var (
|
||||
from = common.HexToAddress(fromAddr)
|
||||
to = common.HexToAddress(toAddr)
|
||||
sk = crypto.ToECDSAUnsafe(common.FromHex(signingKey))
|
||||
value = big.NewInt(amount)
|
||||
gasLimit = uint64(21000)
|
||||
)
|
||||
// Retrieve the chainid (needed for signer)
|
||||
chainid, err := eth.ChainID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Retrieve the pending nonce
|
||||
nonce, err := eth.PendingNonceAt(ctx, from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Get suggested gas price
|
||||
tipCap, _ := eth.SuggestGasTipCap(ctx)
|
||||
feeCap, _ := eth.SuggestGasPrice(ctx)
|
||||
// Create a new transaction
|
||||
tx := types.NewTx(
|
||||
&types.DynamicFeeTx{
|
||||
ChainID: chainid,
|
||||
Nonce: nonce,
|
||||
GasTipCap: tipCap,
|
||||
GasFeeCap: feeCap,
|
||||
Gas: gasLimit,
|
||||
To: &to,
|
||||
Value: value,
|
||||
Data: nil,
|
||||
})
|
||||
// Sign the transaction using our keys
|
||||
signedTx, _ := types.SignTx(tx, types.NewLondonSigner(chainid), sk)
|
||||
// Send the transaction to our node
|
||||
return signedTx, eth.SendTransaction(ctx, signedTx)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../external/eth2.0-spec-tests
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
@@ -5,7 +20,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// This function will ensure that we can connect to the beacon client.
|
||||
@@ -22,8 +37,8 @@ func (bc BeaconClient) CheckBeaconClient() error {
|
||||
}
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||
log.Error("We recieved a non 2xx status code when checking the health of the beacon node.")
|
||||
log.Error("Health Endpoint Status Code: ", resp.StatusCode)
|
||||
loghelper.LogEndpoint(bcEndpoint).Error("We recieved a non 2xx status code when checking the health of the beacon node.")
|
||||
loghelper.LogEndpoint(bcEndpoint).Error("Health Endpoint Status Code: ", resp.StatusCode)
|
||||
return fmt.Errorf("beacon Node Provided a non 2xx status code, code provided: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient_test
|
||||
|
||||
import (
|
||||
@@ -5,18 +20,26 @@ import (
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
beaconclient "github.com/vulcanize/ipld-ethcl-indexer/pkg/beaconclient"
|
||||
beaconclient "github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
)
|
||||
|
||||
var _ = Describe("Healthcheck", func() {
|
||||
var (
|
||||
BC = beaconclient.CreateBeaconClient(context.Background(), "http", "localhost", 5052)
|
||||
errBc = beaconclient.CreateBeaconClient(context.Background(), "http", "blah-blah", 1010)
|
||||
Bc *beaconclient.BeaconClient
|
||||
errBc *beaconclient.BeaconClient
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
Bc, err = beaconclient.CreateBeaconClient(context.Background(), "http", "localhost", 5052, 10, bcUniqueIdentifier, false, true, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
errBc, err = beaconclient.CreateBeaconClient(context.Background(), "http", "blah-blah", 1010, 10, bcUniqueIdentifier, false, true, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
Describe("Connecting to the lighthouse client", Label("integration"), func() {
|
||||
Context("When the client is running", func() {
|
||||
It("We should connect successfully", func() {
|
||||
err := BC.CheckBeaconClient()
|
||||
err := Bc.CheckBeaconClient()
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This package will handle all event subscriptions that utilize SSE.
|
||||
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -17,27 +34,74 @@ var (
|
||||
// This function will capture all the SSE events for a given SseEvents object.
|
||||
// When new messages come in, it will ensure that they are decoded into JSON.
|
||||
// If any errors occur, it log the error information.
|
||||
func handleIncomingSseEvent[P ProcessedEvents](eventHandler *SseEvents[P]) {
|
||||
loghelper.LogEndpoint(eventHandler.Endpoint).Info("Subscribing to Messages")
|
||||
go eventHandler.SseClient.SubscribeChanRaw(eventHandler.MessagesCh)
|
||||
func handleIncomingSseEvent[P ProcessedEvents](eventHandler *SseEvents[P], errMetricInc func(uint64), idleTimeout time.Duration) {
|
||||
go func() {
|
||||
errG := new(errgroup.Group)
|
||||
errG.Go(func() error {
|
||||
err := eventHandler.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err := errG.Wait(); err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"endpoint": eventHandler.Endpoint,
|
||||
}).Error("Unable to subscribe to the SSE endpoint.")
|
||||
return
|
||||
} else {
|
||||
loghelper.LogEndpoint(eventHandler.Endpoint).Info("Successfully subscribed to the event stream.")
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
// TODO(telackey): Doesn't there need to be a check here that the handler hasn't been shutdown?
|
||||
for {
|
||||
var idleTimer *time.Timer = nil
|
||||
var idleTimerC <-chan time.Time = nil
|
||||
if idleTimeout > 0 {
|
||||
idleTimer = time.NewTimer(idleTimeout)
|
||||
idleTimerC = idleTimer.C
|
||||
}
|
||||
|
||||
select {
|
||||
case message := <-eventHandler.MessagesCh:
|
||||
if nil != idleTimer {
|
||||
idleTimer.Stop()
|
||||
}
|
||||
// Message can be nil if its a keep-alive message
|
||||
if len(message.Data) != 0 {
|
||||
log.WithFields(log.Fields{"msg": string(message.Data)}).Debug("We are going to send the following message to be processed.")
|
||||
go processMsg(message.Data, eventHandler.ProcessCh, eventHandler.ErrorCh)
|
||||
}
|
||||
|
||||
case headErr := <-eventHandler.ErrorCh:
|
||||
if nil != idleTimer {
|
||||
idleTimer.Stop()
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"endpoint": eventHandler.Endpoint,
|
||||
"err": headErr.err,
|
||||
"msg": headErr.msg,
|
||||
},
|
||||
).Error("Unable to handle event.")
|
||||
errMetricInc(1)
|
||||
|
||||
case process := <-eventHandler.ProcessCh:
|
||||
log.WithFields(log.Fields{"processed": process}).Debug("Processesing a Message")
|
||||
case <-idleTimerC:
|
||||
err := errors.New("SSE idle timeout")
|
||||
log.WithFields(log.Fields{
|
||||
"endpoint": eventHandler.Endpoint,
|
||||
"err": err,
|
||||
"msg": err.Error(),
|
||||
},
|
||||
).Error("TIMEOUT - Attempting to resubscribe")
|
||||
errMetricInc(1)
|
||||
eventHandler.Disconnect()
|
||||
err = eventHandler.Connect()
|
||||
if err != nil {
|
||||
log.Error("Unable to re-subscribe.", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +124,6 @@ func processMsg[P ProcessedEvents](msg []byte, processCh chan<- *P, errorCh chan
|
||||
// Capture all of the event topics.
|
||||
func (bc *BeaconClient) captureEventTopic() {
|
||||
log.Info("We are capturing all SSE events")
|
||||
go handleIncomingSseEvent(bc.HeadTracking)
|
||||
go handleIncomingSseEvent(bc.ReOrgTracking)
|
||||
go handleIncomingSseEvent(bc.FinalizationTracking)
|
||||
go handleIncomingSseEvent(bc.HeadTracking, bc.Metrics.IncrementHeadError, time.Second*30)
|
||||
go handleIncomingSseEvent(bc.ReOrgTracking, bc.Metrics.IncrementReorgError, 0)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// Create a metric struct and register each channel with prometheus
|
||||
func CreateBeaconClientMetrics() (*BeaconClientMetrics, error) {
|
||||
metrics := &BeaconClientMetrics{
|
||||
SlotInserts: 0,
|
||||
ReorgInserts: 0,
|
||||
KnownGapsInserts: 0,
|
||||
KnownGapsProcessed: 0,
|
||||
KnownGapsReprocessError: 0,
|
||||
HeadError: 0,
|
||||
HeadReorgError: 0,
|
||||
}
|
||||
err := prometheusRegisterHelper("slot_inserts", "Keeps track of the number of slots we have inserted.", &metrics.SlotInserts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = prometheusRegisterHelper("reorg_inserts", "Keeps track of the number of reorgs we have inserted.", &metrics.ReorgInserts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = prometheusRegisterHelper("known_gaps_inserts", "Keeps track of the number of known gaps we have inserted.", &metrics.KnownGapsInserts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = prometheusRegisterHelper("known_gaps_reprocess_error", "Keeps track of the number of known gaps that had errors when reprocessing, but the error was updated successfully.", &metrics.KnownGapsReprocessError)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = prometheusRegisterHelper("known_gaps_processed", "Keeps track of the number of known gaps we successfully processed.", &metrics.KnownGapsProcessed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = prometheusRegisterHelper("historic_slots_processed", "Keeps track of the number of historic slots we successfully processed.", &metrics.HistoricSlotProcessed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = prometheusRegisterHelper("head_error", "Keeps track of the number of errors we had processing head messages.", &metrics.HeadError)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = prometheusRegisterHelper("head_reorg_error", "Keeps track of the number of errors we had processing reorg messages.", &metrics.HeadReorgError)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
func prometheusRegisterHelper(name string, help string, varPointer *uint64) error {
|
||||
err := prometheus.Register(prometheus.NewCounterFunc(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: "beacon_client",
|
||||
Subsystem: "",
|
||||
Name: name,
|
||||
Help: help,
|
||||
ConstLabels: map[string]string{},
|
||||
},
|
||||
func() float64 {
|
||||
return float64(atomic.LoadUint64(varPointer))
|
||||
}))
|
||||
if err != nil && err.Error() != "duplicate metrics collector registration attempted" {
|
||||
loghelper.LogError(err).WithField("name", name).Error("Unable to register counter.")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A structure utilized for keeping track of various metrics. Currently, mostly used in testing.
|
||||
type BeaconClientMetrics struct {
|
||||
SlotInserts uint64 // Number of head events we successfully wrote to the DB.
|
||||
ReorgInserts uint64 // Number of reorg events we successfully wrote to the DB.
|
||||
KnownGapsInserts uint64 // Number of known_gaps we successfully wrote to the DB.
|
||||
KnownGapsProcessed uint64 // Number of knownGaps processed.
|
||||
KnownGapsReprocessError uint64 // Number of knownGaps that were updated with an error.
|
||||
HistoricSlotProcessed uint64 // Number of historic slots successfully processed.
|
||||
HeadError uint64 // Number of errors that occurred when decoding the head message.
|
||||
HeadReorgError uint64 // Number of errors that occurred when decoding the reorg message.
|
||||
}
|
||||
|
||||
// Wrapper function to increment inserts. If we want to use mutexes later we can easily update all
|
||||
// occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementSlotInserts(inc uint64) {
|
||||
log.Debug("Incrementing Slot Insert")
|
||||
atomic.AddUint64(&m.SlotInserts, inc)
|
||||
}
|
||||
|
||||
// Wrapper function to increment reorgs. If we want to use mutexes later we can easily update all
|
||||
// occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementReorgsInsert(inc uint64) {
|
||||
atomic.AddUint64(&m.ReorgInserts, inc)
|
||||
}
|
||||
|
||||
// Wrapper function to increment known gaps. If we want to use mutexes later we can easily update all
|
||||
// occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementKnownGapsInserts(inc uint64) {
|
||||
atomic.AddUint64(&m.KnownGapsInserts, inc)
|
||||
}
|
||||
|
||||
// Wrapper function to increment known gaps processed. If we want to use mutexes later we can easily update all
|
||||
// occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementKnownGapsProcessed(inc uint64) {
|
||||
atomic.AddUint64(&m.KnownGapsProcessed, inc)
|
||||
}
|
||||
|
||||
// Wrapper function to increment head errors. If we want to use mutexes later we can easily update all
|
||||
// occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementHeadError(inc uint64) {
|
||||
atomic.AddUint64(&m.HeadError, inc)
|
||||
}
|
||||
|
||||
// Wrapper function to increment reorg errors. If we want to use mutexes later we can easily update all
|
||||
// occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementReorgError(inc uint64) {
|
||||
atomic.AddUint64(&m.HeadReorgError, inc)
|
||||
}
|
||||
|
||||
// Wrapper function to increment the number of knownGaps that were updated with reprocessing errors.
|
||||
// If we want to use mutexes later we can easily update all occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementKnownGapsReprocessError(inc uint64) {
|
||||
atomic.AddUint64(&m.KnownGapsReprocessError, inc)
|
||||
}
|
||||
|
||||
// Wrapper function to increment the number of historicSlots that were processed successfully.
|
||||
// If we want to use mutexes later we can easily update all occurrences here.
|
||||
func (m *BeaconClientMetrics) IncrementHistoricSlotProcessed(inc uint64) {
|
||||
atomic.AddUint64(&m.HistoricSlotProcessed, inc)
|
||||
}
|
||||
@@ -1,8 +1,23 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient
|
||||
|
||||
// This interface captured what the events can be for processed event streams.
|
||||
type ProcessedEvents interface {
|
||||
Head | FinalizedCheckpoint | ChainReorg
|
||||
Head | ChainReorg
|
||||
}
|
||||
|
||||
// This struct captures the JSON representation of the head topic
|
||||
@@ -35,3 +50,51 @@ type ChainReorg struct {
|
||||
Epoch string `json:"epoch"`
|
||||
ExecutionOptimistic bool `json:"execution_optimistic"`
|
||||
}
|
||||
|
||||
// A struct to capture whats being written to the eth-beacon.slots table.
|
||||
type DbSlots struct {
|
||||
Epoch uint64 // The epoch.
|
||||
Slot uint64 // The slot.
|
||||
BlockRoot string // The block root
|
||||
StateRoot string // The state root
|
||||
Status string // The status, it can be proposed | forked | skipped.
|
||||
}
|
||||
|
||||
// A struct to handle the details of an embedded Eth1-block (ie, the ExecutionPayload)
|
||||
type DbExecutionPayloadHeader struct {
|
||||
BlockNumber uint64
|
||||
Timestamp uint64
|
||||
BlockHash string
|
||||
ParentHash string
|
||||
StateRoot string
|
||||
ReceiptsRoot string
|
||||
TransactionsRoot string
|
||||
}
|
||||
|
||||
// A struct to capture whats being written to eth-beacon.signed_block table.
|
||||
type DbSignedBeaconBlock struct {
|
||||
Slot uint64 // The slot.
|
||||
BlockRoot string // The block root
|
||||
ParentBlock string // The parent block root.
|
||||
Eth1DataBlockHash string // The eth1 block_hash
|
||||
MhKey string // The ipld multihash key.
|
||||
ExecutionPayloadHeader *DbExecutionPayloadHeader // The ExecutionPayloadHeader (after Bellatrix only).
|
||||
}
|
||||
|
||||
// A struct to capture whats being written to eth-beacon.state table.
|
||||
type DbBeaconState struct {
|
||||
Slot uint64 // The slot.
|
||||
StateRoot string // The state root
|
||||
MhKey string // The ipld multihash key.
|
||||
}
|
||||
|
||||
// A structure to capture whats being written to the eth-beacon.known_gaps table.
|
||||
type DbKnownGaps struct {
|
||||
StartSlot uint64 // The start slot for known_gaps, inclusive.
|
||||
EndSlot uint64 // The end slot for known_gaps, inclusive.
|
||||
CheckedOut bool // Indicates if any process is currently processing this entry.
|
||||
ReprocessingError string // The error that occurred when attempting to reprocess these entries.
|
||||
EntryError string // The error that caused this entry to be added to the table. Could be null.
|
||||
EntryTime string // The time this range was added to the DB. This can help us catch ranges that have not been processed for a long time due to some error.
|
||||
EntryProcess string // The entry process that added this process. Potential options are StartUp, Error, ManualEntry, HeadGap.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
dshelp "github.com/ipfs/go-ipfs-ds-help"
|
||||
"github.com/multiformats/go-multihash"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
const SSZ_SHA2_256_PREFIX uint64 = 0xb502
|
||||
|
||||
// MultihashKeyFromSSZRoot converts a SSZ-SHA2-256 root hash into a blockstore prefixed multihash key
|
||||
func MultihashKeyFromSSZRoot(root []byte) (string, error) {
|
||||
mh, err := multihash.Encode(root, SSZ_SHA2_256_PREFIX)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to create a multihash Key")
|
||||
return "", err
|
||||
}
|
||||
dbKey := dshelp.MultihashToDsKey(mh)
|
||||
mhKey := blockstore.BlockPrefix.String() + dbKey.String()
|
||||
log.WithFields(log.Fields{"mhKey": mhKey, "len": len(root)}).Debug("The MHKEY")
|
||||
return mhKey, nil
|
||||
}
|
||||
@@ -1,38 +1,80 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This file contains all the functions to handle SSE events after they have been turned
|
||||
// to the structs.
|
||||
|
||||
package beaconclient
|
||||
|
||||
import log "github.com/sirupsen/logrus"
|
||||
import (
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// This function will perform the necessary steps to handle a reorg.
|
||||
func (bc *BeaconClient) handleReorgs() {
|
||||
func (bc *BeaconClient) handleReorg() {
|
||||
log.Info("Starting to process reorgs.")
|
||||
for {
|
||||
// We will add real functionality later
|
||||
reorg := <-bc.ReOrgTracking.ProcessCh
|
||||
log.WithFields(log.Fields{"reorg": reorg}).Debug("Received a new reorg message.")
|
||||
slot, err := ParseSlot(reorg.Slot)
|
||||
if nil != err {
|
||||
loghelper.LogSlotError(slot.Number(), err)
|
||||
}
|
||||
writeReorgs(bc.Db, slot, reorg.NewHeadBlock, bc.Metrics)
|
||||
}
|
||||
}
|
||||
|
||||
// This function will perform the necessary steps to handle a reorg.
|
||||
func (bc *BeaconClient) handleFinalizedCheckpoint() {
|
||||
log.Info("Starting to process finalized checkpoints.")
|
||||
for {
|
||||
// We will add real functionality later
|
||||
finalized := <-bc.ReOrgTracking.ProcessCh
|
||||
log.WithFields(log.Fields{"finalized": finalized}).Debug("Received a new finalized checkpoint.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This function will handle the latest head event.
|
||||
func (bc *BeaconClient) handleHead() {
|
||||
log.Info("Starting to process head.")
|
||||
errorSlots := 0
|
||||
for {
|
||||
// We will add real functionality later
|
||||
head := <-bc.ReOrgTracking.ProcessCh
|
||||
log.WithFields(log.Fields{"head": head}).Debug("Received a new head event.")
|
||||
}
|
||||
head := <-bc.HeadTracking.ProcessCh
|
||||
// Process all the work here.
|
||||
slot, err := ParseSlot(head.Slot)
|
||||
if err != nil {
|
||||
bc.HeadTracking.ErrorCh <- &SseError{
|
||||
err: fmt.Errorf("Unable to turn the slot from string to int: %s", head.Slot),
|
||||
}
|
||||
errorSlots = errorSlots + 1
|
||||
continue
|
||||
}
|
||||
if errorSlots != 0 && bc.PreviousSlot != 0 {
|
||||
log.WithFields(log.Fields{
|
||||
"lastProcessedSlot": bc.PreviousSlot,
|
||||
"errorSlots": errorSlots,
|
||||
}).Warn("We added slots to the knownGaps table because we got bad head messages.")
|
||||
writeKnownGaps(bc.Db, bc.KnownGapTableIncrement, bc.PreviousSlot+1, slot, fmt.Errorf("Bad Head Messages"), "headProcessing", bc.Metrics)
|
||||
errorSlots = 0
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{"head": head}).Debug("We are going to start processing the slot.")
|
||||
|
||||
// Not used anywhere yet but might be useful to have.
|
||||
if bc.PreviousSlot == 0 && bc.PreviousBlockRoot == "" {
|
||||
bc.StartingSlot = slot
|
||||
}
|
||||
|
||||
go processHeadSlot(slot, head.Block, head.State, bc.SlotProcessingDetails())
|
||||
|
||||
log.WithFields(log.Fields{"head": head.Slot}).Debug("We finished calling processHeadSlot.")
|
||||
|
||||
// Update the previous block
|
||||
bc.PreviousSlot = slot
|
||||
bc.PreviousBlockRoot = head.Block
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// This file contains all the code to process historic slots.
|
||||
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
var (
|
||||
// Get a single highest priority and non-checked out row row from eth_beacon.historical_process
|
||||
getHpEntryStmt string = `SELECT start_slot, end_slot FROM eth_beacon.historic_process
|
||||
WHERE checked_out=false AND end_slot >= $1
|
||||
ORDER BY priority ASC
|
||||
LIMIT 1;`
|
||||
// Used to periodically check to see if there is a new entry in the eth_beacon.historic_process table.
|
||||
checkHpEntryStmt string = `SELECT * FROM eth_beacon.historic_process WHERE checked_out=false AND end_slot >= $1;`
|
||||
// Used to checkout a row from the eth_beacon.historic_process table
|
||||
lockHpEntryStmt string = `UPDATE eth_beacon.historic_process
|
||||
SET checked_out=true, checked_out_by=$3
|
||||
WHERE start_slot=$1 AND end_slot=$2;`
|
||||
// Used to delete an entry from the eth_beacon.historic_process table
|
||||
deleteHpEntryStmt string = `DELETE FROM eth_beacon.historic_process
|
||||
WHERE start_slot=$1 AND end_slot=$2;`
|
||||
// Used to update every single row that this node has checked out.
|
||||
releaseHpLockStmt string = `UPDATE eth_beacon.historic_process
|
||||
SET checked_out=false, checked_out_by=null
|
||||
WHERE checked_out_by=$1`
|
||||
)
|
||||
|
||||
type HistoricProcessing struct {
|
||||
db sql.Database //db connection
|
||||
metrics *BeaconClientMetrics // metrics for beaconclient
|
||||
uniqueNodeIdentifier int // node unique identifier.
|
||||
}
|
||||
|
||||
// Get a single row of historical slots from the table.
|
||||
func (hp HistoricProcessing) getSlotRange(ctx context.Context, slotCh chan<- slotsToProcess, minimumSlot Slot) []error {
|
||||
return getBatchProcessRow(ctx, hp.db, getHpEntryStmt, checkHpEntryStmt, lockHpEntryStmt, slotCh, strconv.Itoa(hp.uniqueNodeIdentifier), minimumSlot)
|
||||
}
|
||||
|
||||
// Remove the table entry.
|
||||
func (hp HistoricProcessing) removeTableEntry(ctx context.Context, processCh <-chan slotsToProcess) error {
|
||||
return removeRowPostProcess(ctx, hp.db, processCh, QueryBySlotStmt, deleteHpEntryStmt)
|
||||
}
|
||||
|
||||
// Remove the table entry.
|
||||
func (hp HistoricProcessing) handleProcessingErrors(ctx context.Context, errMessages <-chan batchHistoricError) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case errMs := <-errMessages:
|
||||
loghelper.LogSlotError(errMs.slot.Number(), errMs.err)
|
||||
writeKnownGaps(hp.db, 1, errMs.slot, errMs.slot, errMs.err, errMs.errProcess, hp.metrics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "un"-checkout the rows held by this DB in the eth_beacon.historical_process table.
|
||||
func (hp HistoricProcessing) releaseDbLocks() error {
|
||||
log.Debug("Updating all the entries to eth_beacon.historical processing")
|
||||
res, err := hp.db.Exec(context.Background(), releaseHpLockStmt, hp.uniqueNodeIdentifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to remove lock from eth_beacon.historical_processing table for node %d, error is %e", hp.uniqueNodeIdentifier, err)
|
||||
}
|
||||
log.Debug("Update all the entries to eth_beacon.historical processing")
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to calculated number of rows affected by releasing locks from eth_beacon.historical_processing table for node %d, error is %e", hp.uniqueNodeIdentifier, err)
|
||||
}
|
||||
log.WithField("rowCount", rows).Info("Released historicalProcess locks for specified rows.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process the slot range.
|
||||
func processSlotRangeWorker(ctx context.Context, workCh <-chan Slot, errCh chan<- batchHistoricError, spd SlotProcessingDetails, incrementTracker func(uint64)) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case slot := <-workCh:
|
||||
log.Debug("Handling slot: ", slot)
|
||||
err, errProcess := handleHistoricSlot(ctx, slot, spd)
|
||||
if err != nil {
|
||||
errMs := batchHistoricError{
|
||||
err: err,
|
||||
errProcess: errProcess,
|
||||
slot: slot,
|
||||
}
|
||||
errCh <- errMs
|
||||
} else {
|
||||
incrementTracker(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper function that insert the start_slot and end_slot from a single row into a channel.
|
||||
// It also locks the row by updating the checked_out column.
|
||||
// The statement for getting the start_slot and end_slot must be provided.
|
||||
// The statement for "locking" the row must also be provided.
|
||||
func getBatchProcessRow(ctx context.Context, db sql.Database, getStartEndSlotStmt string, checkNewRowsStmt string, checkOutRowStmt string, slotCh chan<- slotsToProcess, uniqueNodeIdentifier string, minimumSlot Slot) []error {
|
||||
errCount := make([]error, 0)
|
||||
|
||||
// 5 is an arbitrary number. It allows us to retry a few times before
|
||||
// ending the application.
|
||||
prevErrCount := 0
|
||||
for len(errCount) < 5 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errCount
|
||||
default:
|
||||
if len(errCount) != prevErrCount {
|
||||
log.WithFields(log.Fields{
|
||||
"errCount": errCount,
|
||||
}).Error("New error entry added")
|
||||
}
|
||||
processRow, err := db.Exec(context.Background(), checkNewRowsStmt, minimumSlot)
|
||||
if err != nil {
|
||||
errCount = append(errCount, err)
|
||||
}
|
||||
row, err := processRow.RowsAffected()
|
||||
if err != nil {
|
||||
errCount = append(errCount, err)
|
||||
}
|
||||
if row < 1 {
|
||||
time.Sleep(3 * time.Second)
|
||||
log.Debug("We are checking rows, be patient")
|
||||
break
|
||||
}
|
||||
log.Debug("We found a new row")
|
||||
dbCtx := context.Background()
|
||||
|
||||
// Setup TX
|
||||
tx, err := db.Begin(dbCtx)
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("We are unable to Begin a SQL transaction")
|
||||
errCount = append(errCount, err)
|
||||
break
|
||||
}
|
||||
defer func() {
|
||||
err := tx.Rollback(dbCtx)
|
||||
if err != nil && err != pgx.ErrTxClosed {
|
||||
loghelper.LogError(err).Error("We were unable to Rollback a transaction")
|
||||
errCount = append(errCount, err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Query the DB for slots.
|
||||
sp := slotsToProcess{}
|
||||
err = tx.QueryRow(dbCtx, getStartEndSlotStmt, minimumSlot).Scan(&sp.startSlot, &sp.endSlot)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
time.Sleep(1 * time.Second)
|
||||
break
|
||||
}
|
||||
loghelper.LogSlotRangeStatementError(sp.startSlot.Number(), sp.endSlot.Number(), getStartEndSlotStmt, err).Error("Unable to get a row")
|
||||
errCount = append(errCount, err)
|
||||
break
|
||||
}
|
||||
|
||||
// Checkout the Row
|
||||
res, err := tx.Exec(dbCtx, checkOutRowStmt, sp.startSlot, sp.endSlot, uniqueNodeIdentifier)
|
||||
if err != nil {
|
||||
loghelper.LogSlotRangeStatementError(sp.startSlot.Number(), sp.endSlot.Number(), checkOutRowStmt, err).Error("Unable to checkout the row")
|
||||
errCount = append(errCount, err)
|
||||
break
|
||||
}
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
loghelper.LogSlotRangeStatementError(sp.startSlot.Number(), sp.endSlot.Number(), checkOutRowStmt, fmt.Errorf("Unable to determine the rows affected when trying to checkout a row."))
|
||||
errCount = append(errCount, err)
|
||||
break
|
||||
}
|
||||
if rows > 1 {
|
||||
loghelper.LogSlotRangeStatementError(sp.startSlot.Number(), sp.endSlot.Number(), checkOutRowStmt, err).WithFields(log.Fields{
|
||||
"rowsReturn": rows,
|
||||
}).Error("We locked too many rows.....")
|
||||
errCount = append(errCount, err)
|
||||
break
|
||||
}
|
||||
if rows == 0 {
|
||||
loghelper.LogSlotRangeStatementError(sp.startSlot.Number(), sp.endSlot.Number(), checkOutRowStmt, err).WithFields(log.Fields{
|
||||
"rowsReturn": rows,
|
||||
}).Error("We did not lock a single row.")
|
||||
errCount = append(errCount, err)
|
||||
break
|
||||
}
|
||||
err = tx.Commit(dbCtx)
|
||||
if err != nil {
|
||||
loghelper.LogSlotRangeError(sp.startSlot.Number(), sp.endSlot.Number(), err).Error("Unable commit transactions.")
|
||||
errCount = append(errCount, err)
|
||||
break
|
||||
}
|
||||
log.WithField("slots", sp).Debug("Added a new slots to be processed")
|
||||
slotCh <- sp
|
||||
}
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"ErrCount": errCount,
|
||||
}).Error("The ErrCounter")
|
||||
return errCount
|
||||
}
|
||||
|
||||
// After a row has been processed it should be removed from its appropriate table.
|
||||
func removeRowPostProcess(ctx context.Context, db sql.Database, processCh <-chan slotsToProcess, checkProcessedStmt, removeStmt string) error {
|
||||
errCh := make(chan error)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case slots := <-processCh:
|
||||
// Make sure the start and end slot exist in the slots table.
|
||||
go func() {
|
||||
log.WithFields(log.Fields{
|
||||
"startSlot": slots.startSlot,
|
||||
"endSlot": slots.endSlot,
|
||||
}).Debug("Starting to check to see if the following slots have been processed")
|
||||
for {
|
||||
isStartProcess, err := isSlotProcessed(db, checkProcessedStmt, slots.startSlot)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
isEndProcess, err := isSlotProcessed(db, checkProcessedStmt, slots.endSlot)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
if isStartProcess && isEndProcess {
|
||||
break
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
_, err := db.Exec(context.Background(), removeStmt, slots.startSlot.Number(), slots.endSlot.Number())
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
|
||||
}()
|
||||
if len(errCh) != 0 {
|
||||
return <-errCh
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// This file contains all the code to process historic slots.
|
||||
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
var (
|
||||
// Get a single non-checked out row row from eth_beacon.known_gaps.
|
||||
getKgEntryStmt string = `SELECT start_slot, end_slot FROM eth_beacon.known_gaps
|
||||
WHERE checked_out=false AND end_slot >= $1
|
||||
ORDER BY priority ASC
|
||||
LIMIT 1;`
|
||||
// Used to periodically check to see if there is a new entry in the eth_beacon.known_gaps table.
|
||||
checkKgEntryStmt string = `SELECT * FROM eth_beacon.known_gaps WHERE checked_out=false AND end_slot >= $1;`
|
||||
// Used to checkout a row from the eth_beacon.known_gaps table
|
||||
lockKgEntryStmt string = `UPDATE eth_beacon.known_gaps
|
||||
SET checked_out=true, checked_out_by=$3
|
||||
WHERE start_slot=$1 AND end_slot=$2;`
|
||||
// Used to delete an entry from the knownGaps table
|
||||
deleteKgEntryStmt string = `DELETE FROM eth_beacon.known_gaps
|
||||
WHERE start_slot=$1 AND end_slot=$2;`
|
||||
// Used to check to see if a single slot exists in the known_gaps table.
|
||||
checkKgSingleSlotStmt string = `SELECT start_slot, end_slot FROM eth_beacon.known_gaps
|
||||
WHERE start_slot=$1 AND end_slot=$2;`
|
||||
// Used to update every single row that this node has checked out.
|
||||
releaseKgLockStmt string = `UPDATE eth_beacon.known_gaps
|
||||
SET checked_out=false, checked_out_by=null
|
||||
WHERE checked_out_by=$1`
|
||||
)
|
||||
|
||||
type KnownGapsProcessing struct {
|
||||
db sql.Database //db connection
|
||||
metrics *BeaconClientMetrics // metrics for beaconclient
|
||||
uniqueNodeIdentifier int // node unique identifier.
|
||||
}
|
||||
|
||||
// This function will perform all the heavy lifting for tracking the head of the chain.
|
||||
func (bc *BeaconClient) ProcessKnownGaps(ctx context.Context, maxWorkers int, minimumSlot Slot) []error {
|
||||
log.Info("We are starting the known gaps processing service.")
|
||||
bc.KnownGapsProcess = KnownGapsProcessing{db: bc.Db, uniqueNodeIdentifier: bc.UniqueNodeIdentifier, metrics: bc.Metrics}
|
||||
errs := handleBatchProcess(ctx, maxWorkers, bc.KnownGapsProcess, bc.SlotProcessingDetails(), bc.Metrics.IncrementKnownGapsProcessed, minimumSlot)
|
||||
log.Debug("Exiting known gaps processing service")
|
||||
return errs
|
||||
}
|
||||
|
||||
// This function will perform all the necessary clean up tasks for stopping historical processing.
|
||||
func (bc *BeaconClient) StopKnownGapsProcessing(cancel context.CancelFunc) error {
|
||||
log.Info("We are stopping the known gaps processing service.")
|
||||
cancel()
|
||||
err := bc.KnownGapsProcess.releaseDbLocks()
|
||||
if err != nil {
|
||||
loghelper.LogError(err).WithField("uniqueIdentifier", bc.UniqueNodeIdentifier).Error("We were unable to remove the locks from the eth_beacon.known_gaps table. Manual Intervention is needed!")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get a single row of historical slots from the table.
|
||||
func (kgp KnownGapsProcessing) getSlotRange(ctx context.Context, slotCh chan<- slotsToProcess, minimumSlot Slot) []error {
|
||||
return getBatchProcessRow(ctx, kgp.db, getKgEntryStmt, checkKgEntryStmt, lockKgEntryStmt, slotCh, strconv.Itoa(kgp.uniqueNodeIdentifier), minimumSlot)
|
||||
}
|
||||
|
||||
// Remove the table entry.
|
||||
func (kgp KnownGapsProcessing) removeTableEntry(ctx context.Context, processCh <-chan slotsToProcess) error {
|
||||
return removeRowPostProcess(ctx, kgp.db, processCh, QueryBySlotStmt, deleteKgEntryStmt)
|
||||
}
|
||||
|
||||
// Remove the table entry.
|
||||
func (kgp KnownGapsProcessing) handleProcessingErrors(ctx context.Context, errMessages <-chan batchHistoricError) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case errMs := <-errMessages:
|
||||
// Check to see if this if this entry already exists.
|
||||
res, err := kgp.db.Exec(context.Background(), checkKgSingleSlotStmt, errMs.slot, errMs.slot)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(errMs.slot.Number(), err).Error("Unable to see if this slot is in the eth_beacon.known_gaps table")
|
||||
}
|
||||
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(errMs.slot.Number(), err).WithFields(log.Fields{
|
||||
"queryStatement": checkKgSingleSlotStmt,
|
||||
}).Error("Unable to get the number of rows affected by this statement.")
|
||||
}
|
||||
|
||||
if rows > 0 {
|
||||
loghelper.LogSlotError(errMs.slot.Number(), errMs.err).Error("We received an error when processing a knownGap")
|
||||
err = updateKnownGapErrors(kgp.db, errMs.slot, errMs.slot, errMs.err, kgp.metrics)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(errMs.slot.Number(), err).Error("Error processing known gap")
|
||||
}
|
||||
} else {
|
||||
writeKnownGaps(kgp.db, 1, errMs.slot, errMs.slot, errMs.err, errMs.errProcess, kgp.metrics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Updated checked_out column for the uniqueNodeIdentifier.
|
||||
func (kgp KnownGapsProcessing) releaseDbLocks() error {
|
||||
log.Debug("Updating all the entries to eth_beacon.known_gaps")
|
||||
res, err := kgp.db.Exec(context.Background(), releaseKgLockStmt, kgp.uniqueNodeIdentifier)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.WithField("rowCount", rows).Info("Released knownGaps locks for specified rows.")
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This file will keep track of all the code needed to process a slot.
|
||||
// To process a slot, it should have all the necessary data needed to write it to the DB.
|
||||
// But not actually write it.
|
||||
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type SlotProcessingDetails struct {
|
||||
Context context.Context // A context generic context with multiple uses.
|
||||
ServerEndpoint string // What is the endpoint of the beacon server.
|
||||
Db sql.Database // Database object used for reads and writes.
|
||||
Metrics *BeaconClientMetrics // An object used to keep track of certain BeaconClient Metrics.
|
||||
KnownGapTableIncrement int // The max number of slots within a single known_gaps table entry.
|
||||
CheckDb bool // Should we check the DB to see if the slot exists before processing it?
|
||||
PerformBeaconStateProcessing bool // Should we process BeaconStates?
|
||||
PerformBeaconBlockProcessing bool // Should we process BeaconBlocks?
|
||||
|
||||
StartingSlot Slot // If we're performing head tracking. What is the first slot we processed.
|
||||
PreviousSlot Slot // Whats the previous slot we processed
|
||||
PreviousBlockRoot string // Whats the previous block root, used to check the next blocks parent.
|
||||
}
|
||||
|
||||
func (bc *BeaconClient) SlotProcessingDetails() SlotProcessingDetails {
|
||||
return SlotProcessingDetails{
|
||||
Context: bc.Context,
|
||||
ServerEndpoint: bc.ServerEndpoint,
|
||||
Db: bc.Db,
|
||||
Metrics: bc.Metrics,
|
||||
|
||||
CheckDb: bc.CheckDb,
|
||||
PerformBeaconBlockProcessing: bc.PerformBeaconBlockProcessing,
|
||||
PerformBeaconStateProcessing: bc.PerformBeaconStateProcessing,
|
||||
|
||||
KnownGapTableIncrement: bc.KnownGapTableIncrement,
|
||||
StartingSlot: bc.StartingSlot,
|
||||
PreviousSlot: bc.PreviousSlot,
|
||||
PreviousBlockRoot: bc.PreviousBlockRoot,
|
||||
}
|
||||
}
|
||||
|
||||
type ProcessSlot struct {
|
||||
// Generic
|
||||
|
||||
Slot Slot // The slot number.
|
||||
Epoch Epoch // The epoch number.
|
||||
BlockRoot string // The hex encoded string of the BlockRoot.
|
||||
StateRoot string // The hex encoded string of the StateRoot.
|
||||
ParentBlockRoot string // The hex encoded string of the parent block.
|
||||
Status string // The status of the block
|
||||
HeadOrHistoric string // Is this the head or a historic slot. This is critical when trying to analyze errors and skipped slots.
|
||||
Db sql.Database // The DB object used to write to the DB.
|
||||
Metrics *BeaconClientMetrics // An object to keep track of the beaconclient metrics
|
||||
PerformanceMetrics PerformanceMetrics // An object to keep track of performance metrics.
|
||||
// BeaconBlock
|
||||
|
||||
SszSignedBeaconBlock []byte // The entire SSZ encoded SignedBeaconBlock
|
||||
FullSignedBeaconBlock *SignedBeaconBlock // The unmarshaled BeaconState object, the unmarshalling could have errors.
|
||||
|
||||
// BeaconState
|
||||
FullBeaconState *BeaconState // The unmarshaled BeaconState object, the unmarshalling could have errors.
|
||||
SszBeaconState []byte // The entire SSZ encoded BeaconState
|
||||
|
||||
// DB Write objects
|
||||
DbSlotsModel *DbSlots // The model being written to the slots table.
|
||||
DbSignedBeaconBlockModel *DbSignedBeaconBlock // The model being written to the signed_block table.
|
||||
DbBeaconState *DbBeaconState // The model being written to the state table.
|
||||
}
|
||||
|
||||
type PerformanceMetrics struct {
|
||||
BeaconNodeBlockRetrievalTime time.Duration // How long it took to get the BeaconBlock from the Beacon Node.
|
||||
BeaconNodeStateRetrievalTime time.Duration // How long it took to get the BeaconState from the Beacon Node.
|
||||
ParseBeaconObjectForHash time.Duration // How long it took to get some information from the beacon objects.
|
||||
CheckDbPreProcessing time.Duration // How long it takes to check the DB before processing a block.
|
||||
CreateDbWriteObject time.Duration // How long it takes to create a DB write object.
|
||||
TransactSlotOnly time.Duration // How long it takes to transact the slot information only.
|
||||
CheckReorg time.Duration // How long it takes to check for Reorgs
|
||||
CommitTransaction time.Duration // How long it takes to commit the final transaction.
|
||||
TotalDbTransaction time.Duration // How long it takes from start to committing the entire DB transaction.
|
||||
TotalProcessing time.Duration // How long it took to process the entire slot.
|
||||
}
|
||||
|
||||
// This function will do all the work to process the slot and write it to the DB.
|
||||
// It will return the error and error process. The error process is used for providing reach detail to the
|
||||
// known_gaps table.
|
||||
func processFullSlot(
|
||||
ctx context.Context,
|
||||
slot Slot,
|
||||
blockRoot string,
|
||||
stateRoot string,
|
||||
previousSlot Slot,
|
||||
previousBlockRoot string,
|
||||
knownGapsTableIncrement int,
|
||||
headOrHistoric string,
|
||||
spd *SlotProcessingDetails) (error, string) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ""
|
||||
default:
|
||||
totalStart := time.Now()
|
||||
ps := &ProcessSlot{
|
||||
Slot: slot,
|
||||
BlockRoot: blockRoot,
|
||||
StateRoot: stateRoot,
|
||||
HeadOrHistoric: headOrHistoric,
|
||||
Db: spd.Db,
|
||||
Metrics: spd.Metrics,
|
||||
PerformanceMetrics: PerformanceMetrics{
|
||||
BeaconNodeBlockRetrievalTime: 0,
|
||||
BeaconNodeStateRetrievalTime: 0,
|
||||
ParseBeaconObjectForHash: 0,
|
||||
CheckDbPreProcessing: 0,
|
||||
CreateDbWriteObject: 0,
|
||||
TransactSlotOnly: 0,
|
||||
CheckReorg: 0,
|
||||
CommitTransaction: 0,
|
||||
TotalDbTransaction: 0,
|
||||
TotalProcessing: 0,
|
||||
},
|
||||
}
|
||||
|
||||
g, _ := errgroup.WithContext(context.Background())
|
||||
|
||||
if spd.PerformBeaconStateProcessing {
|
||||
// Get the BeaconState.
|
||||
g.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
start := time.Now()
|
||||
err := ps.getBeaconState(spd.ServerEndpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ps.PerformanceMetrics.BeaconNodeStateRetrievalTime = time.Since(start)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if spd.PerformBeaconBlockProcessing {
|
||||
// Get the SignedBeaconBlock.
|
||||
g.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
start := time.Now()
|
||||
err := ps.getSignedBeaconBlock(spd.ServerEndpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ps.PerformanceMetrics.BeaconNodeBlockRetrievalTime = time.Since(start)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return err, "processSlot"
|
||||
}
|
||||
|
||||
parseBeaconTime := time.Now()
|
||||
finalBlockRoot, finalStateRoot, _, err := ps.provideFinalHash()
|
||||
if err != nil {
|
||||
return err, "CalculateBlockRoot"
|
||||
}
|
||||
ps.PerformanceMetrics.ParseBeaconObjectForHash = time.Since(parseBeaconTime)
|
||||
|
||||
if spd.CheckDb {
|
||||
checkDbTime := time.Now()
|
||||
var blockRequired bool
|
||||
if spd.PerformBeaconBlockProcessing {
|
||||
blockExists, err := checkSlotAndRoot(ps.Db, CheckSignedBeaconBlockStmt, ps.Slot, finalBlockRoot)
|
||||
if err != nil {
|
||||
return err, "checkDb"
|
||||
}
|
||||
blockRequired = !blockExists
|
||||
}
|
||||
|
||||
var stateRequired bool
|
||||
if spd.PerformBeaconStateProcessing {
|
||||
stateExists, err := checkSlotAndRoot(ps.Db, CheckBeaconStateStmt, ps.Slot, finalStateRoot)
|
||||
if err != nil {
|
||||
return err, "checkDb"
|
||||
}
|
||||
stateRequired = !stateExists
|
||||
}
|
||||
|
||||
if !blockRequired && !stateRequired {
|
||||
log.WithField("slot", slot).Info("Slot already in the DB.")
|
||||
return nil, ""
|
||||
}
|
||||
ps.PerformanceMetrics.CheckDbPreProcessing = time.Since(checkDbTime)
|
||||
}
|
||||
|
||||
// Get this object ready to write
|
||||
createDbWriteTime := time.Now()
|
||||
dw, err := ps.createWriteObjects()
|
||||
if err != nil {
|
||||
return err, "blockRoot"
|
||||
}
|
||||
ps.PerformanceMetrics.CreateDbWriteObject = time.Since(createDbWriteTime)
|
||||
|
||||
// Write the object to the DB.
|
||||
dbFullTransactionTime := time.Now()
|
||||
defer func() {
|
||||
err := dw.Tx.Rollback(dw.Ctx)
|
||||
if err != nil && err != pgx.ErrTxClosed {
|
||||
loghelper.LogError(err).Error("We were unable to Rollback a transaction")
|
||||
}
|
||||
}()
|
||||
|
||||
transactionTime := time.Now()
|
||||
err = dw.transactFullSlot()
|
||||
if err != nil {
|
||||
return err, "processSlot"
|
||||
}
|
||||
ps.PerformanceMetrics.TransactSlotOnly = time.Since(transactionTime)
|
||||
|
||||
// Handle any reorgs or skipped slots.
|
||||
reorgTime := time.Now()
|
||||
headOrHistoric = strings.ToLower(headOrHistoric)
|
||||
if headOrHistoric != "head" && headOrHistoric != "historic" {
|
||||
return fmt.Errorf("headOrHistoric must be either historic or head"), ""
|
||||
}
|
||||
if ps.HeadOrHistoric == "head" && previousSlot != 0 && previousBlockRoot != "" && ps.Status != "skipped" {
|
||||
ps.checkPreviousSlot(dw.Tx, dw.Ctx, previousSlot, previousBlockRoot, knownGapsTableIncrement)
|
||||
}
|
||||
ps.PerformanceMetrics.CheckReorg = time.Since(reorgTime)
|
||||
|
||||
// Commit the transaction
|
||||
commitTime := time.Now()
|
||||
if err = dw.Tx.Commit(dw.Ctx); err != nil {
|
||||
return err, "transactionCommit"
|
||||
}
|
||||
ps.PerformanceMetrics.CommitTransaction = time.Since(commitTime)
|
||||
|
||||
// Total metric capture time.
|
||||
ps.PerformanceMetrics.TotalDbTransaction = time.Since(dbFullTransactionTime)
|
||||
ps.PerformanceMetrics.TotalProcessing = time.Since(totalStart)
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"slot": slot,
|
||||
"performanceMetrics": fmt.Sprintf("%+v\n", ps.PerformanceMetrics),
|
||||
}).Debug("Performance Metric output!")
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
}
|
||||
|
||||
// Handle a slot that is at head. A wrapper function for calling `handleFullSlot`.
|
||||
func processHeadSlot(slot Slot, blockRoot string, stateRoot string, spd SlotProcessingDetails) {
|
||||
// Get the knownGaps at startUp
|
||||
if spd.PreviousSlot == 0 && spd.PreviousBlockRoot == "" {
|
||||
writeStartUpGaps(spd.Db, spd.KnownGapTableIncrement, slot, spd.Metrics)
|
||||
}
|
||||
// TODO(telackey): Why context.Background()?
|
||||
err, errReason := processFullSlot(context.Background(), slot, blockRoot, stateRoot,
|
||||
spd.PreviousSlot, spd.PreviousBlockRoot, spd.KnownGapTableIncrement, "head", &spd)
|
||||
if err != nil {
|
||||
writeKnownGaps(spd.Db, spd.KnownGapTableIncrement, slot, slot, err, errReason, spd.Metrics)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle a historic slot. A wrapper function for calling `handleFullSlot`.
|
||||
func handleHistoricSlot(ctx context.Context, slot Slot, spd SlotProcessingDetails) (error, string) {
|
||||
return processFullSlot(ctx, slot, "", "", 0, "",
|
||||
1, "historic", &spd)
|
||||
}
|
||||
|
||||
// Update the SszSignedBeaconBlock and FullSignedBeaconBlock object with their respective values.
|
||||
func (ps *ProcessSlot) getSignedBeaconBlock(serverAddress string) error {
|
||||
var blockIdentifier string // Used to query the block
|
||||
if ps.BlockRoot != "" {
|
||||
blockIdentifier = ps.BlockRoot
|
||||
} else {
|
||||
blockIdentifier = ps.Slot.Format()
|
||||
}
|
||||
|
||||
blockEndpoint := serverAddress + BcBlockQueryEndpoint + blockIdentifier
|
||||
sszSignedBeaconBlock, rc, err := querySsz(blockEndpoint, ps.Slot)
|
||||
|
||||
if err != nil || rc != 200 {
|
||||
loghelper.LogSlotError(ps.Slot.Number(), err).Error("Unable to properly query the slot.")
|
||||
ps.FullSignedBeaconBlock = nil
|
||||
ps.SszSignedBeaconBlock = []byte{}
|
||||
ps.ParentBlockRoot = ""
|
||||
ps.Status = "skipped"
|
||||
|
||||
// A 404 is normal in the case of a "skipped" slot.
|
||||
if rc == 404 {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var signedBeaconBlock SignedBeaconBlock
|
||||
err = signedBeaconBlock.UnmarshalSSZ(sszSignedBeaconBlock)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(ps.Slot.Number(), err).Error("Unable to unmarshal SignedBeaconBlock for slot.")
|
||||
ps.FullSignedBeaconBlock = nil
|
||||
ps.SszSignedBeaconBlock = []byte{}
|
||||
ps.ParentBlockRoot = ""
|
||||
ps.Status = "skipped"
|
||||
return err
|
||||
}
|
||||
|
||||
ps.FullSignedBeaconBlock = &signedBeaconBlock
|
||||
ps.SszSignedBeaconBlock = sszSignedBeaconBlock
|
||||
|
||||
ps.ParentBlockRoot = toHex(ps.FullSignedBeaconBlock.Block().ParentRoot())
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update the SszBeaconState and FullBeaconState object with their respective values.
|
||||
func (ps *ProcessSlot) getBeaconState(serverEndpoint string) error {
|
||||
var stateIdentifier string // Used to query the state
|
||||
if ps.StateRoot != "" {
|
||||
stateIdentifier = ps.StateRoot
|
||||
} else {
|
||||
stateIdentifier = ps.Slot.Format()
|
||||
}
|
||||
|
||||
stateEndpoint := serverEndpoint + BcStateQueryEndpoint + stateIdentifier
|
||||
sszBeaconState, _, err := querySsz(stateEndpoint, ps.Slot)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(ps.Slot.Number(), err).Error("Unable to properly query the BeaconState.")
|
||||
return err
|
||||
}
|
||||
|
||||
var beaconState BeaconState
|
||||
err = beaconState.UnmarshalSSZ(sszBeaconState)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(ps.Slot.Number(), err).Error("Unable to unmarshal the BeaconState.")
|
||||
return err
|
||||
}
|
||||
|
||||
ps.FullBeaconState = &beaconState
|
||||
ps.SszBeaconState = sszBeaconState
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check to make sure that the previous block we processed is the parent of the current block.
|
||||
func (ps *ProcessSlot) checkPreviousSlot(tx sql.Tx, ctx context.Context, previousSlot Slot, previousBlockRoot string, knownGapsTableIncrement int) {
|
||||
if nil == ps.FullSignedBeaconBlock {
|
||||
log.Debug("Can't check block root, no current block.")
|
||||
return
|
||||
}
|
||||
parentRoot := toHex(ps.FullSignedBeaconBlock.Block().ParentRoot())
|
||||
slot := ps.Slot
|
||||
if previousSlot == slot {
|
||||
log.WithFields(log.Fields{
|
||||
"slot": slot,
|
||||
"fork": true,
|
||||
}).Warn("A fork occurred! The previous slot and current slot match.")
|
||||
transactReorgs(tx, ctx, ps.Slot, ps.BlockRoot, ps.Metrics)
|
||||
} else if previousSlot > slot {
|
||||
log.WithFields(log.Fields{
|
||||
"previousSlot": previousSlot,
|
||||
"curSlot": slot,
|
||||
}).Warn("We noticed the previous slot is greater than the current slot.")
|
||||
} else if previousSlot+1 != slot {
|
||||
log.WithFields(log.Fields{
|
||||
"previousSlot": previousSlot,
|
||||
"currentSlot": slot,
|
||||
}).Error("We skipped a few slots.")
|
||||
transactKnownGaps(tx, ctx, knownGapsTableIncrement, previousSlot+1, slot-1, fmt.Errorf("gaps during head processing"), "headGaps", ps.Metrics)
|
||||
} else if previousBlockRoot != parentRoot {
|
||||
log.WithFields(log.Fields{
|
||||
"previousBlockRoot": previousBlockRoot,
|
||||
"currentBlockParent": parentRoot,
|
||||
}).Error("The previousBlockRoot does not match the current blocks parent, an unprocessed fork might have occurred.")
|
||||
transactReorgs(tx, ctx, previousSlot, parentRoot, ps.Metrics)
|
||||
} else {
|
||||
log.Debug("Previous Slot and Current Slot are one distance from each other.")
|
||||
}
|
||||
}
|
||||
|
||||
// Transforms all the raw data into DB models that can be written to the DB.
|
||||
func (ps *ProcessSlot) createWriteObjects() (*DatabaseWriter, error) {
|
||||
var status string
|
||||
if ps.Status != "" {
|
||||
status = ps.Status
|
||||
} else {
|
||||
status = "proposed"
|
||||
}
|
||||
|
||||
parseBeaconTime := time.Now()
|
||||
// These will normally be pre-calculated by this point.
|
||||
blockRoot, stateRoot, eth1DataBlockHash, err := ps.provideFinalHash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ps.PerformanceMetrics.ParseBeaconObjectForHash = time.Since(parseBeaconTime)
|
||||
|
||||
payloadHeader := ps.provideExecutionPayloadDetails()
|
||||
|
||||
dw, err := CreateDatabaseWrite(ps.Db, ps.Slot, stateRoot, blockRoot, ps.ParentBlockRoot, eth1DataBlockHash,
|
||||
payloadHeader, status, &ps.SszSignedBeaconBlock, &ps.SszBeaconState, ps.Metrics)
|
||||
if err != nil {
|
||||
return dw, err
|
||||
}
|
||||
|
||||
return dw, nil
|
||||
}
|
||||
|
||||
// This function will return the final blockRoot, stateRoot, and eth1DataBlockHash that will be
|
||||
// used to write to a DB
|
||||
func (ps *ProcessSlot) provideFinalHash() (string, string, string, error) {
|
||||
var (
|
||||
stateRoot string
|
||||
blockRoot string
|
||||
eth1DataBlockHash string
|
||||
)
|
||||
if ps.Status == "skipped" {
|
||||
stateRoot = ""
|
||||
blockRoot = ""
|
||||
eth1DataBlockHash = ""
|
||||
} else {
|
||||
if ps.StateRoot != "" {
|
||||
stateRoot = ps.StateRoot
|
||||
} else {
|
||||
if nil != ps.FullSignedBeaconBlock {
|
||||
stateRoot = toHex(ps.FullSignedBeaconBlock.Block().StateRoot())
|
||||
log.Debug("BeaconBlock StateRoot: ", stateRoot)
|
||||
} else {
|
||||
log.Debug("BeaconBlock StateRoot: <nil beacon block>")
|
||||
}
|
||||
}
|
||||
|
||||
if ps.BlockRoot != "" {
|
||||
blockRoot = ps.BlockRoot
|
||||
} else {
|
||||
if nil != ps.FullSignedBeaconBlock {
|
||||
rawBlockRoot := ps.FullSignedBeaconBlock.Block().HashTreeRoot()
|
||||
blockRoot = toHex(rawBlockRoot)
|
||||
log.WithFields(log.Fields{"blockRoot": blockRoot}).Debug("Block Root from ssz")
|
||||
} else {
|
||||
log.Debug("BeaconBlock HashTreeRoot: <nil beacon block>")
|
||||
}
|
||||
}
|
||||
if nil != ps.FullSignedBeaconBlock {
|
||||
eth1DataBlockHash = toHex(ps.FullSignedBeaconBlock.Block().Body().Eth1Data().BlockHash)
|
||||
}
|
||||
}
|
||||
return blockRoot, stateRoot, eth1DataBlockHash, nil
|
||||
}
|
||||
|
||||
func (ps *ProcessSlot) provideExecutionPayloadDetails() *ExecutionPayloadHeader {
|
||||
if nil == ps.FullSignedBeaconBlock || !ps.FullSignedBeaconBlock.IsBellatrix() {
|
||||
return nil
|
||||
}
|
||||
|
||||
payload := ps.FullSignedBeaconBlock.Block().Body().ExecutionPayloadHeader()
|
||||
blockNumber := uint64(payload.BlockNumber)
|
||||
|
||||
// The earliest blocks on the Bellatrix fork, pre-Merge, have zeroed ExecutionPayloads.
|
||||
// There is nothing useful to to store in that case, even though the structure exists.
|
||||
if blockNumber == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
func toHex(r [32]byte) string {
|
||||
return "0x" + hex.EncodeToString(r[:])
|
||||
}
|
||||
@@ -1,101 +1,73 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This file will contain functions to query the Beacon Chain Server.
|
||||
|
||||
package beaconclient
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// Attempt to use generics..
|
||||
// // These are types that append slot at the end of the URL to handle a request.
|
||||
// type SlotBasedRequests interface {
|
||||
// *specs.BeaconState | *specs.SignedBeaconBlock
|
||||
// UnmarshalSSZ([]byte) error
|
||||
// }
|
||||
//
|
||||
// func queryState[R SlotBasedRequests](endpoint string, slot string) (R, error) {
|
||||
// obj := new(R)
|
||||
// rawState, err := querySlot(endpoint, slot)
|
||||
// if err != nil {
|
||||
// return *obj, err
|
||||
// }
|
||||
//
|
||||
// err = &obj.UnmarshalSSZ(rawState)
|
||||
// err = (*obj).UnmarshalSSZ(rawState)
|
||||
// if err != nil {
|
||||
// loghelper.LogSlotError(slot, err).Error("Unable to unmarshal the SSZ response from the Beacon Node Successfully!")
|
||||
// return *obj, fmt.Errorf("Unable to unmarshal the SSZ response from the Beacon Node Successfully!: %s", err.Error())
|
||||
// }
|
||||
// return *obj, nil
|
||||
// }
|
||||
// Object to unmarshal the BlockRootResponse
|
||||
type BlockRootResponse struct {
|
||||
Data BlockRootMessage `json:"data"`
|
||||
}
|
||||
|
||||
// This function will query a state object based on the slot provided.
|
||||
// The object is SSZ encoded.
|
||||
|
||||
//type BeaconBlockResponse struct {
|
||||
// version string `json: `
|
||||
//}
|
||||
|
||||
// func queryState(endpoint string, slot string) (spectests.BeaconState, error) {
|
||||
// obj := new(spectests.BeaconState)
|
||||
// fullEndpoint := endpoint + slot
|
||||
// rawState, err := querySsz(fullEndpoint, slot)
|
||||
// if err != nil {
|
||||
// return *obj, err
|
||||
// }
|
||||
//
|
||||
// err = obj.UnmarshalSSZ(rawState)
|
||||
// if err != nil {
|
||||
// loghelper.LogSlotError(slot, err).Error("Unable to unmarshal the SSZ response from the Beacon Node")
|
||||
// return *obj, fmt.Errorf("Unable to unmarshal the SSZ response from the Beacon Node: %s", err.Error())
|
||||
// }
|
||||
// return *obj, nil
|
||||
// }
|
||||
//
|
||||
// // This function will query a state object based on the slot provided.
|
||||
// // The object is SSZ encoded.
|
||||
// func queryBlock(endpoint string, slot string) (spectests.SignedBeaconBlock, error) {
|
||||
// obj := new(spectests.SignedBeaconBlock)
|
||||
// fullEndpoint := endpoint + slot
|
||||
// rawBlock, err := querySsz(fullEndpoint, slot)
|
||||
// if err != nil {
|
||||
// return *obj, err
|
||||
// }
|
||||
//
|
||||
// err = obj.UnmarshalSSZ(rawBlock)
|
||||
// if err != nil {
|
||||
// loghelper.LogSlotError(slot, err).Error("Unable to unmarshal the SSZ response from the Beacon Node Successfully!")
|
||||
// return *obj, fmt.Errorf("Unable to unmarshal the SSZ response from the Beacon Node Successfully!: %s", err.Error())
|
||||
// }
|
||||
// return *obj, nil
|
||||
// }
|
||||
// Object to unmarshal the BlockRoot Message
|
||||
type BlockRootMessage struct {
|
||||
Root string `json:"root"`
|
||||
}
|
||||
|
||||
// A helper function to query endpoints that utilize slots.
|
||||
func querySsz(endpoint string, slot string) ([]byte, error) {
|
||||
log.WithFields(log.Fields{"endpoint": endpoint}).Info("Querying endpoint")
|
||||
func querySsz(endpoint string, slot Slot) ([]byte, int, error) {
|
||||
log.WithFields(log.Fields{"endpoint": endpoint}).Debug("Querying endpoint")
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", endpoint, nil)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(slot, err).Error("Unable to create a request!")
|
||||
return nil, fmt.Errorf("Unable to create a request!: %s", err.Error())
|
||||
loghelper.LogSlotError(slot.Number(), err).Error("Unable to create a request!")
|
||||
return nil, 0, fmt.Errorf("Unable to create a request!: %s", err.Error())
|
||||
}
|
||||
// Not set correctly
|
||||
req.Header.Set("Accept", "application/octet-stream")
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(slot, err).Error("Unable to query Beacon Node!")
|
||||
return nil, fmt.Errorf("Unable to query Beacon Node: %s", err.Error())
|
||||
loghelper.LogSlotError(slot.Number(), err).Error("Unable to query Beacon Node!")
|
||||
return nil, 0, fmt.Errorf("Unable to query Beacon Node: %s", err.Error())
|
||||
}
|
||||
defer response.Body.Close()
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(slot, err).Error("Unable to turn response into a []bytes array!")
|
||||
return nil, fmt.Errorf("Unable to turn response into a []bytes array!: %s", err.Error())
|
||||
|
||||
rc := response.StatusCode
|
||||
// Any 2xx code is OK.
|
||||
if rc < 200 || rc >= 300 {
|
||||
return nil, rc, fmt.Errorf("HTTP Error: %d", rc)
|
||||
}
|
||||
return body, nil
|
||||
|
||||
var body bytes.Buffer
|
||||
buf := bufio.NewWriter(&body)
|
||||
_, err = io.Copy(buf, response.Body)
|
||||
if err != nil {
|
||||
loghelper.LogSlotError(slot.Number(), err).Error("Unable to turn response into a []bytes array!")
|
||||
return nil, rc, fmt.Errorf("Unable to turn response into a []bytes array!: %s", err.Error())
|
||||
}
|
||||
|
||||
return body.Bytes(), rc, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package beaconclient_test
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/beaconclient"
|
||||
)
|
||||
|
||||
var (
|
||||
prodConfig = Config{
|
||||
protocol: os.Getenv("bc_protocol"),
|
||||
address: os.Getenv("bc_address"),
|
||||
port: getEnvInt(os.Getenv("bc_port")),
|
||||
dbHost: os.Getenv("db_host"),
|
||||
dbPort: getEnvInt(os.Getenv("db_port")),
|
||||
dbName: os.Getenv("db_name"),
|
||||
dbUser: os.Getenv("db_user"),
|
||||
dbPassword: os.Getenv("db_password"),
|
||||
dbDriver: os.Getenv("db_driver"),
|
||||
knownGapsTableIncrement: 100000000,
|
||||
bcUniqueIdentifier: 100,
|
||||
checkDb: false,
|
||||
performBeaconBlockProcessing: true,
|
||||
// As of 2022-09, generating and downloading the full BeaconState is so slow it will cause the tests to fail.
|
||||
performBeaconStateProcessing: false,
|
||||
}
|
||||
)
|
||||
|
||||
// Note: These tests expect to communicate with a fully-synced Beacon node.
|
||||
|
||||
var _ = Describe("Systemvalidation", Label("system"), func() {
|
||||
level, _ := log.ParseLevel("debug")
|
||||
log.SetLevel(level)
|
||||
|
||||
Describe("Run the application against a running lighthouse node", func() {
|
||||
Context("When we receive head messages", func() {
|
||||
It("We should process the messages successfully", func() {
|
||||
bc := setUpTest(prodConfig, "10000000000")
|
||||
processProdHeadBlocks(bc, 3, 0, 0, 0)
|
||||
})
|
||||
})
|
||||
Context("When we have historical and knownGaps slots to process", Label("system-batch"), func() {
|
||||
It("Should process them successfully", func() {
|
||||
bc := setUpTest(prodConfig, "10000000000")
|
||||
//known Gaps
|
||||
BeaconNodeTester.writeEventToKnownGaps(bc, 100, 101)
|
||||
BeaconNodeTester.runKnownGapsProcess(bc, 2, 2, 0, 0, 0)
|
||||
|
||||
// Historical
|
||||
BeaconNodeTester.writeEventToHistoricProcess(bc, 2375703, 2375703, 10)
|
||||
BeaconNodeTester.runHistoricalProcess(bc, 2, 3, 0, 0, 0)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
validatePopularBatchBlocks(bc)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Wrapper function to get int env variables.
|
||||
func getEnvInt(envVar string) int {
|
||||
val, err := strconv.Atoi(envVar)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Start head tracking and wait for the expected results.
|
||||
func processProdHeadBlocks(bc *beaconclient.BeaconClient, expectedInserts, expectedReorgs, expectedKnownGaps, expectedKnownGapsReprocessError uint64) {
|
||||
go bc.CaptureHead()
|
||||
time.Sleep(1 * time.Second)
|
||||
validateMetrics(bc, expectedInserts, expectedReorgs, expectedKnownGaps, expectedKnownGapsReprocessError)
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package sql
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package sql
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package postgres
|
||||
|
||||
import (
|
||||
@@ -18,7 +33,7 @@ const (
|
||||
// DefaultConfig are default parameters for connecting to a Postgres sql
|
||||
var DefaultConfig = Config{
|
||||
Hostname: "localhost",
|
||||
Port: 8077,
|
||||
Port: 8076,
|
||||
DatabaseName: "vulcanize_testing",
|
||||
Username: "vdbm",
|
||||
Password: "password",
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package postgres
|
||||
|
||||
import (
|
||||
@@ -5,7 +20,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
var _ sql.Database = &DB{}
|
||||
@@ -23,6 +39,35 @@ func NewPostgresDB(c Config) (*DB, error) {
|
||||
return &DB{driver}, nil
|
||||
}
|
||||
|
||||
// A simple wrapper to create a DB object to use.
|
||||
func SetupPostgresDb(dbHostname string, dbPort int, dbName string, dbUsername string, dbPassword string, driverName string) (sql.Database, error) {
|
||||
log.Debug("Resolving Driver Type")
|
||||
DbDriver, err := ResolveDriverType(driverName)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"driver_name_provided": driverName,
|
||||
}).Error("Can't resolve driver type")
|
||||
}
|
||||
log.Info("Using Driver: ", DbDriver)
|
||||
|
||||
postgresConfig := Config{
|
||||
Hostname: dbHostname,
|
||||
Port: dbPort,
|
||||
DatabaseName: dbName,
|
||||
Username: dbUsername,
|
||||
Password: dbPassword,
|
||||
Driver: DbDriver,
|
||||
}
|
||||
DB, err := NewPostgresDB(postgresConfig)
|
||||
|
||||
if err != nil {
|
||||
loghelper.LogError(err).Error("Unable to connect to the DB")
|
||||
return nil, err
|
||||
}
|
||||
return DB, err
|
||||
}
|
||||
|
||||
// Create a driver based on the config
|
||||
func createDriver(c Config) (*pgxDriver, error) {
|
||||
switch c.Driver {
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package postgres
|
||||
|
||||
import (
|
||||
@@ -8,7 +23,7 @@ import (
|
||||
"github.com/jackc/pgconn"
|
||||
"github.com/jackc/pgx/v4"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
)
|
||||
|
||||
// pgxDriver driver, implements sql.Driver
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package postgres_test
|
||||
|
||||
import (
|
||||
@@ -8,9 +23,9 @@ import (
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/database/sql/postgres"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/testhelpers"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/database/sql/postgres"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/testhelpers"
|
||||
)
|
||||
|
||||
var _ = Describe("Pgx", func() {
|
||||
@@ -29,17 +44,18 @@ var _ = Describe("Pgx", func() {
|
||||
_, err := postgres.NewPostgresDB(postgres.Config{
|
||||
Driver: "PGX",
|
||||
})
|
||||
Expect(err).NotTo(BeNil())
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
present, err := doesContainsSubstring(err.Error(), sql.DbConnectionFailedMsg)
|
||||
Expect(present).To(BeTrue())
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("The connection is successful", func() {
|
||||
It("Should create a DB object", func() {
|
||||
db, err := postgres.NewPostgresDB(postgres.DefaultConfig)
|
||||
defer db.Close()
|
||||
Expect(err).To(BeNil())
|
||||
defer db.Close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package postgres_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package gracefulshutdown
|
||||
|
||||
import (
|
||||
@@ -10,30 +25,34 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||
"github.com/vulcanize/ipld-eth-beacon-indexer/pkg/loghelper"
|
||||
)
|
||||
|
||||
// operation is a clean up function on shutting down
|
||||
type Operation func(ctx context.Context) error
|
||||
|
||||
var (
|
||||
TimeoutErr = func(timeout string) error {
|
||||
return fmt.Errorf("The Timeout %s, has been elapsed, the application will forcefully exit", timeout)
|
||||
}
|
||||
)
|
||||
|
||||
// gracefulShutdown waits for termination syscalls and doing clean up operations after received it
|
||||
func Shutdown(ctx context.Context, timeout time.Duration, ops map[string]Operation) (<-chan struct{}, <-chan error) {
|
||||
func Shutdown(ctx context.Context, notifierCh chan os.Signal, timeout time.Duration, ops map[string]Operation) (<-chan struct{}, <-chan error) {
|
||||
waitCh := make(chan struct{})
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
s := make(chan os.Signal, 1)
|
||||
|
||||
// add any other syscalls that you want to be notified with
|
||||
signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
<-s
|
||||
signal.Notify(notifierCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
<-notifierCh
|
||||
|
||||
log.Info("Shutting Down your application")
|
||||
|
||||
// set timeout for the ops to be done to prevent system hang
|
||||
timeoutFunc := time.AfterFunc(timeout, func() {
|
||||
log.Warnf("timeout %d ms has been elapsed, force exit", timeout.Milliseconds())
|
||||
errCh <- fmt.Errorf("Application shutdown took too long.")
|
||||
return
|
||||
log.Warnf(TimeoutErr(timeout.String()).Error())
|
||||
errCh <- TimeoutErr(timeout.String())
|
||||
})
|
||||
|
||||
defer timeoutFunc.Stop()
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package loghelper
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// A simple helper function that will help wrap the error message.
|
||||
func LogEndpoint(endpoint string) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"endpoint": endpoint,
|
||||
})
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// A simple function to help with logging errors.
|
||||
package loghelper
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// A simple helper function that will help wrap the error message.
|
||||
func LogError(err error) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
})
|
||||
}
|
||||
|
||||
func LogSlotError(slot string, err error) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"slot": slot,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package loghelper
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// A simple helper function that will help wrap the error message.
|
||||
func LogEndpoint(endpoint string) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"endpoint": endpoint,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// A simple function to help with logging errors.
|
||||
package loghelper
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// A simple helper function that will help wrap the error message.
|
||||
func LogError(err error) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
})
|
||||
}
|
||||
|
||||
// A simple herlper function to log slot and error.
|
||||
func LogSlotError(slot uint64, err error) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"slot": slot,
|
||||
})
|
||||
}
|
||||
|
||||
func LogSlotRangeError(startSlot uint64, endSlot uint64, err error) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"startSlot": startSlot,
|
||||
"endSlot": endSlot,
|
||||
})
|
||||
}
|
||||
func LogSlotRangeStatementError(startSlot uint64, endSlot uint64, statement string, err error) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"startSlot": startSlot,
|
||||
"endSlot": endSlot,
|
||||
"SqlStatement": statement,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package loghelper
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// A simple helper function that will help wrap the reorg error messages.
|
||||
func LogReorgError(slot uint64, latestBlockRoot string, err error) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"err": err,
|
||||
"slot": slot,
|
||||
"latestBlockRoot": latestBlockRoot,
|
||||
})
|
||||
}
|
||||
|
||||
// A simple helper function that will help wrap regular reorg messages.
|
||||
func LogReorg(slot uint64, latestBlockRoot string) *log.Entry {
|
||||
return log.WithFields(log.Fields{
|
||||
"slot": slot,
|
||||
"latestBlockRoot": latestBlockRoot,
|
||||
})
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package testhelpers
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package version
|
||||
|
||||
import "fmt"
|
||||
|
||||
Reference in New Issue
Block a user