mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
Merge pull request #433 from cffls/develop
Merge branch 'v0.3.0-dev' into develop
This commit is contained in:
commit
88dbfa1c13
156 changed files with 7274 additions and 2481 deletions
11
.github/matic-cli-config.yml
vendored
Normal file
11
.github/matic-cli-config.yml
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
defaultStake: 10000
|
||||||
|
defaultFee: 2000
|
||||||
|
borChainId: "15001"
|
||||||
|
heimdallChainId: heimdall-15001
|
||||||
|
contractsBranch: jc/v0.3.1-backport
|
||||||
|
numOfValidators: 3
|
||||||
|
numOfNonValidators: 0
|
||||||
|
ethURL: http://ganache:9545
|
||||||
|
devnetType: docker
|
||||||
|
borDockerBuildContext: "../../bor"
|
||||||
|
heimdallDockerBuildContext: "https://github.com/maticnetwork/heimdall.git#v0.3.0-dev"
|
||||||
189
.github/workflows/ci.yml
vendored
189
.github/workflows/ci.yml
vendored
|
|
@ -1,28 +1,183 @@
|
||||||
name: CI
|
name: CI
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
- "qa"
|
||||||
|
- "develop"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
types: [opened, synchronize, edited]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
tests:
|
||||||
runs-on: ubuntu-latest
|
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-20.04, macos-11 ] # list of os: https://github.com/actions/virtual-environments
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Install Go
|
- run: |
|
||||||
uses: actions/setup-go@v2
|
git submodule update --init --recursive --force
|
||||||
|
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.17
|
go-version: 1.18.x
|
||||||
- name: "Build binaries"
|
|
||||||
|
- name: Install dependencies on Linux
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: sudo apt update && sudo apt install build-essential
|
||||||
|
|
||||||
|
- name: Golang-ci install
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: make lintci-deps
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/Library/Caches/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: ${{ runner.os }}-go-
|
||||||
|
|
||||||
|
- name: Build
|
||||||
run: make all
|
run: make all
|
||||||
- name: "Run tests"
|
|
||||||
|
- name: Lint
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: make lint
|
||||||
|
|
||||||
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
|
|
||||||
|
#- name: Data race tests
|
||||||
|
# run: make test-race
|
||||||
|
|
||||||
|
- name: test-integration
|
||||||
|
run: make test-integration
|
||||||
|
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v1
|
||||||
with:
|
with:
|
||||||
file: ./cover.out
|
file: ./cover.out
|
||||||
- name: Reproducible build test
|
|
||||||
|
# # TODO: make it work
|
||||||
|
# - name: Reproducible build test
|
||||||
|
# run: |
|
||||||
|
# make geth
|
||||||
|
# shasum -a256 ./build/bin/geth > bor1.sha256
|
||||||
|
# make geth
|
||||||
|
# shasum -a256 ./build/bin/geth > bor2.sha256
|
||||||
|
# if ! cmp -s bor1.sha256 bor2.sha256; then
|
||||||
|
# echo >&2 "Reproducible build broken"; cat bor1.sha256; cat bor2.sha256; exit 1
|
||||||
|
# fi
|
||||||
|
|
||||||
|
integration-tests:
|
||||||
|
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: bor
|
||||||
|
- name: Checkout submodules
|
||||||
run: |
|
run: |
|
||||||
make geth
|
cd bor
|
||||||
shasum -a256 ./build/bin/geth > bor1.sha256
|
git submodule update --init --recursive --force
|
||||||
make geth
|
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||||
shasum -a256 ./build/bin/geth > bor2.sha256
|
|
||||||
if ! cmp -s bor1.sha256 bor2.sha256; then
|
- uses: actions/setup-go@v3
|
||||||
echo >&2 "Reproducible build broken"; cat bor1.sha256; cat bor2.sha256; exit 1
|
with:
|
||||||
fi
|
go-version: 1.18.x
|
||||||
|
|
||||||
|
- name: Checkout matic-cli
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: maticnetwork/matic-cli
|
||||||
|
ref: v0.3.0-dev
|
||||||
|
path: matic-cli
|
||||||
|
|
||||||
|
- name: Install dependencies on Linux
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install build-essential
|
||||||
|
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
|
||||||
|
sudo snap install solc
|
||||||
|
sudo apt install python2 jq curl
|
||||||
|
sudo ln -sf /usr/bin/python2 /usr/bin/python
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '10.17.0'
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: |
|
||||||
|
matic-cli/package-lock.json
|
||||||
|
matic-cli/devnet/code/contracts/package-lock.json
|
||||||
|
matic-cli/devnet/code/genesis-contracts/package-lock.json
|
||||||
|
matic-cli/devnet/code/genesis-contracts/matic-contracts/package-lock.json
|
||||||
|
|
||||||
|
- name: Bootstrap devnet
|
||||||
|
run: |
|
||||||
|
cd matic-cli
|
||||||
|
npm install --prefer-offline --no-audit --progress=false
|
||||||
|
mkdir devnet
|
||||||
|
cd devnet
|
||||||
|
../bin/matic-cli setup devnet -c ../../bor/.github/matic-cli-config.yml
|
||||||
|
|
||||||
|
- name: Launch devnet
|
||||||
|
run: |
|
||||||
|
cd matic-cli/devnet
|
||||||
|
bash docker-ganache-start.sh
|
||||||
|
bash docker-heimdall-start-all.sh
|
||||||
|
bash docker-bor-setup.sh
|
||||||
|
bash docker-bor-start-all.sh
|
||||||
|
sleep 120 && bash ganache-deployment-bor.sh
|
||||||
|
sleep 120 && bash ganache-deployment-sync.sh
|
||||||
|
sleep 120
|
||||||
|
docker exec bor0 bash -c "bor attach /root/.bor/data/bor.ipc -exec 'admin.peers'"
|
||||||
|
docker exec bor0 bash -c "bor attach /root/.bor/data/bor.ipc -exec 'eth.blockNumber'"
|
||||||
|
|
||||||
|
- name: Run smoke tests
|
||||||
|
run: |
|
||||||
|
echo "Deposit 100 matic for each account to bor network"
|
||||||
|
cd matic-cli/devnet/code/contracts
|
||||||
|
npm run truffle exec scripts/deposit.js -- --network development $(jq -r .root.tokens.MaticToken contractAddresses.json) 100000000000000000000
|
||||||
|
cd -
|
||||||
|
bash bor/integration-tests/smoke_test.sh
|
||||||
|
|
||||||
|
- name: Upload logs
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: logs_${{ github.run_id }}
|
||||||
|
path: |
|
||||||
|
matic-cli/devnet/logs
|
||||||
|
|
||||||
|
- name: Package code and chain data
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
cd matic-cli/devnet
|
||||||
|
docker compose down
|
||||||
|
cd -
|
||||||
|
mkdir -p ${{ github.run_id }}/matic-cli
|
||||||
|
sudo mv bor ${{ github.run_id }}
|
||||||
|
sudo mv matic-cli/devnet ${{ github.run_id }}/matic-cli
|
||||||
|
sudo tar czf code.tar.gz ${{ github.run_id }}
|
||||||
|
|
||||||
|
- name: Upload code and chain data
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: code_${{ github.run_id }}
|
||||||
|
path: code.tar.gz
|
||||||
|
|
|
||||||
29
.github/workflows/dockerimage.yml
vendored
29
.github/workflows/dockerimage.yml
vendored
|
|
@ -1,29 +0,0 @@
|
||||||
name: Bor Docker Image CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- '**'
|
|
||||||
tags:
|
|
||||||
- 'v*.*.*'
|
|
||||||
# to be used by fork patch-releases ^^
|
|
||||||
- 'v*.*.*-*'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Build the Bor Docker image
|
|
||||||
env:
|
|
||||||
DOCKERHUB: ${{ secrets.DOCKERHUB }}
|
|
||||||
DOCKERHUB_KEY: ${{ secrets.DOCKERHUB_KEY }}
|
|
||||||
run: |
|
|
||||||
ls -l
|
|
||||||
echo "Docker login"
|
|
||||||
docker login -u $DOCKERHUB -p $DOCKERHUB_KEY
|
|
||||||
echo "running build"
|
|
||||||
docker build -f Dockerfile.classic -t maticnetwork/bor:${GITHUB_REF/refs\/tags\//} .
|
|
||||||
echo "pushing image"
|
|
||||||
docker push maticnetwork/bor:${GITHUB_REF/refs\/tags\//}
|
|
||||||
echo "DONE!"
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -15,6 +15,8 @@
|
||||||
*/**/*dapps*
|
*/**/*dapps*
|
||||||
build/_vendor/pkg
|
build/_vendor/pkg
|
||||||
|
|
||||||
|
cover.out
|
||||||
|
|
||||||
#*
|
#*
|
||||||
.#*
|
.#*
|
||||||
*#
|
*#
|
||||||
|
|
|
||||||
155
.golangci.yml
155
.golangci.yml
|
|
@ -1,6 +1,7 @@
|
||||||
# This file configures github.com/golangci/golangci-lint.
|
# This file configures github.com/golangci/golangci-lint.
|
||||||
|
|
||||||
run:
|
run:
|
||||||
|
go: '1.18'
|
||||||
timeout: 20m
|
timeout: 20m
|
||||||
tests: true
|
tests: true
|
||||||
# default is true. Enables skipping of directories:
|
# default is true. Enables skipping of directories:
|
||||||
|
|
@ -8,28 +9,139 @@ run:
|
||||||
skip-dirs-use-default: true
|
skip-dirs-use-default: true
|
||||||
skip-files:
|
skip-files:
|
||||||
- core/genesis_alloc.go
|
- core/genesis_alloc.go
|
||||||
|
- gen_.*.go
|
||||||
|
- .*_gen.go
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
|
||||||
enable:
|
enable:
|
||||||
- deadcode
|
|
||||||
- goconst
|
- goconst
|
||||||
- goimports
|
- goimports
|
||||||
- gosimple
|
|
||||||
- govet
|
|
||||||
- ineffassign
|
|
||||||
- misspell
|
- misspell
|
||||||
# - staticcheck
|
|
||||||
- unconvert
|
- unconvert
|
||||||
# - unused
|
- bodyclose
|
||||||
- varcheck
|
- containedctx
|
||||||
|
- contextcheck
|
||||||
|
- decorder
|
||||||
|
- durationcheck
|
||||||
|
- errchkjson
|
||||||
|
- errname
|
||||||
|
- exhaustive
|
||||||
|
- exportloopref
|
||||||
|
- gocognit
|
||||||
|
- gofmt
|
||||||
|
# - gomnd
|
||||||
|
- gomoddirectives
|
||||||
|
- gosec
|
||||||
|
- makezero
|
||||||
|
- nestif
|
||||||
|
- nilerr
|
||||||
|
- nilnil
|
||||||
|
- noctx
|
||||||
|
#- nosprintfhostport # TODO: do we use IPv6?
|
||||||
|
- paralleltest
|
||||||
|
- prealloc
|
||||||
|
- predeclared
|
||||||
|
#- promlinter
|
||||||
|
#- revive
|
||||||
|
# - tagliatelle
|
||||||
|
- tenv
|
||||||
|
- thelper
|
||||||
|
- tparallel
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- wsl
|
||||||
|
#- errorlint causes stack overflow. TODO: recheck after each golangci update
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
gofmt:
|
gofmt:
|
||||||
simplify: true
|
simplify: true
|
||||||
|
auto-fix: false
|
||||||
|
|
||||||
goconst:
|
goconst:
|
||||||
min-len: 3 # minimum length of string constant
|
min-len: 3 # minimum length of string constant
|
||||||
min-occurrences: 6 # minimum number of occurrences
|
min-occurrences: 2 # minimum number of occurrences
|
||||||
|
numbers: true
|
||||||
|
|
||||||
|
goimports:
|
||||||
|
local-prefixes: github.com/ethereum/go-ethereum
|
||||||
|
|
||||||
|
nestif:
|
||||||
|
min-complexity: 5
|
||||||
|
|
||||||
|
prealloc:
|
||||||
|
for-loops: true
|
||||||
|
|
||||||
|
gocritic:
|
||||||
|
# Which checks should be enabled; can't be combined with 'disabled-checks';
|
||||||
|
# See https://go-critic.github.io/overview#checks-overview
|
||||||
|
# To check which checks are enabled run `GL_DEBUG=gocritic ./build/bin/golangci-lint run`
|
||||||
|
# By default list of stable checks is used.
|
||||||
|
enabled-checks:
|
||||||
|
- badLock
|
||||||
|
- filepathJoin
|
||||||
|
- sortSlice
|
||||||
|
- sprintfQuotedString
|
||||||
|
- syncMapLoadAndDelete
|
||||||
|
- weakCond
|
||||||
|
- boolExprSimplify
|
||||||
|
- httpNoBody
|
||||||
|
- ioutilDeprecated
|
||||||
|
- nestingReduce
|
||||||
|
- preferFilepathJoin
|
||||||
|
- redundantSprint
|
||||||
|
- stringConcatSimplify
|
||||||
|
- timeExprSimplify
|
||||||
|
- typeAssertChain
|
||||||
|
- yodaStyleExpr
|
||||||
|
- truncateCmp
|
||||||
|
- equalFold
|
||||||
|
- preferDecodeRune
|
||||||
|
- preferFprint
|
||||||
|
- preferStringWriter
|
||||||
|
- preferWriteByte
|
||||||
|
- sliceClear
|
||||||
|
#- ruleguard
|
||||||
|
|
||||||
|
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
|
||||||
|
disabled-checks:
|
||||||
|
- regexpMust
|
||||||
|
- exitAfterDefer
|
||||||
|
- dupBranchBody
|
||||||
|
- singleCaseSwitch
|
||||||
|
- unlambda
|
||||||
|
- captLocal
|
||||||
|
- commentFormatting
|
||||||
|
- ifElseChain
|
||||||
|
- importShadow
|
||||||
|
- builtinShadow
|
||||||
|
|
||||||
|
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
|
||||||
|
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
|
||||||
|
enabled-tags:
|
||||||
|
- performance
|
||||||
|
- diagnostic
|
||||||
|
- opinionated
|
||||||
|
- style
|
||||||
|
disabled-tags:
|
||||||
|
- experimental
|
||||||
|
govet:
|
||||||
|
disable:
|
||||||
|
- deepequalerrors
|
||||||
|
- fieldalignment
|
||||||
|
- shadow
|
||||||
|
- unsafeptr
|
||||||
|
check-shadowing: true
|
||||||
|
enable-all: true
|
||||||
|
settings:
|
||||||
|
printf:
|
||||||
|
# Run `go tool vet help printf` to see available settings for `printf` analyzer.
|
||||||
|
funcs:
|
||||||
|
- (github.com/ethereum/go-ethereum/log.Logger).Trace
|
||||||
|
- (github.com/ethereum/go-ethereum/log.Logger).Debug
|
||||||
|
- (github.com/ethereum/go-ethereum/log.Logger).Info
|
||||||
|
- (github.com/ethereum/go-ethereum/log.Logger).Warn
|
||||||
|
- (github.com/ethereum/go-ethereum/log.Logger).Error
|
||||||
|
- (github.com/ethereum/go-ethereum/log.Logger).Crit
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
|
|
@ -48,3 +160,28 @@ issues:
|
||||||
- path: cmd/faucet/
|
- path: cmd/faucet/
|
||||||
linters:
|
linters:
|
||||||
- deadcode
|
- deadcode
|
||||||
|
# Exclude some linters from running on tests files.
|
||||||
|
- path: test\.go
|
||||||
|
linters:
|
||||||
|
- gosec
|
||||||
|
- unused
|
||||||
|
- deadcode
|
||||||
|
- gocritic
|
||||||
|
- path: cmd/devp2p
|
||||||
|
linters:
|
||||||
|
- gosec
|
||||||
|
- unused
|
||||||
|
- deadcode
|
||||||
|
- gocritic
|
||||||
|
- path: metrics/sample\.go
|
||||||
|
linters:
|
||||||
|
- gosec
|
||||||
|
- gocritic
|
||||||
|
- path: p2p/simulations
|
||||||
|
linters:
|
||||||
|
- gosec
|
||||||
|
- gocritic
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
max-same-issues: 0
|
||||||
|
#new: true
|
||||||
|
new-from-rev: origin/master
|
||||||
|
|
@ -7,7 +7,7 @@ release:
|
||||||
|
|
||||||
builds:
|
builds:
|
||||||
- id: darwin-amd64
|
- id: darwin-amd64
|
||||||
main: ./cmd/geth
|
main: ./cmd/cli
|
||||||
binary: bor
|
binary: bor
|
||||||
goos:
|
goos:
|
||||||
- darwin
|
- darwin
|
||||||
|
|
@ -22,7 +22,7 @@ builds:
|
||||||
-s -w
|
-s -w
|
||||||
|
|
||||||
- id: darwin-arm64
|
- id: darwin-arm64
|
||||||
main: ./cmd/geth
|
main: ./cmd/cli
|
||||||
binary: bor
|
binary: bor
|
||||||
goos:
|
goos:
|
||||||
- darwin
|
- darwin
|
||||||
|
|
@ -37,7 +37,7 @@ builds:
|
||||||
-s -w
|
-s -w
|
||||||
|
|
||||||
- id: linux-amd64
|
- id: linux-amd64
|
||||||
main: ./cmd/geth
|
main: ./cmd/cli
|
||||||
binary: bor
|
binary: bor
|
||||||
goos:
|
goos:
|
||||||
- linux
|
- linux
|
||||||
|
|
@ -53,7 +53,7 @@ builds:
|
||||||
-s -w -extldflags "-static"
|
-s -w -extldflags "-static"
|
||||||
|
|
||||||
- id: linux-arm64
|
- id: linux-arm64
|
||||||
main: ./cmd/geth
|
main: ./cmd/cli
|
||||||
binary: bor
|
binary: bor
|
||||||
goos:
|
goos:
|
||||||
- linux
|
- linux
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ RUN apt-get update -y && apt-get upgrade -y \
|
||||||
|
|
||||||
WORKDIR ${BOR_DIR}
|
WORKDIR ${BOR_DIR}
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN make bor-all
|
RUN make bor
|
||||||
|
|
||||||
|
RUN cp build/bin/bor /usr/local/bin/
|
||||||
|
|
||||||
ENV SHELL /bin/bash
|
ENV SHELL /bin/bash
|
||||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
EXPOSE 8545 8546 8547 30303 30303/udp
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
# Build Geth in a stock Go builder container
|
|
||||||
FROM golang:1.18.1-alpine as builder
|
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers git bash
|
|
||||||
|
|
||||||
ADD . /bor
|
|
||||||
RUN cd /bor && make bor-all
|
|
||||||
|
|
||||||
CMD ["/bin/bash"]
|
|
||||||
|
|
||||||
# Pull Bor into a second stage deploy alpine container
|
|
||||||
FROM alpine:latest
|
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
|
||||||
COPY --from=builder /bor/build/bin/bor /usr/local/bin/
|
|
||||||
COPY --from=builder /bor/build/bin/bootnode /usr/local/bin/
|
|
||||||
|
|
||||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
|
||||||
71
Makefile
71
Makefile
|
|
@ -2,27 +2,35 @@
|
||||||
# with Go source code. If you know what GOPATH is then you probably
|
# with Go source code. If you know what GOPATH is then you probably
|
||||||
# don't need to bother with make.
|
# don't need to bother with make.
|
||||||
|
|
||||||
.PHONY: geth android ios evm all test clean
|
.PHONY: geth android ios geth-cross evm all test clean docs
|
||||||
|
.PHONY: geth-linux geth-linux-386 geth-linux-amd64 geth-linux-mips64 geth-linux-mips64le
|
||||||
|
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
|
||||||
|
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
|
||||||
|
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
|
||||||
|
|
||||||
GOBIN = ./build/bin
|
|
||||||
GO ?= latest
|
GO ?= latest
|
||||||
|
GOBIN = $(CURDIR)/build/bin
|
||||||
GORUN = env GO111MODULE=on go run
|
GORUN = env GO111MODULE=on go run
|
||||||
GOPATH = $(shell go env GOPATH)
|
GOPATH = $(shell go env GOPATH)
|
||||||
|
|
||||||
bor:
|
GIT_COMMIT ?= $(shell git rev-list -1 HEAD)
|
||||||
$(GORUN) build/ci.go install ./cmd/geth
|
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
mkdir -p $(GOPATH)/bin/
|
GIT_TAG ?= $(shell git describe --tags `git rev-list --tags="v*" --max-count=1`)
|
||||||
cp $(GOBIN)/geth $(GOBIN)/bor
|
|
||||||
cp $(GOBIN)/* $(GOPATH)/bin/
|
|
||||||
|
|
||||||
bor-all:
|
PACKAGE = github.com/ethereum/go-ethereum
|
||||||
$(GORUN) build/ci.go install
|
GO_FLAGS += -buildvcs=false
|
||||||
|
GO_FLAGS += -ldflags "-X ${PACKAGE}/params.GitCommit=${GIT_COMMIT} -X ${PACKAGE}/params.GitBranch=${GIT_BRANCH} -X ${PACKAGE}/params.GitTag=${GIT_TAG}"
|
||||||
|
|
||||||
|
TESTALL = $$(go list ./... | grep -v go-ethereum/cmd/)
|
||||||
|
TESTE2E = ./tests/...
|
||||||
|
GOTEST = GODEBUG=cgocheck=0 go test $(GO_FLAGS) -p 1
|
||||||
|
|
||||||
|
bor:
|
||||||
mkdir -p $(GOPATH)/bin/
|
mkdir -p $(GOPATH)/bin/
|
||||||
cp $(GOBIN)/geth $(GOBIN)/bor
|
go build -o $(GOBIN)/bor ./cmd/cli/main.go
|
||||||
cp $(GOBIN)/* $(GOPATH)/bin/
|
|
||||||
|
|
||||||
protoc:
|
protoc:
|
||||||
protoc --go_out=. --go-grpc_out=. ./command/server/proto/*.proto
|
protoc --go_out=. --go-grpc_out=. ./internal/cli/server/proto/*.proto
|
||||||
|
|
||||||
geth:
|
geth:
|
||||||
$(GORUN) build/ci.go install ./cmd/geth
|
$(GORUN) build/ci.go install ./cmd/geth
|
||||||
|
|
@ -45,11 +53,29 @@ ios:
|
||||||
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
|
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
|
||||||
|
|
||||||
test:
|
test:
|
||||||
# Skip mobile and cmd tests since they are being deprecated
|
$(GOTEST) --timeout 5m -shuffle=on -cover -coverprofile=cover.out $(TESTALL)
|
||||||
go test -v $$(go list ./... | grep -v go-ethereum/cmd/) -cover -coverprofile=cover.out
|
|
||||||
|
|
||||||
lint: ## Run linters.
|
test-race:
|
||||||
$(GORUN) build/ci.go lint
|
$(GOTEST) --timeout 15m -race -shuffle=on $(TESTALL)
|
||||||
|
|
||||||
|
test-integration:
|
||||||
|
$(GOTEST) --timeout 30m -tags integration $(TESTE2E)
|
||||||
|
|
||||||
|
escape:
|
||||||
|
cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out
|
||||||
|
|
||||||
|
lint:
|
||||||
|
@./build/bin/golangci-lint run --config ./.golangci.yml
|
||||||
|
|
||||||
|
lintci-deps:
|
||||||
|
rm -f ./build/bin/golangci-lint
|
||||||
|
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./build/bin v1.46.0
|
||||||
|
|
||||||
|
goimports:
|
||||||
|
goimports -local "$(PACKAGE)" -w .
|
||||||
|
|
||||||
|
docs:
|
||||||
|
$(GORUN) cmd/clidoc/main.go -d ./docs/cli
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
env GO111MODULE=on go clean -cache
|
env GO111MODULE=on go clean -cache
|
||||||
|
|
@ -59,11 +85,13 @@ clean:
|
||||||
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
||||||
|
|
||||||
devtools:
|
devtools:
|
||||||
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
|
# Notice! If you adding new binary - add it also to tests/deps/fake.go file
|
||||||
env GOBIN= go install github.com/kevinburke/go-bindata/go-bindata@latest
|
$(GOBUILD) -o $(GOBIN)/stringer github.com/golang.org/x/tools/cmd/stringer
|
||||||
env GOBIN= go install github.com/fjl/gencodec@latest
|
$(GOBUILD) -o $(GOBIN)/go-bindata github.com/kevinburke/go-bindata/go-bindata
|
||||||
env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest
|
$(GOBUILD) -o $(GOBIN)/codecgen github.com/ugorji/go/codec/codecgen
|
||||||
env GOBIN= go install ./cmd/abigen
|
$(GOBUILD) -o $(GOBIN)/abigen ./cmd/abigen
|
||||||
|
$(GOBUILD) -o $(GOBIN)/mockgen github.com/golang/mock/mockgen
|
||||||
|
$(GOBUILD) -o $(GOBIN)/protoc-gen-go github.com/golang/protobuf/protoc-gen-go
|
||||||
PATH=$(GOBIN):$(PATH) go generate ./common
|
PATH=$(GOBIN):$(PATH) go generate ./common
|
||||||
PATH=$(GOBIN):$(PATH) go generate ./core/types
|
PATH=$(GOBIN):$(PATH) go generate ./core/types
|
||||||
PATH=$(GOBIN):$(PATH) go generate ./consensus/bor
|
PATH=$(GOBIN):$(PATH) go generate ./consensus/bor
|
||||||
|
|
@ -71,7 +99,6 @@ devtools:
|
||||||
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
||||||
|
|
||||||
# Cross Compilation Targets (xgo)
|
# Cross Compilation Targets (xgo)
|
||||||
|
|
||||||
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
|
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
|
||||||
@echo "Full cross compilation done:"
|
@echo "Full cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/geth-*
|
@ls -ld $(GOBIN)/geth-*
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -63,12 +63,6 @@ them using your favourite package manager. Once the dependencies are installed,
|
||||||
$ make bor
|
$ make bor
|
||||||
```
|
```
|
||||||
|
|
||||||
- or, to build the full suite of utilities:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ make bor-all
|
|
||||||
```
|
|
||||||
|
|
||||||
### Make awesome changes!
|
### Make awesome changes!
|
||||||
|
|
||||||
1. Create new branch for your changes
|
1. Create new branch for your changes
|
||||||
|
|
@ -113,12 +107,6 @@ them using your favourite package manager. Once the dependencies are installed,
|
||||||
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
||||||
|
|
||||||
|
|
||||||
Build the beta client:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
go build -o bor-beta command/*.go
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
|
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/goleak"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/leak"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -38,6 +41,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSimulatedBackend(t *testing.T) {
|
func TestSimulatedBackend(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t, leak.IgnoreList()...)
|
||||||
|
|
||||||
var gasLimit uint64 = 8000029
|
var gasLimit uint64 = 8000029
|
||||||
key, _ := crypto.GenerateKey() // nolint: gosec
|
key, _ := crypto.GenerateKey() // nolint: gosec
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,25 @@
|
||||||
[Service]
|
[Service]
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5s
|
RestartSec=5s
|
||||||
ExecStart=/usr/local/bin/bor \
|
ExecStart=/usr/local/bin/bor server \
|
||||||
--bor-mumbai \
|
-chain=mumbai \
|
||||||
# --bor-mainnet \
|
# -chain=mainnet \
|
||||||
--datadir /var/lib/bor/data \
|
-datadir /var/lib/bor/data \
|
||||||
--bootnodes "enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303,enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303"
|
-metrics \
|
||||||
|
-metrics.prometheus-addr="127.0.0.1:7071" \
|
||||||
|
-bootnodes "enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303,enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303"
|
||||||
# Validator params
|
# Validator params
|
||||||
# Uncomment and configure the following lines in case you run a validator
|
# Uncomment and configure the following lines in case you run a validator. Don't forget to add backslash (\)
|
||||||
# --keystore /var/lib/bor/keystore \
|
# to previous command line.
|
||||||
# --unlock [VALIDATOR ADDRESS] \
|
# -keystore /var/lib/bor/keystore \
|
||||||
# --password /var/lib/bor/password.txt \
|
# -unlock [VALIDATOR ADDRESS] \
|
||||||
# --allow-insecure-unlock \
|
# -password /var/lib/bor/password.txt \
|
||||||
# --nodiscover --maxpeers 1 \
|
# -allow-insecure-unlock \
|
||||||
# --mine
|
# -nodiscover -maxpeers 1 \
|
||||||
|
# -miner.etherbase [VALIDATOR ADDRESS] \
|
||||||
|
# -mine
|
||||||
Type=simple
|
Type=simple
|
||||||
User=root
|
User=ubuntu
|
||||||
KillSignal=SIGINT
|
KillSignal=SIGINT
|
||||||
TimeoutStopSec=120
|
TimeoutStopSec=120
|
||||||
|
|
||||||
|
|
|
||||||
77
cmd/clidoc/main.go
Normal file
77
cmd/clidoc/main.go
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/internal/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultDir string = "./docs/cli"
|
||||||
|
DefaultMainPage string = "README.md"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
commands := cli.Commands()
|
||||||
|
|
||||||
|
dest := flag.String("d", DefaultDir, "Destination directory where the docs will be generated")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
dirPath := filepath.Join(".", *dest)
|
||||||
|
if err := os.MkdirAll(dirPath, os.ModePerm); err != nil {
|
||||||
|
log.Fatalln("Failed to create directory.", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mainPage := []string{
|
||||||
|
"# Bor command line interface",
|
||||||
|
"## Commands",
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := make([]string, len(commands))
|
||||||
|
i := 0
|
||||||
|
|
||||||
|
for k := range commands {
|
||||||
|
keys[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, name := range keys {
|
||||||
|
cmd, err := commands[name]()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error occurred when inspecting bor command %s: %s", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := strings.ReplaceAll(name, " ", "_") + ".md"
|
||||||
|
|
||||||
|
overwriteFile(filepath.Join(dirPath, fileName), cmd.MarkDown())
|
||||||
|
mainPage = append(mainPage, "- [```"+name+"```](./"+fileName+")")
|
||||||
|
}
|
||||||
|
|
||||||
|
overwriteFile(filepath.Join(dirPath, DefaultMainPage), strings.Join(mainPage, "\n\n"))
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func overwriteFile(filePath string, text string) {
|
||||||
|
log.Printf("Writing to page: %s\n", filePath)
|
||||||
|
|
||||||
|
f, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = f.WriteString(text); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = f.Close(); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
common/debug/debug.go
Normal file
28
common/debug/debug.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Callers returns given number of callers with packages
|
||||||
|
func Callers(show int) []string {
|
||||||
|
fpcs := make([]uintptr, show)
|
||||||
|
|
||||||
|
n := runtime.Callers(2, fpcs)
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
callers := make([]string, 0, len(fpcs))
|
||||||
|
|
||||||
|
for _, p := range fpcs {
|
||||||
|
caller := runtime.FuncForPC(p - 1)
|
||||||
|
if caller == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
callers = append(callers, caller.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
return callers
|
||||||
|
}
|
||||||
23
common/leak/ignore_list.go
Normal file
23
common/leak/ignore_list.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package leak
|
||||||
|
|
||||||
|
import "go.uber.org/goleak"
|
||||||
|
|
||||||
|
func IgnoreList() []goleak.Option {
|
||||||
|
return []goleak.Option{
|
||||||
|
// a list of goroutne leaks that hard to fix due to external dependencies or too big refactoring needed
|
||||||
|
goleak.IgnoreTopFunction("github.com/ethereum/go-ethereum/core.(*txSenderCacher).cache"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/rjeczalik/notify.(*recursiveTree).dispatch"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/rjeczalik/notify.(*recursiveTree).internal"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/rjeczalik/notify.(*nonrecursiveTree).dispatch"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/rjeczalik/notify.(*nonrecursiveTree).internal"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/rjeczalik/notify._Cfunc_CFRunLoopRun"),
|
||||||
|
|
||||||
|
// todo: this leaks should be fixed
|
||||||
|
goleak.IgnoreTopFunction("github.com/ethereum/go-ethereum/metrics.(*meterArbiter).tick"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/ethereum/go-ethereum/consensus/ethash.(*remoteSealer).loop"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/ethereum/go-ethereum/core.(*BlockChain).updateFutureBlocks"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/ethereum/go-ethereum/core/state/snapshot.(*diskLayer).generate"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/ethereum/go-ethereum/accounts/abi/bind/backends.nullSubscription.func1"),
|
||||||
|
goleak.IgnoreTopFunction("github.com/ethereum/go-ethereum/eth/filters.(*EventSystem).eventLoop"),
|
||||||
|
}
|
||||||
|
}
|
||||||
11
common/set/slice.go
Normal file
11
common/set/slice.go
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
package set
|
||||||
|
|
||||||
|
func New[T comparable](slice []T) map[T]struct{} {
|
||||||
|
m := make(map[T]struct{}, len(slice))
|
||||||
|
|
||||||
|
for _, el := range slice {
|
||||||
|
m[el] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
6
consensus/bor/abi/interface.go
Normal file
6
consensus/bor/abi/interface.go
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package abi
|
||||||
|
|
||||||
|
type ABI interface {
|
||||||
|
Pack(name string, args ...interface{}) ([]byte, error)
|
||||||
|
UnpackIntoInterface(v interface{}, name string, data []byte) error
|
||||||
|
}
|
||||||
|
|
@ -4,14 +4,17 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/xsleonard/go-merkle"
|
"github.com/xsleonard/go-merkle"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
@ -43,9 +46,88 @@ func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BlockSigners struct {
|
||||||
|
Signers []difficultiesKV
|
||||||
|
Diff int
|
||||||
|
Author common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
type difficultiesKV struct {
|
||||||
|
Signer common.Address
|
||||||
|
Difficulty uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func rankMapDifficulties(values map[common.Address]uint64) []difficultiesKV {
|
||||||
|
ss := make([]difficultiesKV, 0, len(values))
|
||||||
|
for k, v := range values {
|
||||||
|
ss = append(ss, difficultiesKV{k, v})
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(ss, func(i, j int) bool {
|
||||||
|
return ss[i].Difficulty > ss[j].Difficulty
|
||||||
|
})
|
||||||
|
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSnapshotProposerSequence retrieves the in-turn signers of all sprints in a span
|
||||||
|
func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigners, error) {
|
||||||
|
snapNumber := *number - 1
|
||||||
|
|
||||||
|
var difficulties = make(map[common.Address]uint64)
|
||||||
|
|
||||||
|
snap, err := api.GetSnapshot(&snapNumber)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return BlockSigners{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
proposer := snap.ValidatorSet.GetProposer().Address
|
||||||
|
proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
|
||||||
|
|
||||||
|
signers := snap.signers()
|
||||||
|
for i := 0; i < len(signers); i++ {
|
||||||
|
tempIndex := i
|
||||||
|
if tempIndex < proposerIndex {
|
||||||
|
tempIndex = tempIndex + len(signers)
|
||||||
|
}
|
||||||
|
|
||||||
|
difficulties[signers[i]] = uint64(len(signers) - (tempIndex - proposerIndex))
|
||||||
|
}
|
||||||
|
|
||||||
|
rankedDifficulties := rankMapDifficulties(difficulties)
|
||||||
|
|
||||||
|
author, err := api.GetAuthor(number)
|
||||||
|
if err != nil {
|
||||||
|
return BlockSigners{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := int(difficulties[*author])
|
||||||
|
blockSigners := &BlockSigners{
|
||||||
|
Signers: rankedDifficulties,
|
||||||
|
Diff: diff,
|
||||||
|
Author: *author,
|
||||||
|
}
|
||||||
|
|
||||||
|
return *blockSigners, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSnapshotProposer retrieves the in-turn signer at a given block.
|
||||||
|
func (api *API) GetSnapshotProposer(number *rpc.BlockNumber) (common.Address, error) {
|
||||||
|
*number -= 1
|
||||||
|
snap, err := api.GetSnapshot(number)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return common.Address{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return snap.ValidatorSet.GetProposer().Address, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetAuthor retrieves the author a block.
|
// GetAuthor retrieves the author a block.
|
||||||
func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) {
|
func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) {
|
||||||
// Retrieve the requested block number (or current if none requested)
|
// Retrieve the requested block number (or current if none requested)
|
||||||
|
|
@ -59,7 +141,9 @@ func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
author, err := api.bor.Author(header)
|
author, err := api.bor.Author(header)
|
||||||
|
|
||||||
return &author, err
|
return &author, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,6 +153,7 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,10 +170,13 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.signers(), nil
|
return snap.signers(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,10 +186,13 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.signers(), nil
|
return snap.signers(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,15 +202,17 @@ func (api *API) GetCurrentProposer() (common.Address, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.ValidatorSet.GetProposer().Address, nil
|
return snap.ValidatorSet.GetProposer().Address, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentValidators gets the current validators
|
// GetCurrentValidators gets the current validators
|
||||||
func (api *API) GetCurrentValidators() ([]*Validator, error) {
|
func (api *API) GetCurrentValidators() ([]*valset.Validator, error) {
|
||||||
snap, err := api.GetSnapshot(nil)
|
snap, err := api.GetSnapshot(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make([]*Validator, 0), err
|
return make([]*valset.Validator, 0), err
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap.ValidatorSet.Validators, nil
|
return snap.ValidatorSet.Validators, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,26 +221,36 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
if err := api.initializeRootHashCache(); err != nil {
|
if err := api.initializeRootHashCache(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
key := getRootHashKey(start, end)
|
key := getRootHashKey(start, end)
|
||||||
|
|
||||||
if root, known := api.rootHashCache.Get(key); known {
|
if root, known := api.rootHashCache.Get(key); known {
|
||||||
return root.(string), nil
|
return root.(string), nil
|
||||||
}
|
}
|
||||||
length := uint64(end - start + 1)
|
|
||||||
|
length := end - start + 1
|
||||||
|
|
||||||
if length > MaxCheckpointLength {
|
if length > MaxCheckpointLength {
|
||||||
return "", &MaxCheckpointLengthExceededError{start, end}
|
return "", &MaxCheckpointLengthExceededError{start, end}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
|
currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
|
||||||
|
|
||||||
if start > end || end > currentHeaderNumber {
|
if start > end || end > currentHeaderNumber {
|
||||||
return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber}
|
return "", &valset.InvalidStartEndBlockError{Start: start, End: end, CurrentHeader: currentHeaderNumber}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockHeaders := make([]*types.Header, end-start+1)
|
blockHeaders := make([]*types.Header, end-start+1)
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
concurrent := make(chan bool, 20)
|
concurrent := make(chan bool, 20)
|
||||||
|
|
||||||
for i := start; i <= end; i++ {
|
for i := start; i <= end; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
concurrent <- true
|
concurrent <- true
|
||||||
|
|
||||||
go func(number uint64) {
|
go func(number uint64) {
|
||||||
blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number))
|
blockHeaders[number-start] = api.chain.GetHeaderByNumber(number)
|
||||||
|
|
||||||
<-concurrent
|
<-concurrent
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(i)
|
}(i)
|
||||||
|
|
@ -156,6 +259,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
close(concurrent)
|
close(concurrent)
|
||||||
|
|
||||||
headers := make([][32]byte, nextPowerOfTwo(length))
|
headers := make([][32]byte, nextPowerOfTwo(length))
|
||||||
|
|
||||||
for i := 0; i < len(blockHeaders); i++ {
|
for i := 0; i < len(blockHeaders); i++ {
|
||||||
blockHeader := blockHeaders[i]
|
blockHeader := blockHeaders[i]
|
||||||
header := crypto.Keccak256(appendBytes32(
|
header := crypto.Keccak256(appendBytes32(
|
||||||
|
|
@ -166,6 +270,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
))
|
))
|
||||||
|
|
||||||
var arr [32]byte
|
var arr [32]byte
|
||||||
|
|
||||||
copy(arr[:], header)
|
copy(arr[:], header)
|
||||||
headers[i] = arr
|
headers[i] = arr
|
||||||
}
|
}
|
||||||
|
|
@ -174,8 +279,10 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
|
if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := hex.EncodeToString(tree.Root().Hash)
|
root := hex.EncodeToString(tree.Root().Hash)
|
||||||
api.rootHashCache.Add(key, root)
|
api.rootHashCache.Add(key, root)
|
||||||
|
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,6 +291,7 @@ func (api *API) initializeRootHashCache() error {
|
||||||
if api.rootHashCache == nil {
|
if api.rootHashCache == nil {
|
||||||
api.rootHashCache, err = lru.NewARC(10)
|
api.rootHashCache, err = lru.NewARC(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
14
consensus/bor/api/caller.go
Normal file
14
consensus/bor/api/caller.go
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate mockgen -destination=./caller_mock.go -package=api . Caller
|
||||||
|
type Caller interface {
|
||||||
|
Call(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *ethapi.StateOverride) (hexutil.Bytes, error)
|
||||||
|
}
|
||||||
53
consensus/bor/api/caller_mock.go
Normal file
53
consensus/bor/api/caller_mock.go
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/ethereum/go-ethereum/consensus/bor/api (interfaces: Caller)
|
||||||
|
|
||||||
|
// Package api is a generated GoMock package.
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
hexutil "github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
ethapi "github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockCaller is a mock of Caller interface.
|
||||||
|
type MockCaller struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockCallerMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockCallerMockRecorder is the mock recorder for MockCaller.
|
||||||
|
type MockCallerMockRecorder struct {
|
||||||
|
mock *MockCaller
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockCaller creates a new mock instance.
|
||||||
|
func NewMockCaller(ctrl *gomock.Controller) *MockCaller {
|
||||||
|
mock := &MockCaller{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockCallerMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockCaller) EXPECT() *MockCallerMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call mocks base method.
|
||||||
|
func (m *MockCaller) Call(arg0 context.Context, arg1 ethapi.TransactionArgs, arg2 rpc.BlockNumberOrHash, arg3 *ethapi.StateOverride) (hexutil.Bytes, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Call", arg0, arg1, arg2, arg3)
|
||||||
|
ret0, _ := ret[0].(hexutil.Bytes)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call indicates an expected call of Call.
|
||||||
|
func (mr *MockCallerMockRecorder) Call(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockCaller)(nil).Call), arg0, arg1, arg2, arg3)
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -12,10 +14,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenesisContractChange(t *testing.T) {
|
func TestGenesisContractChange(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
addr0 := common.Address{0x1}
|
addr0 := common.Address{0x1}
|
||||||
|
|
||||||
b := &Bor{
|
b := &Bor{
|
||||||
|
|
@ -101,6 +104,8 @@ func TestGenesisContractChange(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
// As part of the EIP-1559 fork in mumbai, an incorrect seal hash
|
// As part of the EIP-1559 fork in mumbai, an incorrect seal hash
|
||||||
// was used for Bor that did not included the BaseFee. The Jaipur
|
// was used for Bor that did not included the BaseFee. The Jaipur
|
||||||
// block is a hard fork to fix that.
|
// block is a hard fork to fix that.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package bor
|
package clerk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
133
consensus/bor/contract/client.go
Normal file
133
consensus/bor/contract/client.go
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -3,37 +3,10 @@ package bor
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TotalVotingPowerExceededError is returned when the maximum allowed total voting power is exceeded
|
|
||||||
type TotalVotingPowerExceededError struct {
|
|
||||||
Sum int64
|
|
||||||
Validators []*Validator
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *TotalVotingPowerExceededError) Error() string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"Total voting power should be guarded to not exceed %v; got: %v; for validator set: %v",
|
|
||||||
MaxTotalVotingPower,
|
|
||||||
e.Sum,
|
|
||||||
e.Validators,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidStartEndBlockError struct {
|
|
||||||
Start uint64
|
|
||||||
End uint64
|
|
||||||
CurrentHeader uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *InvalidStartEndBlockError) Error() string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"Invalid parameters start: %d and end block: %d params",
|
|
||||||
e.Start,
|
|
||||||
e.End,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MaxCheckpointLengthExceededError struct {
|
type MaxCheckpointLengthExceededError struct {
|
||||||
Start uint64
|
Start uint64
|
||||||
End uint64
|
End uint64
|
||||||
|
|
@ -129,7 +102,7 @@ type InvalidStateReceivedError struct {
|
||||||
Number uint64
|
Number uint64
|
||||||
LastStateID uint64
|
LastStateID uint64
|
||||||
To *time.Time
|
To *time.Time
|
||||||
Event *EventRecordWithTime
|
Event *clerk.EventRecordWithTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *InvalidStateReceivedError) Error() string {
|
func (e *InvalidStateReceivedError) Error() string {
|
||||||
|
|
|
||||||
16
consensus/bor/genesis.go
Normal file
16
consensus/bor/genesis.go
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/statefull"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate mockgen -destination=./genesis_contract_mock.go -package=bor . GenesisContract
|
||||||
|
type GenesisContract interface {
|
||||||
|
CommitState(event *clerk.EventRecordWithTime, state *state.StateDB, header *types.Header, chCtx statefull.ChainContext) (uint64, error)
|
||||||
|
LastStateId(snapshotNumber uint64) (*big.Int, error)
|
||||||
|
}
|
||||||
69
consensus/bor/genesis_contract_mock.go
Normal file
69
consensus/bor/genesis_contract_mock.go
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: GenesisContract)
|
||||||
|
|
||||||
|
// Package bor is a generated GoMock package.
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
big "math/big"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
statefull "github.com/ethereum/go-ethereum/consensus/bor/statefull"
|
||||||
|
state "github.com/ethereum/go-ethereum/core/state"
|
||||||
|
types "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockGenesisContract is a mock of GenesisContract interface.
|
||||||
|
type MockGenesisContract struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockGenesisContractMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockGenesisContractMockRecorder is the mock recorder for MockGenesisContract.
|
||||||
|
type MockGenesisContractMockRecorder struct {
|
||||||
|
mock *MockGenesisContract
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockGenesisContract creates a new mock instance.
|
||||||
|
func NewMockGenesisContract(ctrl *gomock.Controller) *MockGenesisContract {
|
||||||
|
mock := &MockGenesisContract{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockGenesisContractMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockGenesisContract) EXPECT() *MockGenesisContractMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitState mocks base method.
|
||||||
|
func (m *MockGenesisContract) CommitState(arg0 *clerk.EventRecordWithTime, arg1 *state.StateDB, arg2 *types.Header, arg3 statefull.ChainContext) (uint64, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CommitState", arg0, arg1, arg2, arg3)
|
||||||
|
ret0, _ := ret[0].(uint64)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitState indicates an expected call of CommitState.
|
||||||
|
func (mr *MockGenesisContractMockRecorder) CommitState(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitState", reflect.TypeOf((*MockGenesisContract)(nil).CommitState), arg0, arg1, arg2, arg3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastStateId mocks base method.
|
||||||
|
func (m *MockGenesisContract) LastStateId(arg0 uint64) (*big.Int, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "LastStateId", arg0)
|
||||||
|
ret0, _ := ret[0].(*big.Int)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastStateId indicates an expected call of LastStateId.
|
||||||
|
func (mr *MockGenesisContractMockRecorder) LastStateId(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastStateId", reflect.TypeOf((*MockGenesisContract)(nil).LastStateId), arg0)
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
15
consensus/bor/heimdall.go
Normal file
15
consensus/bor/heimdall.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate mockgen -destination=../../tests/bor/mocks/IHeimdallClient.go -package=mocks . IHeimdallClient
|
||||||
|
type IHeimdallClient interface {
|
||||||
|
StateSyncEvents(fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error)
|
||||||
|
Span(spanID uint64) (*span.HeimdallSpan, error)
|
||||||
|
FetchLatestCheckpoint() (*checkpoint.Checkpoint, error)
|
||||||
|
Close()
|
||||||
|
}
|
||||||
22
consensus/bor/heimdall/checkpoint/checkpoint.go
Normal file
22
consensus/bor/heimdall/checkpoint/checkpoint.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package checkpoint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Checkpoint defines a response object type of bor checkpoint
|
||||||
|
type Checkpoint struct {
|
||||||
|
Proposer common.Address `json:"proposer"`
|
||||||
|
StartBlock *big.Int `json:"start_block"`
|
||||||
|
EndBlock *big.Int `json:"end_block"`
|
||||||
|
RootHash common.Hash `json:"root_hash"`
|
||||||
|
BorChainID string `json:"bor_chain_id"`
|
||||||
|
Timestamp uint64 `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckpointResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result Checkpoint `json:"result"`
|
||||||
|
}
|
||||||
243
consensus/bor/heimdall/client.go
Normal file
243
consensus/bor/heimdall/client.go
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
package heimdall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errShutdownDetected is returned if a shutdown was detected
|
||||||
|
var errShutdownDetected = errors.New("shutdown detected")
|
||||||
|
|
||||||
|
const (
|
||||||
|
stateFetchLimit = 50
|
||||||
|
apiHeimdallTimeout = 5 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type StateSyncEventsResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result []*clerk.EventRecordWithTime `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpanResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result span.HeimdallSpan `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HeimdallClient struct {
|
||||||
|
urlString string
|
||||||
|
client http.Client
|
||||||
|
closeCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHeimdallClient(urlString string) *HeimdallClient {
|
||||||
|
return &HeimdallClient{
|
||||||
|
urlString: urlString,
|
||||||
|
client: http.Client{
|
||||||
|
Timeout: apiHeimdallTimeout,
|
||||||
|
},
|
||||||
|
closeCh: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d"
|
||||||
|
fetchStateSyncEventsPath = "clerk/event-record/list"
|
||||||
|
fetchLatestCheckpoint = "/checkpoints/latest"
|
||||||
|
|
||||||
|
fetchSpanFormat = "bor/span/%d"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *HeimdallClient) StateSyncEvents(fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
||||||
|
eventRecords := make([]*clerk.EventRecordWithTime, 0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
url, err := stateSyncURL(h.urlString, fromID, to)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetching state sync events", "queryParams", url.RawQuery)
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[StateSyncEventsResponse](h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if response == nil || response.Result == nil {
|
||||||
|
// status 204
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
eventRecords = append(eventRecords, response.Result...)
|
||||||
|
|
||||||
|
if len(response.Result) < stateFetchLimit {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fromID += uint64(stateFetchLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.SliceStable(eventRecords, func(i, j int) bool {
|
||||||
|
return eventRecords[i].ID < eventRecords[j].ID
|
||||||
|
})
|
||||||
|
|
||||||
|
return eventRecords, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallClient) Span(spanID uint64) (*span.HeimdallSpan, error) {
|
||||||
|
url, err := spanURL(h.urlString, spanID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[SpanResponse](h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchLatestCheckpoint fetches the latest bor submitted checkpoint from heimdall
|
||||||
|
func (h *HeimdallClient) FetchLatestCheckpoint() (*checkpoint.Checkpoint, error) {
|
||||||
|
url, err := latestCheckpointURL(h.urlString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[checkpoint.CheckpointResponse](h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchWithRetry returns data from heimdall with retry
|
||||||
|
func FetchWithRetry[T any](client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) {
|
||||||
|
// attempt counter
|
||||||
|
attempt := 1
|
||||||
|
result := new(T)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), apiHeimdallTimeout)
|
||||||
|
|
||||||
|
// request data once
|
||||||
|
body, err := internalFetch(ctx, client, url)
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
if err == nil && body != nil {
|
||||||
|
err = json.Unmarshal(body, result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new ticker for retrying the request
|
||||||
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
log.Info("Retrying again in 5 seconds to fetch data from Heimdall", "path", url.Path, "attempt", attempt)
|
||||||
|
attempt++
|
||||||
|
select {
|
||||||
|
case <-closeCh:
|
||||||
|
log.Debug("Shutdown detected, terminating request")
|
||||||
|
|
||||||
|
return nil, errShutdownDetected
|
||||||
|
case <-ticker.C:
|
||||||
|
ctx, cancel = context.WithTimeout(context.Background(), apiHeimdallTimeout)
|
||||||
|
|
||||||
|
body, err = internalFetch(ctx, client, url)
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
if err == nil && body != nil {
|
||||||
|
err = json.Unmarshal(body, result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func spanURL(urlString string, spanID uint64) (*url.URL, error) {
|
||||||
|
return makeURL(urlString, fmt.Sprintf(fetchSpanFormat, spanID), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func stateSyncURL(urlString string, fromID uint64, to int64) (*url.URL, error) {
|
||||||
|
queryParams := fmt.Sprintf(fetchStateSyncEventsFormat, fromID, to, stateFetchLimit)
|
||||||
|
|
||||||
|
return makeURL(urlString, fetchStateSyncEventsPath, queryParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func latestCheckpointURL(urlString string) (*url.URL, error) {
|
||||||
|
return makeURL(urlString, fetchLatestCheckpoint, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) {
|
||||||
|
u, err := url.Parse(urlString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Path = rawPath
|
||||||
|
u.RawQuery = rawQuery
|
||||||
|
|
||||||
|
return u, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal fetch method
|
||||||
|
func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte, error) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
// check status code
|
||||||
|
if res.StatusCode != 200 && res.StatusCode != 204 {
|
||||||
|
return nil, fmt.Errorf("Error while fetching data from Heimdall")
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshall data from buffer
|
||||||
|
if res.StatusCode == 204 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get response
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close sends a signal to stop the running process
|
||||||
|
func (h *HeimdallClient) Close() {
|
||||||
|
close(h.closeCh)
|
||||||
|
h.client.CloseIdleConnections()
|
||||||
|
}
|
||||||
35
consensus/bor/heimdall/client_test.go
Normal file
35
consensus/bor/heimdall/client_test.go
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
package heimdall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSpanURL(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
url, err := spanURL("http://bor0", 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected = "http://bor0/bor/span/1"
|
||||||
|
|
||||||
|
if url.String() != expected {
|
||||||
|
t.Fatalf("expected URL %q, got %q", url.String(), expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateSyncURL(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
url, err := stateSyncURL("http://bor0", 10, 100)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected = "http://bor0/clerk/event-record/list?from-id=10&to-time=100&limit=50"
|
||||||
|
|
||||||
|
if url.String() != expected {
|
||||||
|
t.Fatalf("expected URL %q, got %q", url.String(), expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
20
consensus/bor/heimdall/span/span.go
Normal file
20
consensus/bor/heimdall/span/span.go
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
package span
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Span Bor represents a current bor span
|
||||||
|
type Span struct {
|
||||||
|
ID uint64 `json:"span_id" yaml:"span_id"`
|
||||||
|
StartBlock uint64 `json:"start_block" yaml:"start_block"`
|
||||||
|
EndBlock uint64 `json:"end_block" yaml:"end_block"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeimdallSpan represents span from heimdall APIs
|
||||||
|
type HeimdallSpan struct {
|
||||||
|
Span
|
||||||
|
ValidatorSet valset.ValidatorSet `json:"validator_set" yaml:"validator_set"`
|
||||||
|
SelectedProducers []valset.Validator `json:"selected_producers" yaml:"selected_producers"`
|
||||||
|
ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"`
|
||||||
|
}
|
||||||
200
consensus/bor/heimdall/span/spanner.go
Normal file
200
consensus/bor/heimdall/span/spanner.go
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
package span
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/statefull"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChainSpanner struct {
|
||||||
|
ethAPI api.Caller
|
||||||
|
validatorSet abi.ABI
|
||||||
|
chainConfig *params.ChainConfig
|
||||||
|
validatorContractAddress common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChainSpanner(ethAPI api.Caller, validatorSet abi.ABI, chainConfig *params.ChainConfig, validatorContractAddress common.Address) *ChainSpanner {
|
||||||
|
return &ChainSpanner{
|
||||||
|
ethAPI: ethAPI,
|
||||||
|
validatorSet: validatorSet,
|
||||||
|
chainConfig: chainConfig,
|
||||||
|
validatorContractAddress: validatorContractAddress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentSpan get current span from contract
|
||||||
|
func (c *ChainSpanner) GetCurrentSpan(headerHash common.Hash) (*Span, error) {
|
||||||
|
// block
|
||||||
|
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||||
|
|
||||||
|
// method
|
||||||
|
method := "getCurrentSpan"
|
||||||
|
|
||||||
|
data, err := c.validatorSet.Pack(method)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to pack tx for getCurrentSpan", "error", err)
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msgData := (hexutil.Bytes)(data)
|
||||||
|
toAddress := c.validatorContractAddress
|
||||||
|
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||||
|
|
||||||
|
// todo: would we like to have a timeout here?
|
||||||
|
result, err := c.ethAPI.Call(context.Background(), ethapi.TransactionArgs{
|
||||||
|
Gas: &gas,
|
||||||
|
To: &toAddress,
|
||||||
|
Data: &msgData,
|
||||||
|
}, blockNr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// span result
|
||||||
|
ret := new(struct {
|
||||||
|
Number *big.Int
|
||||||
|
StartBlock *big.Int
|
||||||
|
EndBlock *big.Int
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := c.validatorSet.UnpackIntoInterface(ret, method, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new span
|
||||||
|
span := Span{
|
||||||
|
ID: ret.Number.Uint64(),
|
||||||
|
StartBlock: ret.StartBlock.Uint64(),
|
||||||
|
EndBlock: ret.EndBlock.Uint64(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &span, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentValidators get current validators
|
||||||
|
func (c *ChainSpanner) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// method
|
||||||
|
const method = "getBorValidators"
|
||||||
|
|
||||||
|
data, err := c.validatorSet.Pack(method, big.NewInt(0).SetUint64(blockNumber))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to pack tx for getValidator", "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// call
|
||||||
|
msgData := (hexutil.Bytes)(data)
|
||||||
|
toAddress := c.validatorContractAddress
|
||||||
|
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||||
|
|
||||||
|
// block
|
||||||
|
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||||
|
|
||||||
|
result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
|
||||||
|
Gas: &gas,
|
||||||
|
To: &toAddress,
|
||||||
|
Data: &msgData,
|
||||||
|
}, blockNr, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ret0 = new([]common.Address)
|
||||||
|
ret1 = new([]*big.Int)
|
||||||
|
)
|
||||||
|
|
||||||
|
out := &[]interface{}{
|
||||||
|
ret0,
|
||||||
|
ret1,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.validatorSet.UnpackIntoInterface(out, method, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
valz := make([]*valset.Validator, len(*ret0))
|
||||||
|
for i, a := range *ret0 {
|
||||||
|
valz[i] = &valset.Validator{
|
||||||
|
Address: a,
|
||||||
|
VotingPower: (*ret1)[i].Int64(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valz, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const method = "commitSpan"
|
||||||
|
|
||||||
|
func (c *ChainSpanner) CommitSpan(heimdallSpan HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error {
|
||||||
|
// get validators bytes
|
||||||
|
validators := make([]valset.MinimalVal, 0, len(heimdallSpan.ValidatorSet.Validators))
|
||||||
|
for _, val := range heimdallSpan.ValidatorSet.Validators {
|
||||||
|
validators = append(validators, val.MinimalVal())
|
||||||
|
}
|
||||||
|
|
||||||
|
validatorBytes, err := rlp.EncodeToBytes(validators)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get producers bytes
|
||||||
|
producers := make([]valset.MinimalVal, 0, len(heimdallSpan.SelectedProducers))
|
||||||
|
for _, val := range heimdallSpan.SelectedProducers {
|
||||||
|
producers = append(producers, val.MinimalVal())
|
||||||
|
}
|
||||||
|
|
||||||
|
producerBytes, err := rlp.EncodeToBytes(producers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("✅ Committing new span",
|
||||||
|
"id", heimdallSpan.ID,
|
||||||
|
"startBlock", heimdallSpan.StartBlock,
|
||||||
|
"endBlock", heimdallSpan.EndBlock,
|
||||||
|
"validatorBytes", hex.EncodeToString(validatorBytes),
|
||||||
|
"producerBytes", hex.EncodeToString(producerBytes),
|
||||||
|
)
|
||||||
|
|
||||||
|
data, err := c.validatorSet.Pack(method,
|
||||||
|
big.NewInt(0).SetUint64(heimdallSpan.ID),
|
||||||
|
big.NewInt(0).SetUint64(heimdallSpan.StartBlock),
|
||||||
|
big.NewInt(0).SetUint64(heimdallSpan.EndBlock),
|
||||||
|
validatorBytes,
|
||||||
|
producerBytes,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to pack tx for commitSpan", "error", err)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get system message
|
||||||
|
msg := statefull.GetSystemMessage(c.validatorContractAddress, data)
|
||||||
|
|
||||||
|
// apply message
|
||||||
|
_, err = statefull.ApplyMessage(msg, state, header, c.chainConfig, chainContext)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -2,12 +2,12 @@ package bor
|
||||||
|
|
||||||
func appendBytes32(data ...[]byte) []byte {
|
func appendBytes32(data ...[]byte) []byte {
|
||||||
var result []byte
|
var result []byte
|
||||||
|
|
||||||
for _, v := range data {
|
for _, v := range data {
|
||||||
paddedV, err := convertTo32(v)
|
paddedV := convertTo32(v)
|
||||||
if err == nil {
|
|
||||||
result = append(result, paddedV[:]...)
|
result = append(result, paddedV[:]...)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,25 +24,29 @@ func nextPowerOfTwo(n uint64) uint64 {
|
||||||
n |= n >> 16
|
n |= n >> 16
|
||||||
n |= n >> 32
|
n |= n >> 32
|
||||||
n++
|
n++
|
||||||
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertTo32(input []byte) (output [32]byte, err error) {
|
func convertTo32(input []byte) (output [32]byte) {
|
||||||
l := len(input)
|
l := len(input)
|
||||||
if l > 32 || l == 0 {
|
if l > 32 || l == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(output[32-l:], input[:])
|
copy(output[32-l:], input[:])
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert(input []([32]byte)) [][]byte {
|
func convert(input []([32]byte)) [][]byte {
|
||||||
var output [][]byte
|
output := make([][]byte, 0, len(input))
|
||||||
|
|
||||||
for _, in := range input {
|
for _, in := range input {
|
||||||
newInput := make([]byte, len(in[:]))
|
newInput := make([]byte, len(in[:]))
|
||||||
copy(newInput, in[:])
|
copy(newInput, in[:])
|
||||||
output = append(output, newInput)
|
output = append(output, newInput)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,196 +0,0 @@
|
||||||
package bor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
stateFetchLimit = 50
|
|
||||||
)
|
|
||||||
|
|
||||||
// ResponseWithHeight defines a response object type that wraps an original
|
|
||||||
// response with a height.
|
|
||||||
type ResponseWithHeight struct {
|
|
||||||
Height string `json:"height"`
|
|
||||||
Result json.RawMessage `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checkpoint defines a response object type of bor checkpoint
|
|
||||||
type Checkpoint struct {
|
|
||||||
Proposer common.Address `json:"proposer"`
|
|
||||||
StartBlock *big.Int `json:"start_block"`
|
|
||||||
EndBlock *big.Int `json:"end_block"`
|
|
||||||
RootHash common.Hash `json:"root_hash"`
|
|
||||||
BorChainID string `json:"bor_chain_id"`
|
|
||||||
Timestamp uint64 `json:"timestamp"`
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:generate mockgen -destination=../../tests/bor/mocks/IHeimdallClient.go -package=mocks . IHeimdallClient
|
|
||||||
type IHeimdallClient interface {
|
|
||||||
Fetch(path string, query string) (*ResponseWithHeight, error)
|
|
||||||
FetchWithRetry(path string, query string) (*ResponseWithHeight, error)
|
|
||||||
FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error)
|
|
||||||
FetchLatestCheckpoint() (*Checkpoint, error)
|
|
||||||
Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
type HeimdallClient struct {
|
|
||||||
urlString string
|
|
||||||
client http.Client
|
|
||||||
closeCh chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
|
|
||||||
h := &HeimdallClient{
|
|
||||||
urlString: urlString,
|
|
||||||
client: http.Client{
|
|
||||||
Timeout: time.Duration(5 * time.Second),
|
|
||||||
},
|
|
||||||
closeCh: make(chan struct{}),
|
|
||||||
}
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) {
|
|
||||||
eventRecords := make([]*EventRecordWithTime, 0)
|
|
||||||
for {
|
|
||||||
queryParams := fmt.Sprintf("from-id=%d&to-time=%d&limit=%d", fromID, to, stateFetchLimit)
|
|
||||||
log.Info("Fetching state sync events", "queryParams", queryParams)
|
|
||||||
response, err := h.FetchWithRetry("clerk/event-record/list", queryParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var _eventRecords []*EventRecordWithTime
|
|
||||||
if response.Result == nil { // status 204
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(response.Result, &_eventRecords); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
eventRecords = append(eventRecords, _eventRecords...)
|
|
||||||
if len(_eventRecords) < stateFetchLimit {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fromID += uint64(stateFetchLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.SliceStable(eventRecords, func(i, j int) bool {
|
|
||||||
return eventRecords[i].ID < eventRecords[j].ID
|
|
||||||
})
|
|
||||||
return eventRecords, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchLatestCheckpoint fetches the latest bor submitted checkpoint from heimdall
|
|
||||||
func (h *HeimdallClient) FetchLatestCheckpoint() (*Checkpoint, error) {
|
|
||||||
checkpoint := &Checkpoint{}
|
|
||||||
|
|
||||||
response, err := h.Fetch("/checkpoints/latest", "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = json.Unmarshal(response.Result, checkpoint); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkpoint, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch fetches response from heimdall
|
|
||||||
func (h *HeimdallClient) Fetch(rawPath string, rawQuery string) (*ResponseWithHeight, error) {
|
|
||||||
u, err := url.Parse(h.urlString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
u.Path = rawPath
|
|
||||||
u.RawQuery = rawQuery
|
|
||||||
|
|
||||||
return h.internalFetch(u)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchWithRetry returns data from heimdall with retry
|
|
||||||
func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*ResponseWithHeight, error) {
|
|
||||||
u, err := url.Parse(h.urlString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
u.Path = rawPath
|
|
||||||
u.RawQuery = rawQuery
|
|
||||||
|
|
||||||
// attempt counter
|
|
||||||
attempt := 1
|
|
||||||
|
|
||||||
// request data once
|
|
||||||
res, err := h.internalFetch(u)
|
|
||||||
if err == nil && res != nil {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a new ticker for retrying the request
|
|
||||||
ticker := time.NewTicker(5 * time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
log.Info("Retrying again in 5 seconds to fetch data from Heimdall", "path", u.Path, "attempt", attempt)
|
|
||||||
attempt++
|
|
||||||
select {
|
|
||||||
case <-h.closeCh:
|
|
||||||
log.Debug("Shutdown detected, terminating request")
|
|
||||||
return nil, errShutdownDetected
|
|
||||||
case <-ticker.C:
|
|
||||||
res, err := h.internalFetch(u)
|
|
||||||
if err == nil && res != nil {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// internal fetch method
|
|
||||||
func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error) {
|
|
||||||
res, err := h.client.Get(u.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
// check status code
|
|
||||||
if res.StatusCode != 200 && res.StatusCode != 204 {
|
|
||||||
return nil, fmt.Errorf("Error while fetching data from Heimdall")
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmarshall data from buffer
|
|
||||||
var response ResponseWithHeight
|
|
||||||
if res.StatusCode == 204 {
|
|
||||||
return &response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// get response
|
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(body, &response); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close sends a signal to stop the running process
|
|
||||||
func (h *HeimdallClient) Close() {
|
|
||||||
close(h.closeCh)
|
|
||||||
h.client.CloseIdleConnections()
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +1,29 @@
|
||||||
package bor
|
package bor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Snapshot is the state of the authorization voting at a given point in time.
|
// Snapshot is the state of the authorization voting at a given point in time.
|
||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
config *params.BorConfig // Consensus engine parameters to fine tune behavior
|
config *params.BorConfig // Consensus engine parameters to fine tune behavior
|
||||||
ethAPI *ethapi.PublicBlockChainAPI
|
|
||||||
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
|
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
|
||||||
|
|
||||||
Number uint64 `json:"number"` // Block number where the snapshot was created
|
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||||
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
|
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
|
||||||
ValidatorSet *ValidatorSet `json:"validatorSet"` // Validator set at this moment
|
ValidatorSet *valset.ValidatorSet `json:"validatorSet"` // Validator set at this moment
|
||||||
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
||||||
}
|
}
|
||||||
|
|
||||||
// signersAscending implements the sort interface to allow sorting a list of addresses
|
|
||||||
type signersAscending []common.Address
|
|
||||||
|
|
||||||
func (s signersAscending) Len() int { return len(s) }
|
|
||||||
func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
|
|
||||||
func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
||||||
// method does not initialize the set of recent signers, so only ever use if for
|
// method does not initialize the set of recent signers, so only ever use if for
|
||||||
// the genesis block.
|
// the genesis block.
|
||||||
|
|
@ -40,37 +32,38 @@ func newSnapshot(
|
||||||
sigcache *lru.ARCCache,
|
sigcache *lru.ARCCache,
|
||||||
number uint64,
|
number uint64,
|
||||||
hash common.Hash,
|
hash common.Hash,
|
||||||
validators []*Validator,
|
validators []*valset.Validator,
|
||||||
ethAPI *ethapi.PublicBlockChainAPI,
|
|
||||||
) *Snapshot {
|
) *Snapshot {
|
||||||
snap := &Snapshot{
|
snap := &Snapshot{
|
||||||
config: config,
|
config: config,
|
||||||
ethAPI: ethAPI,
|
|
||||||
sigcache: sigcache,
|
sigcache: sigcache,
|
||||||
Number: number,
|
Number: number,
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
Recents: make(map[uint64]common.Address),
|
Recents: make(map[uint64]common.Address),
|
||||||
}
|
}
|
||||||
|
|
||||||
return snap
|
return snap
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadSnapshot loads an existing snapshot from the database.
|
// loadSnapshot loads an existing snapshot from the database.
|
||||||
func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash, ethAPI *ethapi.PublicBlockChainAPI) (*Snapshot, error) {
|
func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
|
||||||
blob, err := db.Get(append([]byte("bor-"), hash[:]...))
|
blob, err := db.Get(append([]byte("bor-"), hash[:]...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
snap := new(Snapshot)
|
snap := new(Snapshot)
|
||||||
|
|
||||||
if err := json.Unmarshal(blob, snap); err != nil {
|
if err := json.Unmarshal(blob, snap); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
snap.config = config
|
snap.config = config
|
||||||
snap.sigcache = sigcache
|
snap.sigcache = sigcache
|
||||||
snap.ethAPI = ethAPI
|
|
||||||
|
|
||||||
// update total voting power
|
// update total voting power
|
||||||
if err := snap.ValidatorSet.updateTotalVotingPower(); err != nil {
|
if err := snap.ValidatorSet.UpdateTotalVotingPower(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,6 +76,7 @@ func (s *Snapshot) store(db ethdb.Database) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Put(append([]byte("bor-"), s.Hash[:]...), blob)
|
return db.Put(append([]byte("bor-"), s.Hash[:]...), blob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +84,6 @@ func (s *Snapshot) store(db ethdb.Database) error {
|
||||||
func (s *Snapshot) copy() *Snapshot {
|
func (s *Snapshot) copy() *Snapshot {
|
||||||
cpy := &Snapshot{
|
cpy := &Snapshot{
|
||||||
config: s.config,
|
config: s.config,
|
||||||
ethAPI: s.ethAPI,
|
|
||||||
sigcache: s.sigcache,
|
sigcache: s.sigcache,
|
||||||
Number: s.Number,
|
Number: s.Number,
|
||||||
Hash: s.Hash,
|
Hash: s.Hash,
|
||||||
|
|
@ -115,6 +108,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
return nil, errOutOfRangeChain
|
return nil, errOutOfRangeChain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if headers[0].Number.Uint64() != s.Number+1 {
|
if headers[0].Number.Uint64() != s.Number+1 {
|
||||||
return nil, errOutOfRangeChain
|
return nil, errOutOfRangeChain
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +120,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
// Delete the oldest signer from the recent list to allow it signing again
|
// Delete the oldest signer from the recent list to allow it signing again
|
||||||
if number >= s.config.Sprint && number-s.config.Sprint >= 0 {
|
if number >= s.config.Sprint {
|
||||||
delete(snap.Recents, number-s.config.Sprint)
|
delete(snap.Recents, number-s.config.Sprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,15 +147,17 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
if err := validateHeaderExtraField(header.Extra); err != nil {
|
if err := validateHeaderExtraField(header.Extra); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
||||||
|
|
||||||
// get validators from headers and use that for new validator set
|
// get validators from headers and use that for new validator set
|
||||||
newVals, _ := ParseValidators(validatorBytes)
|
newVals, _ := valset.ParseValidators(validatorBytes)
|
||||||
v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
|
v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
|
||||||
v.IncrementProposerPriority(1)
|
v.IncrementProposerPriority(1)
|
||||||
snap.ValidatorSet = v
|
snap.ValidatorSet = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snap.Number += uint64(len(headers))
|
snap.Number += uint64(len(headers))
|
||||||
snap.Hash = headers[len(headers)-1].Hash()
|
snap.Hash = headers[len(headers)-1].Hash()
|
||||||
|
|
||||||
|
|
@ -173,10 +169,13 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error)
|
||||||
validators := s.ValidatorSet.Validators
|
validators := s.ValidatorSet.Validators
|
||||||
proposer := s.ValidatorSet.GetProposer().Address
|
proposer := s.ValidatorSet.GetProposer().Address
|
||||||
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
|
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
|
||||||
|
|
||||||
if proposerIndex == -1 {
|
if proposerIndex == -1 {
|
||||||
return -1, &UnauthorizedProposerError{s.Number, proposer.Bytes()}
|
return -1, &UnauthorizedProposerError{s.Number, proposer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
||||||
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
|
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
|
||||||
|
|
||||||
if signerIndex == -1 {
|
if signerIndex == -1 {
|
||||||
return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()}
|
return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
@ -187,6 +186,7 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error)
|
||||||
tempIndex = tempIndex + len(validators)
|
tempIndex = tempIndex + len(validators)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tempIndex - proposerIndex, nil
|
return tempIndex - proposerIndex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,13 +196,14 @@ func (s *Snapshot) signers() []common.Address {
|
||||||
for _, sig := range s.ValidatorSet.Validators {
|
for _, sig := range s.ValidatorSet.Validators {
|
||||||
sigs = append(sigs, sig.Address)
|
sigs = append(sigs, sig.Address)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sigs
|
return sigs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Difficulty returns the difficulty for a particular signer at the current snapshot number
|
// Difficulty returns the difficulty for a particular signer at the current snapshot number
|
||||||
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
|
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
|
||||||
// if signer is empty
|
// if signer is empty
|
||||||
if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 {
|
if signer == (common.Address{}) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"pgregory.net/rapid"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
unique "github.com/ethereum/go-ethereum/common/set"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -16,8 +19,10 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
validatorSet := NewValidatorSet(validators)
|
validatorSet := valset.NewValidatorSet(validators)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: validatorSet,
|
ValidatorSet: validatorSet,
|
||||||
}
|
}
|
||||||
|
|
@ -28,20 +33,24 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, 0, successionNumber)
|
assert.Equal(t, 0, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
|
|
||||||
// sort validators by address, which is what NewValidatorSet also does
|
// sort validators by address, which is what NewValidatorSet also does
|
||||||
sort.Sort(ValidatorsByAddress(validators))
|
sort.Sort(valset.ValidatorsByAddress(validators))
|
||||||
|
|
||||||
proposerIndex := 32
|
proposerIndex := 32
|
||||||
signerIndex := 56
|
signerIndex := 56
|
||||||
// give highest ProposerPriority to a particular val, so that they become the proposer
|
// give highest ProposerPriority to a particular val, so that they become the proposer
|
||||||
validators[proposerIndex].VotingPower = 200
|
validators[proposerIndex].VotingPower = 200
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
|
|
||||||
// choose a signer at an index greater than proposer index
|
// choose a signer at an index greater than proposer index
|
||||||
|
|
@ -50,17 +59,20 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, signerIndex-proposerIndex, successionNumber)
|
assert.Equal(t, signerIndex-proposerIndex, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
proposerIndex := 98
|
proposerIndex := 98
|
||||||
signerIndex := 11
|
signerIndex := 11
|
||||||
// give highest ProposerPriority to a particular val, so that they become the proposer
|
// give highest ProposerPriority to a particular val, so that they become the proposer
|
||||||
validators[proposerIndex].VotingPower = 200
|
validators[proposerIndex].VotingPower = 200
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
|
|
||||||
// choose a signer at an index greater than proposer index
|
// choose a signer at an index greater than proposer index
|
||||||
|
|
@ -69,29 +81,38 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
|
|
||||||
dummyProposerAddress := randomAddress()
|
dummyProposerAddress := randomAddress()
|
||||||
snap.ValidatorSet.Proposer = &Validator{Address: dummyProposerAddress}
|
snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress}
|
||||||
|
|
||||||
// choose any signer
|
// choose any signer
|
||||||
signer := snap.ValidatorSet.Validators[3].Address
|
signer := snap.ValidatorSet.Validators[3].Address
|
||||||
|
|
||||||
_, err := snap.GetSignerSuccessionNumber(signer)
|
_, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
e, ok := err.(*UnauthorizedProposerError)
|
e, ok := err.(*UnauthorizedProposerError)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
validators := buildRandomValidatorSet(numVals)
|
validators := buildRandomValidatorSet(numVals)
|
||||||
snap := Snapshot{
|
snap := Snapshot{
|
||||||
ValidatorSet: NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
dummySignerAddress := randomAddress()
|
dummySignerAddress := randomAddress()
|
||||||
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
||||||
|
|
@ -101,24 +122,78 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildRandomValidatorSet(numVals int) []*Validator {
|
// nolint: unparam
|
||||||
|
func buildRandomValidatorSet(numVals int) []*valset.Validator {
|
||||||
rand.Seed(time.Now().Unix())
|
rand.Seed(time.Now().Unix())
|
||||||
validators := make([]*Validator, numVals)
|
|
||||||
|
validators := make([]*valset.Validator, numVals)
|
||||||
|
valAddrs := randomAddresses(numVals)
|
||||||
|
|
||||||
for i := 0; i < numVals; i++ {
|
for i := 0; i < numVals; i++ {
|
||||||
validators[i] = &Validator{
|
validators[i] = &valset.Validator{
|
||||||
Address: randomAddress(),
|
Address: valAddrs[i],
|
||||||
// cannot process validators with voting power 0, hence +1
|
// cannot process validators with voting power 0, hence +1
|
||||||
VotingPower: int64(rand.Intn(99) + 1),
|
VotingPower: int64(rand.Intn(99) + 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort validators by address, which is what NewValidatorSet also does
|
// sort validators by address, which is what NewValidatorSet also does
|
||||||
sort.Sort(ValidatorsByAddress(validators))
|
sort.Sort(valset.ValidatorsByAddress(validators))
|
||||||
|
|
||||||
return validators
|
return validators
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomAddress() common.Address {
|
func randomAddress() common.Address {
|
||||||
bytes := make([]byte, 32)
|
bytes := make([]byte, 32)
|
||||||
rand.Read(bytes)
|
rand.Read(bytes)
|
||||||
|
|
||||||
return common.BytesToAddress(bytes)
|
return common.BytesToAddress(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func randomAddresses(n int) []common.Address {
|
||||||
|
if n <= 0 {
|
||||||
|
return []common.Address{}
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs := make([]common.Address, 0, n)
|
||||||
|
addrsSet := make(map[common.Address]struct{}, n)
|
||||||
|
|
||||||
|
var (
|
||||||
|
addr common.Address
|
||||||
|
exist bool
|
||||||
|
)
|
||||||
|
|
||||||
|
bytes := make([]byte, 32)
|
||||||
|
|
||||||
|
for {
|
||||||
|
rand.Read(bytes)
|
||||||
|
|
||||||
|
addr = common.BytesToAddress(bytes)
|
||||||
|
|
||||||
|
_, exist = addrsSet[addr]
|
||||||
|
if !exist {
|
||||||
|
addrs = append(addrs, addr)
|
||||||
|
|
||||||
|
addrsSet[addr] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) == n {
|
||||||
|
return addrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandomAddresses(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rapid.Check(t, func(t *rapid.T) {
|
||||||
|
length := rapid.IntMax(100).Draw(t, "length").(int)
|
||||||
|
|
||||||
|
addrs := randomAddresses(length)
|
||||||
|
addressSet := unique.New(addrs)
|
||||||
|
|
||||||
|
if len(addrs) != len(addressSet) {
|
||||||
|
t.Fatalf("length of unique addresses %d, expected %d", len(addressSet), len(addrs))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
package bor
|
package bor
|
||||||
|
|
||||||
// Span represents a current bor span
|
import (
|
||||||
type Span struct {
|
"github.com/ethereum/go-ethereum/common"
|
||||||
ID uint64 `json:"span_id" yaml:"span_id"`
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
StartBlock uint64 `json:"start_block" yaml:"start_block"`
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
EndBlock uint64 `json:"end_block" yaml:"end_block"`
|
"github.com/ethereum/go-ethereum/core"
|
||||||
}
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
// HeimdallSpan represents span from heimdall APIs
|
//go:generate mockgen -destination=./span_mock.go -package=bor . Spanner
|
||||||
type HeimdallSpan struct {
|
type Spanner interface {
|
||||||
Span
|
GetCurrentSpan(headerHash common.Hash) (*span.Span, error)
|
||||||
ValidatorSet ValidatorSet `json:"validator_set" yaml:"validator_set"`
|
GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error)
|
||||||
SelectedProducers []Validator `json:"selected_producers" yaml:"selected_producers"`
|
CommitSpan(heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error
|
||||||
ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"`
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
84
consensus/bor/span_mock.go
Normal file
84
consensus/bor/span_mock.go
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: Spanner)
|
||||||
|
|
||||||
|
// Package bor is a generated GoMock package.
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
common "github.com/ethereum/go-ethereum/common"
|
||||||
|
span "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
|
valset "github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
core "github.com/ethereum/go-ethereum/core"
|
||||||
|
state "github.com/ethereum/go-ethereum/core/state"
|
||||||
|
types "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockSpanner is a mock of Spanner interface.
|
||||||
|
type MockSpanner struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockSpannerMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockSpannerMockRecorder is the mock recorder for MockSpanner.
|
||||||
|
type MockSpannerMockRecorder struct {
|
||||||
|
mock *MockSpanner
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockSpanner creates a new mock instance.
|
||||||
|
func NewMockSpanner(ctrl *gomock.Controller) *MockSpanner {
|
||||||
|
mock := &MockSpanner{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockSpannerMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockSpanner) EXPECT() *MockSpannerMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitSpan mocks base method.
|
||||||
|
func (m *MockSpanner) CommitSpan(arg0 span.HeimdallSpan, arg1 *state.StateDB, arg2 *types.Header, arg3 core.ChainContext) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CommitSpan", arg0, arg1, arg2, arg3)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitSpan indicates an expected call of CommitSpan.
|
||||||
|
func (mr *MockSpannerMockRecorder) CommitSpan(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), arg0, arg1, arg2, arg3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentSpan mocks base method.
|
||||||
|
func (m *MockSpanner) GetCurrentSpan(arg0 common.Hash) (*span.Span, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetCurrentSpan", arg0)
|
||||||
|
ret0, _ := ret[0].(*span.Span)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentSpan indicates an expected call of GetCurrentSpan.
|
||||||
|
func (mr *MockSpannerMockRecorder) GetCurrentSpan(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentValidators mocks base method.
|
||||||
|
func (m *MockSpanner) GetCurrentValidators(arg0 common.Hash, arg1 uint64) ([]*valset.Validator, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].([]*valset.Validator)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentValidators indicates an expected call of GetCurrentValidators.
|
||||||
|
func (mr *MockSpannerMockRecorder) GetCurrentValidators(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidators), arg0, arg1)
|
||||||
|
}
|
||||||
93
consensus/bor/statefull/processor.go
Normal file
93
consensus/bor/statefull/processor.go
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
package statefull
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
var systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
|
||||||
|
|
||||||
|
type ChainContext struct {
|
||||||
|
Chain consensus.ChainHeaderReader
|
||||||
|
Bor consensus.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ChainContext) Engine() consensus.Engine {
|
||||||
|
return c.Bor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ChainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||||
|
return c.Chain.GetHeader(hash, number)
|
||||||
|
}
|
||||||
|
|
||||||
|
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
||||||
|
type callmsg struct {
|
||||||
|
ethereum.CallMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m callmsg) From() common.Address { return m.CallMsg.From }
|
||||||
|
func (m callmsg) Nonce() uint64 { return 0 }
|
||||||
|
func (m callmsg) CheckNonce() bool { return false }
|
||||||
|
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
||||||
|
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||||
|
func (m callmsg) Gas() uint64 { return m.CallMsg.Gas }
|
||||||
|
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
||||||
|
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
||||||
|
|
||||||
|
// get system message
|
||||||
|
func GetSystemMessage(toAddress common.Address, data []byte) callmsg {
|
||||||
|
return callmsg{
|
||||||
|
ethereum.CallMsg{
|
||||||
|
From: systemAddress,
|
||||||
|
Gas: math.MaxUint64 / 2,
|
||||||
|
GasPrice: big.NewInt(0),
|
||||||
|
Value: big.NewInt(0),
|
||||||
|
To: &toAddress,
|
||||||
|
Data: data,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply message
|
||||||
|
func ApplyMessage(
|
||||||
|
msg callmsg,
|
||||||
|
state *state.StateDB,
|
||||||
|
header *types.Header,
|
||||||
|
chainConfig *params.ChainConfig,
|
||||||
|
chainContext core.ChainContext,
|
||||||
|
) (uint64, error) {
|
||||||
|
initialGas := msg.Gas()
|
||||||
|
|
||||||
|
// Create a new context to be used in the EVM environment
|
||||||
|
blockContext := core.NewEVMBlockContext(header, chainContext, &header.Coinbase)
|
||||||
|
|
||||||
|
// Create a new environment which holds all relevant information
|
||||||
|
// about the transaction and calling mechanisms.
|
||||||
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, state, chainConfig, vm.Config{})
|
||||||
|
|
||||||
|
// Apply the transaction to the current state (included in the env)
|
||||||
|
_, gasLeft, err := vmenv.Call(
|
||||||
|
vm.AccountRef(msg.From()),
|
||||||
|
*msg.To(),
|
||||||
|
msg.Data(),
|
||||||
|
msg.Gas(),
|
||||||
|
msg.Value(),
|
||||||
|
)
|
||||||
|
// Update the state with pending changes
|
||||||
|
if err != nil {
|
||||||
|
state.Finalise(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasUsed := initialGas - gasLeft
|
||||||
|
|
||||||
|
return gasUsed, nil
|
||||||
|
}
|
||||||
11
consensus/bor/validators_getter.go
Normal file
11
consensus/bor/validators_getter.go
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate mockgen -destination=./validators_getter_mock.go -package=bor . ValidatorsGetter
|
||||||
|
type ValidatorsGetter interface {
|
||||||
|
GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error)
|
||||||
|
}
|
||||||
51
consensus/bor/validators_getter_mock.go
Normal file
51
consensus/bor/validators_getter_mock.go
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: ValidatorsGetter)
|
||||||
|
|
||||||
|
// Package bor is a generated GoMock package.
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
common "github.com/ethereum/go-ethereum/common"
|
||||||
|
valset "github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockValidatorsGetter is a mock of ValidatorsGetter interface.
|
||||||
|
type MockValidatorsGetter struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockValidatorsGetterMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockValidatorsGetterMockRecorder is the mock recorder for MockValidatorsGetter.
|
||||||
|
type MockValidatorsGetterMockRecorder struct {
|
||||||
|
mock *MockValidatorsGetter
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockValidatorsGetter creates a new mock instance.
|
||||||
|
func NewMockValidatorsGetter(ctrl *gomock.Controller) *MockValidatorsGetter {
|
||||||
|
mock := &MockValidatorsGetter{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockValidatorsGetterMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockValidatorsGetter) EXPECT() *MockValidatorsGetterMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentValidators mocks base method.
|
||||||
|
func (m *MockValidatorsGetter) GetCurrentValidators(arg0 common.Hash, arg1 uint64) ([]*valset.Validator, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].([]*valset.Validator)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentValidators indicates an expected call of GetCurrentValidators.
|
||||||
|
func (mr *MockValidatorsGetterMockRecorder) GetCurrentValidators(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockValidatorsGetter)(nil).GetCurrentValidators), arg0, arg1)
|
||||||
|
}
|
||||||
32
consensus/bor/valset/error.go
Normal file
32
consensus/bor/valset/error.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package valset
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// TotalVotingPowerExceededError is returned when the maximum allowed total voting power is exceeded
|
||||||
|
type TotalVotingPowerExceededError struct {
|
||||||
|
Sum int64
|
||||||
|
Validators []*Validator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *TotalVotingPowerExceededError) Error() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Total voting power should be guarded to not exceed %v; got: %v; for validator set: %v",
|
||||||
|
MaxTotalVotingPower,
|
||||||
|
e.Sum,
|
||||||
|
e.Validators,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type InvalidStartEndBlockError struct {
|
||||||
|
Start uint64
|
||||||
|
End uint64
|
||||||
|
CurrentHeader uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidStartEndBlockError) Error() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Invalid parameters start: %d and end block: %d params",
|
||||||
|
e.Start,
|
||||||
|
e.End,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
package bor
|
package valset
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
// "encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -43,9 +42,12 @@ func (v *Validator) Cmp(other *Validator) *Validator {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return other
|
return other
|
||||||
}
|
}
|
||||||
|
|
||||||
if other == nil {
|
if other == nil {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint:nestif
|
||||||
if v.ProposerPriority > other.ProposerPriority {
|
if v.ProposerPriority > other.ProposerPriority {
|
||||||
return v
|
return v
|
||||||
} else if v.ProposerPriority < other.ProposerPriority {
|
} else if v.ProposerPriority < other.ProposerPriority {
|
||||||
|
|
@ -66,6 +68,7 @@ func (v *Validator) String() string {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return "nil-Validator"
|
return "nil-Validator"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("Validator{%v Power:%v Priority:%v}",
|
return fmt.Sprintf("Validator{%v Power:%v Priority:%v}",
|
||||||
v.Address.Hex(),
|
v.Address.Hex(),
|
||||||
v.VotingPower,
|
v.VotingPower,
|
||||||
|
|
@ -87,6 +90,7 @@ func (v *Validator) HeaderBytes() []byte {
|
||||||
result := make([]byte, 40)
|
result := make([]byte, 40)
|
||||||
copy(result[:20], v.Address.Bytes())
|
copy(result[:20], v.Address.Bytes())
|
||||||
copy(result[20:], v.PowerBytes())
|
copy(result[20:], v.PowerBytes())
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +99,7 @@ func (v *Validator) PowerBytes() []byte {
|
||||||
powerBytes := big.NewInt(0).SetInt64(v.VotingPower).Bytes()
|
powerBytes := big.NewInt(0).SetInt64(v.VotingPower).Bytes()
|
||||||
result := make([]byte, 20)
|
result := make([]byte, 20)
|
||||||
copy(result[20-len(powerBytes):], powerBytes)
|
copy(result[20-len(powerBytes):], powerBytes)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,6 +119,7 @@ func ParseValidators(validatorsBytes []byte) ([]*Validator, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*Validator, len(validatorsBytes)/40)
|
result := make([]*Validator, len(validatorsBytes)/40)
|
||||||
|
|
||||||
for i := 0; i < len(validatorsBytes); i += 40 {
|
for i := 0; i < len(validatorsBytes); i += 40 {
|
||||||
address := make([]byte, 20)
|
address := make([]byte, 20)
|
||||||
power := make([]byte, 20)
|
power := make([]byte, 20)
|
||||||
|
|
@ -142,6 +148,7 @@ func SortMinimalValByAddress(a []MinimalVal) []MinimalVal {
|
||||||
sort.Slice(a, func(i, j int) bool {
|
sort.Slice(a, func(i, j int) bool {
|
||||||
return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0
|
return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0
|
||||||
})
|
})
|
||||||
|
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,5 +157,6 @@ func ValidatorsToMinimalValidators(vals []Validator) (minVals []MinimalVal) {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
minVals = append(minVals, val.MinimalVal())
|
minVals = append(minVals, val.MinimalVal())
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package bor
|
package valset
|
||||||
|
|
||||||
// Tendermint leader selection algorithm
|
// Tendermint leader selection algorithm
|
||||||
|
|
||||||
|
|
@ -55,13 +55,16 @@ type ValidatorSet struct {
|
||||||
// function panics.
|
// function panics.
|
||||||
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
||||||
vals := &ValidatorSet{}
|
vals := &ValidatorSet{}
|
||||||
|
|
||||||
err := vals.updateWithChangeSet(valz, false)
|
err := vals.updateWithChangeSet(valz, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("cannot create validator set: %s", err))
|
panic(fmt.Sprintf("cannot create validator set: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(valz) > 0 {
|
if len(valz) > 0 {
|
||||||
vals.IncrementProposerPriority(1)
|
vals.IncrementProposerPriority(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return vals
|
return vals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,9 +75,10 @@ func (vals *ValidatorSet) IsNilOrEmpty() bool {
|
||||||
|
|
||||||
// Increment ProposerPriority and update the proposer on a copy, and return it.
|
// Increment ProposerPriority and update the proposer on a copy, and return it.
|
||||||
func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet {
|
func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet {
|
||||||
copy := vals.Copy()
|
validatorCopy := vals.Copy()
|
||||||
copy.IncrementProposerPriority(times)
|
validatorCopy.IncrementProposerPriority(times)
|
||||||
return copy
|
|
||||||
|
return validatorCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
// IncrementProposerPriority increments ProposerPriority of each validator and updates the
|
// IncrementProposerPriority increments ProposerPriority of each validator and updates the
|
||||||
|
|
@ -84,6 +88,7 @@ func (vals *ValidatorSet) IncrementProposerPriority(times int) {
|
||||||
if vals.IsNilOrEmpty() {
|
if vals.IsNilOrEmpty() {
|
||||||
panic("empty validator set")
|
panic("empty validator set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if times <= 0 {
|
if times <= 0 {
|
||||||
panic("Cannot call IncrementProposerPriority with non-positive times")
|
panic("Cannot call IncrementProposerPriority with non-positive times")
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +125,7 @@ func (vals *ValidatorSet) RescalePriorities(diffMax int64) {
|
||||||
// NOTE: This may make debugging priority issues easier as well.
|
// NOTE: This may make debugging priority issues easier as well.
|
||||||
diff := computeMaxMinPriorityDiff(vals)
|
diff := computeMaxMinPriorityDiff(vals)
|
||||||
ratio := (diff + diffMax - 1) / diffMax
|
ratio := (diff + diffMax - 1) / diffMax
|
||||||
|
|
||||||
if diff > diffMax {
|
if diff > diffMax {
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
val.ProposerPriority = val.ProposerPriority / ratio
|
val.ProposerPriority = val.ProposerPriority / ratio
|
||||||
|
|
@ -145,10 +151,13 @@ func (vals *ValidatorSet) incrementProposerPriority() *Validator {
|
||||||
func (vals *ValidatorSet) computeAvgProposerPriority() int64 {
|
func (vals *ValidatorSet) computeAvgProposerPriority() int64 {
|
||||||
n := int64(len(vals.Validators))
|
n := int64(len(vals.Validators))
|
||||||
sum := big.NewInt(0)
|
sum := big.NewInt(0)
|
||||||
|
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
sum.Add(sum, big.NewInt(val.ProposerPriority))
|
sum.Add(sum, big.NewInt(val.ProposerPriority))
|
||||||
}
|
}
|
||||||
|
|
||||||
avg := sum.Div(sum, big.NewInt(n))
|
avg := sum.Div(sum, big.NewInt(n))
|
||||||
|
|
||||||
if avg.IsInt64() {
|
if avg.IsInt64() {
|
||||||
return avg.Int64()
|
return avg.Int64()
|
||||||
}
|
}
|
||||||
|
|
@ -162,17 +171,22 @@ func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 {
|
||||||
if vals.IsNilOrEmpty() {
|
if vals.IsNilOrEmpty() {
|
||||||
panic("empty validator set")
|
panic("empty validator set")
|
||||||
}
|
}
|
||||||
|
|
||||||
max := int64(math.MinInt64)
|
max := int64(math.MinInt64)
|
||||||
min := int64(math.MaxInt64)
|
min := int64(math.MaxInt64)
|
||||||
|
|
||||||
for _, v := range vals.Validators {
|
for _, v := range vals.Validators {
|
||||||
if v.ProposerPriority < min {
|
if v.ProposerPriority < min {
|
||||||
min = v.ProposerPriority
|
min = v.ProposerPriority
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.ProposerPriority > max {
|
if v.ProposerPriority > max {
|
||||||
max = v.ProposerPriority
|
max = v.ProposerPriority
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diff := max - min
|
diff := max - min
|
||||||
|
|
||||||
if diff < 0 {
|
if diff < 0 {
|
||||||
return -1 * diff
|
return -1 * diff
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -185,6 +199,7 @@ func (vals *ValidatorSet) getValWithMostPriority() *Validator {
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
res = res.Cmp(val)
|
res = res.Cmp(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +207,9 @@ func (vals *ValidatorSet) shiftByAvgProposerPriority() {
|
||||||
if vals.IsNilOrEmpty() {
|
if vals.IsNilOrEmpty() {
|
||||||
panic("empty validator set")
|
panic("empty validator set")
|
||||||
}
|
}
|
||||||
|
|
||||||
avgProposerPriority := vals.computeAvgProposerPriority()
|
avgProposerPriority := vals.computeAvgProposerPriority()
|
||||||
|
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority)
|
val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority)
|
||||||
}
|
}
|
||||||
|
|
@ -203,10 +220,13 @@ func validatorListCopy(valsList []*Validator) []*Validator {
|
||||||
if valsList == nil {
|
if valsList == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
valsCopy := make([]*Validator, len(valsList))
|
valsCopy := make([]*Validator, len(valsList))
|
||||||
|
|
||||||
for i, val := range valsList {
|
for i, val := range valsList {
|
||||||
valsCopy[i] = val.Copy()
|
valsCopy[i] = val.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
return valsCopy
|
return valsCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,6 +245,7 @@ func (vals *ValidatorSet) HasAddress(address []byte) bool {
|
||||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
||||||
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
|
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
|
||||||
})
|
})
|
||||||
|
|
||||||
return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address)
|
return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,9 +255,10 @@ func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *
|
||||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
||||||
return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0
|
return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0
|
||||||
})
|
})
|
||||||
if idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address.Bytes()) {
|
if idx < len(vals.Validators) && vals.Validators[idx].Address == address {
|
||||||
return idx, vals.Validators[idx].Copy()
|
return idx, vals.Validators[idx].Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, nil
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,7 +269,9 @@ func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator)
|
||||||
if index < 0 || index >= len(vals.Validators) {
|
if index < 0 || index >= len(vals.Validators) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
val = vals.Validators[index]
|
val = vals.Validators[index]
|
||||||
|
|
||||||
return val.Address.Bytes(), val.Copy()
|
return val.Address.Bytes(), val.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,8 +281,7 @@ func (vals *ValidatorSet) Size() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force recalculation of the set's total voting power.
|
// Force recalculation of the set's total voting power.
|
||||||
func (vals *ValidatorSet) updateTotalVotingPower() error {
|
func (vals *ValidatorSet) UpdateTotalVotingPower() error {
|
||||||
|
|
||||||
sum := int64(0)
|
sum := int64(0)
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
// mind overflow
|
// mind overflow
|
||||||
|
|
@ -267,7 +290,9 @@ func (vals *ValidatorSet) updateTotalVotingPower() error {
|
||||||
return &TotalVotingPowerExceededError{sum, vals.Validators}
|
return &TotalVotingPowerExceededError{sum, vals.Validators}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vals.totalVotingPower = sum
|
vals.totalVotingPower = sum
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,11 +301,13 @@ func (vals *ValidatorSet) updateTotalVotingPower() error {
|
||||||
func (vals *ValidatorSet) TotalVotingPower() int64 {
|
func (vals *ValidatorSet) TotalVotingPower() int64 {
|
||||||
if vals.totalVotingPower == 0 {
|
if vals.totalVotingPower == 0 {
|
||||||
log.Info("invoking updateTotalVotingPower before returning it")
|
log.Info("invoking updateTotalVotingPower before returning it")
|
||||||
if err := vals.updateTotalVotingPower(); err != nil {
|
|
||||||
|
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||||
// Can/should we do better?
|
// Can/should we do better?
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vals.totalVotingPower
|
return vals.totalVotingPower
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,9 +317,11 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
|
||||||
if len(vals.Validators) == 0 {
|
if len(vals.Validators) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if vals.Proposer == nil {
|
if vals.Proposer == nil {
|
||||||
vals.Proposer = vals.findProposer()
|
vals.Proposer = vals.findProposer()
|
||||||
}
|
}
|
||||||
|
|
||||||
return vals.Proposer.Copy()
|
return vals.Proposer.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,6 +332,7 @@ func (vals *ValidatorSet) findProposer() *Validator {
|
||||||
proposer = proposer.Cmp(val)
|
proposer = proposer.Cmp(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return proposer
|
return proposer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,6 +373,7 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
||||||
|
|
||||||
removals = make([]*Validator, 0, len(changes))
|
removals = make([]*Validator, 0, len(changes))
|
||||||
updates = make([]*Validator, 0, len(changes))
|
updates = make([]*Validator, 0, len(changes))
|
||||||
|
|
||||||
var prevAddr common.Address
|
var prevAddr common.Address
|
||||||
|
|
||||||
// Scan changes by address and append valid validators to updates or removals lists.
|
// Scan changes by address and append valid validators to updates or removals lists.
|
||||||
|
|
@ -351,22 +382,27 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
||||||
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
|
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if valUpdate.VotingPower < 0 {
|
if valUpdate.VotingPower < 0 {
|
||||||
err = fmt.Errorf("voting power can't be negative: %v", valUpdate)
|
err = fmt.Errorf("voting power can't be negative: %v", valUpdate)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if valUpdate.VotingPower > MaxTotalVotingPower {
|
if valUpdate.VotingPower > MaxTotalVotingPower {
|
||||||
err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ",
|
err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ",
|
||||||
MaxTotalVotingPower, valUpdate)
|
MaxTotalVotingPower, valUpdate)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if valUpdate.VotingPower == 0 {
|
if valUpdate.VotingPower == 0 {
|
||||||
removals = append(removals, valUpdate)
|
removals = append(removals, valUpdate)
|
||||||
} else {
|
} else {
|
||||||
updates = append(updates, valUpdate)
|
updates = append(updates, valUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
prevAddr = valUpdate.Address
|
prevAddr = valUpdate.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
return updates, removals, err
|
return updates, removals, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,12 +418,12 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
||||||
// by processChanges for duplicates and invalid values.
|
// by processChanges for duplicates and invalid values.
|
||||||
// No changes are made to the validator set 'vals'.
|
// No changes are made to the validator set 'vals'.
|
||||||
func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) {
|
func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) {
|
||||||
|
|
||||||
updatedTotalVotingPower = vals.TotalVotingPower()
|
updatedTotalVotingPower = vals.TotalVotingPower()
|
||||||
|
|
||||||
for _, valUpdate := range updates {
|
for _, valUpdate := range updates {
|
||||||
address := valUpdate.Address
|
address := valUpdate.Address
|
||||||
_, val := vals.GetByAddress(address)
|
_, val := vals.GetByAddress(address)
|
||||||
|
|
||||||
if val == nil {
|
if val == nil {
|
||||||
// New validator, add its voting power the the total.
|
// New validator, add its voting power the the total.
|
||||||
updatedTotalVotingPower += valUpdate.VotingPower
|
updatedTotalVotingPower += valUpdate.VotingPower
|
||||||
|
|
@ -396,11 +432,14 @@ func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVoting
|
||||||
// Updated validator, add the difference in power to the total.
|
// Updated validator, add the difference in power to the total.
|
||||||
updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower
|
updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower
|
||||||
}
|
}
|
||||||
|
|
||||||
overflow := updatedTotalVotingPower > MaxTotalVotingPower
|
overflow := updatedTotalVotingPower > MaxTotalVotingPower
|
||||||
|
|
||||||
if overflow {
|
if overflow {
|
||||||
err = fmt.Errorf(
|
err = fmt.Errorf(
|
||||||
"failed to add/update validator %v, total voting power would exceed the max allowed %v",
|
"failed to add/update validator %v, total voting power would exceed the max allowed %v",
|
||||||
valUpdate, MaxTotalVotingPower)
|
valUpdate, MaxTotalVotingPower)
|
||||||
|
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -414,10 +453,10 @@ func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVoting
|
||||||
// 'updates' parameter must be a list of unique validators to be added or updated.
|
// 'updates' parameter must be a list of unique validators to be added or updated.
|
||||||
// No changes are made to the validator set 'vals'.
|
// No changes are made to the validator set 'vals'.
|
||||||
func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotalVotingPower int64) {
|
func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotalVotingPower int64) {
|
||||||
|
|
||||||
for _, valUpdate := range updates {
|
for _, valUpdate := range updates {
|
||||||
address := valUpdate.Address
|
address := valUpdate.Address
|
||||||
_, val := vals.GetByAddress(address)
|
_, val := vals.GetByAddress(address)
|
||||||
|
|
||||||
if val == nil {
|
if val == nil {
|
||||||
// add val
|
// add val
|
||||||
// Set ProposerPriority to -C*totalVotingPower (with C ~= 1.125) to make sure validators can't
|
// Set ProposerPriority to -C*totalVotingPower (with C ~= 1.125) to make sure validators can't
|
||||||
|
|
@ -432,7 +471,6 @@ func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotal
|
||||||
valUpdate.ProposerPriority = val.ProposerPriority
|
valUpdate.ProposerPriority = val.ProposerPriority
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merges the vals' validator list with the updates list.
|
// Merges the vals' validator list with the updates list.
|
||||||
|
|
@ -440,7 +478,6 @@ func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotal
|
||||||
// Expects updates to be a list of updates sorted by address with no duplicates or errors,
|
// Expects updates to be a list of updates sorted by address with no duplicates or errors,
|
||||||
// must have been validated with verifyUpdates() and priorities computed with computeNewPriorities().
|
// must have been validated with verifyUpdates() and priorities computed with computeNewPriorities().
|
||||||
func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
||||||
|
|
||||||
existing := vals.Validators
|
existing := vals.Validators
|
||||||
merged := make([]*Validator, len(existing)+len(updates))
|
merged := make([]*Validator, len(existing)+len(updates))
|
||||||
i := 0
|
i := 0
|
||||||
|
|
@ -478,24 +515,25 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
||||||
// Checks that the validators to be removed are part of the validator set.
|
// Checks that the validators to be removed are part of the validator set.
|
||||||
// No changes are made to the validator set 'vals'.
|
// No changes are made to the validator set 'vals'.
|
||||||
func verifyRemovals(deletes []*Validator, vals *ValidatorSet) error {
|
func verifyRemovals(deletes []*Validator, vals *ValidatorSet) error {
|
||||||
|
|
||||||
for _, valUpdate := range deletes {
|
for _, valUpdate := range deletes {
|
||||||
address := valUpdate.Address
|
address := valUpdate.Address
|
||||||
_, val := vals.GetByAddress(address)
|
_, val := vals.GetByAddress(address)
|
||||||
|
|
||||||
if val == nil {
|
if val == nil {
|
||||||
return fmt.Errorf("failed to find validator %X to remove", address)
|
return fmt.Errorf("failed to find validator %X to remove", address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(deletes) > len(vals.Validators) {
|
if len(deletes) > len(vals.Validators) {
|
||||||
panic("more deletes than validators")
|
panic("more deletes than validators")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the validators specified in 'deletes' from validator set 'vals'.
|
// Removes the validators specified in 'deletes' from validator set 'vals'.
|
||||||
// Should not fail as verification has been done before.
|
// Should not fail as verification has been done before.
|
||||||
func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
||||||
|
|
||||||
existing := vals.Validators
|
existing := vals.Validators
|
||||||
|
|
||||||
merged := make([]*Validator, len(existing)-len(deletes))
|
merged := make([]*Validator, len(existing)-len(deletes))
|
||||||
|
|
@ -509,6 +547,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
||||||
merged[i] = existing[0]
|
merged[i] = existing[0]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
existing = existing[1:]
|
existing = existing[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,7 +565,6 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
||||||
// are not allowed and will trigger an error if present in 'changes'.
|
// are not allowed and will trigger an error if present in 'changes'.
|
||||||
// The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet().
|
// The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet().
|
||||||
func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error {
|
func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error {
|
||||||
|
|
||||||
if len(changes) <= 0 {
|
if len(changes) <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -564,7 +602,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
|
||||||
vals.applyUpdates(updates)
|
vals.applyUpdates(updates)
|
||||||
vals.applyRemovals(deletes)
|
vals.applyRemovals(deletes)
|
||||||
|
|
||||||
if err := vals.updateTotalVotingPower(); err != nil {
|
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -596,19 +634,19 @@ func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator) error {
|
||||||
|
|
||||||
func IsErrTooMuchChange(err error) bool {
|
func IsErrTooMuchChange(err error) bool {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case errTooMuchChange:
|
case tooMuchChangeError:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type errTooMuchChange struct {
|
type tooMuchChangeError struct {
|
||||||
got int64
|
got int64
|
||||||
needed int64
|
needed int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e errTooMuchChange) Error() string {
|
func (e tooMuchChangeError) Error() string {
|
||||||
return fmt.Sprintf("Invalid commit -- insufficient old voting power: got %v, needed %v", e.got, e.needed)
|
return fmt.Sprintf("Invalid commit -- insufficient old voting power: got %v, needed %v", e.got, e.needed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -622,11 +660,14 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
|
||||||
if vals == nil {
|
if vals == nil {
|
||||||
return "nil-ValidatorSet"
|
return "nil-ValidatorSet"
|
||||||
}
|
}
|
||||||
|
|
||||||
var valStrings []string
|
var valStrings []string
|
||||||
|
|
||||||
vals.Iterate(func(index int, val *Validator) bool {
|
vals.Iterate(func(index int, val *Validator) bool {
|
||||||
valStrings = append(valStrings, val.String())
|
valStrings = append(valStrings, val.String())
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
return fmt.Sprintf(`ValidatorSet{
|
return fmt.Sprintf(`ValidatorSet{
|
||||||
%s Proposer: %v
|
%s Proposer: %v
|
||||||
%s Validators:
|
%s Validators:
|
||||||
|
|
@ -636,7 +677,6 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
|
||||||
indent,
|
indent,
|
||||||
indent, strings.Join(valStrings, "\n"+indent+" "),
|
indent, strings.Join(valStrings, "\n"+indent+" "),
|
||||||
indent)
|
indent)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
@ -668,6 +708,7 @@ func safeAdd(a, b int64) (int64, bool) {
|
||||||
} else if b < 0 && a < math.MinInt64-b {
|
} else if b < 0 && a < math.MinInt64-b {
|
||||||
return -1, true
|
return -1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return a + b, false
|
return a + b, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,6 +718,7 @@ func safeSub(a, b int64) (int64, bool) {
|
||||||
} else if b < 0 && a > math.MaxInt64+b {
|
} else if b < 0 && a > math.MaxInt64+b {
|
||||||
return -1, true
|
return -1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return a - b, false
|
return a - b, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -686,8 +728,10 @@ func safeAddClip(a, b int64) int64 {
|
||||||
if b < 0 {
|
if b < 0 {
|
||||||
return math.MinInt64
|
return math.MinInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return math.MaxInt64
|
return math.MaxInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -697,7 +741,9 @@ func safeSubClip(a, b int64) int64 {
|
||||||
if b > 0 {
|
if b > 0 {
|
||||||
return math.MinInt64
|
return math.MinInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return math.MaxInt64
|
return math.MaxInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
@ -70,7 +70,7 @@ func TestRemoteNotify(t *testing.T) {
|
||||||
if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want {
|
if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want {
|
||||||
t.Errorf("work packet target mismatch: have %s, want %s", work[2], want)
|
t.Errorf("work packet target mismatch: have %s, want %s", work[2], want)
|
||||||
}
|
}
|
||||||
case <-time.After(3 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
t.Fatalf("notification timed out")
|
t.Fatalf("notification timed out")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,14 @@ type Merger struct {
|
||||||
// NewMerger creates a new Merger which stores its transition status in the provided db.
|
// NewMerger creates a new Merger which stores its transition status in the provided db.
|
||||||
func NewMerger(db ethdb.KeyValueStore) *Merger {
|
func NewMerger(db ethdb.KeyValueStore) *Merger {
|
||||||
var status transitionStatus
|
var status transitionStatus
|
||||||
|
|
||||||
blob := rawdb.ReadTransitionStatus(db)
|
blob := rawdb.ReadTransitionStatus(db)
|
||||||
if len(blob) != 0 {
|
if len(blob) != 0 {
|
||||||
if err := rlp.DecodeBytes(blob, &status); err != nil {
|
if err := rlp.DecodeBytes(blob, &status); err != nil {
|
||||||
log.Crit("Failed to decode the transition status", "err", err)
|
log.Crit("Failed to decode the transition status", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Merger{
|
return &Merger{
|
||||||
db: db,
|
db: db,
|
||||||
status: status,
|
status: status,
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
}
|
}
|
||||||
makeChainForBench(db, full, count)
|
makeChainForBench(db, full, count)
|
||||||
db.Close()
|
db.Close()
|
||||||
cacheConfig := *defaultCacheConfig
|
|
||||||
|
cacheConfig := *DefaultCacheConfig
|
||||||
cacheConfig.TrieDirtyDisabled = true
|
cacheConfig.TrieDirtyDisabled = true
|
||||||
|
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
|
|
@ -43,7 +45,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -133,9 +134,9 @@ type CacheConfig struct {
|
||||||
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
|
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultCacheConfig are the default caching values if none are specified by the
|
// DefaultCacheConfig are the default caching values if none are specified by the
|
||||||
// user (also used during testing).
|
// user (also used during testing).
|
||||||
var defaultCacheConfig = &CacheConfig{
|
var DefaultCacheConfig = &CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
|
|
@ -222,7 +223,7 @@ type BlockChain struct {
|
||||||
// and Processor.
|
// and Processor.
|
||||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) {
|
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) {
|
||||||
if cacheConfig == nil {
|
if cacheConfig == nil {
|
||||||
cacheConfig = defaultCacheConfig
|
cacheConfig = DefaultCacheConfig
|
||||||
}
|
}
|
||||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
@ -397,10 +398,25 @@ func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscr
|
||||||
return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
|
return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snaps retrieves the snapshot tree.
|
||||||
|
func (bc *BlockChain) Snaps() *snapshot.Tree {
|
||||||
|
return bc.snaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB retrieves the blockchain database.
|
||||||
|
func (bc *BlockChain) DB() ethdb.Database {
|
||||||
|
return bc.db
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Bor related changes
|
// Bor related changes
|
||||||
//
|
//
|
||||||
|
|
||||||
|
type BorStateSyncer interface {
|
||||||
|
SetStateSync(stateData []*types.StateSyncData)
|
||||||
|
SubscribeStateSyncEvent(ch chan<- StateSyncEvent) event.Subscription
|
||||||
|
}
|
||||||
|
|
||||||
// SetStateSync set sync data in state_data
|
// SetStateSync set sync data in state_data
|
||||||
func (bc *BlockChain) SetStateSync(stateData []*types.StateSyncData) {
|
func (bc *BlockChain) SetStateSync(stateData []*types.StateSyncData) {
|
||||||
bc.stateSyncData = stateData
|
bc.stateSyncData = stateData
|
||||||
|
|
|
||||||
|
|
@ -920,7 +920,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
archiveDb, delfn := makeDb()
|
archiveDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
|
|
||||||
archiveCaching := *defaultCacheConfig
|
archiveCaching := *DefaultCacheConfig
|
||||||
archiveCaching.TrieDirtyDisabled = true
|
archiveCaching.TrieDirtyDisabled = true
|
||||||
|
|
||||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -335,6 +336,9 @@ func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethd
|
||||||
|
|
||||||
type fakeChainReader struct {
|
type fakeChainReader struct {
|
||||||
config *params.ChainConfig
|
config *params.ChainConfig
|
||||||
|
stateSyncData []*types.StateSyncData
|
||||||
|
stateSyncFeed event.Feed
|
||||||
|
scope event.SubscriptionScope
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config returns the chain configuration.
|
// Config returns the chain configuration.
|
||||||
|
|
@ -348,3 +352,13 @@ func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header
|
||||||
func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil }
|
func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil }
|
||||||
func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil }
|
func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil }
|
||||||
func (cr *fakeChainReader) GetTd(hash common.Hash, number uint64) *big.Int { return nil }
|
func (cr *fakeChainReader) GetTd(hash common.Hash, number uint64) *big.Int { return nil }
|
||||||
|
|
||||||
|
// SetStateSync set sync data in state_data
|
||||||
|
func (cr *fakeChainReader) SetStateSync(stateData []*types.StateSyncData) {
|
||||||
|
cr.stateSyncData = stateData
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeStateSyncEvent registers a subscription of StateSyncEvent.
|
||||||
|
func (cr *fakeChainReader) SubscribeStateSyncEvent(ch chan<- StateSyncEvent) event.Subscription {
|
||||||
|
return cr.scope.Track(cr.stateSyncFeed.Subscribe(ch))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
|
@ -32,7 +34,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestStateProcessorErrors tests the output from the 'core' errors
|
// TestStateProcessorErrors tests the output from the 'core' errors
|
||||||
|
|
@ -308,7 +309,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
Coinbase: parent.Coinbase(),
|
||||||
Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{
|
Difficulty: engine.CalcDifficulty(&fakeChainReader{config: config}, parent.Time()+10, &types.Header{
|
||||||
Number: parent.Number(),
|
Number: parent.Number(),
|
||||||
Time: parent.Time(),
|
Time: parent.Time(),
|
||||||
Difficulty: parent.Difficulty(),
|
Difficulty: parent.Difficulty(),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
// the database in some strange state with gaps in the chain, nor with block data
|
// the database in some strange state with gaps in the chain, nor with block data
|
||||||
// dangling in the future.
|
// dangling in the future.
|
||||||
|
|
||||||
package core
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
@ -27,12 +27,22 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests a recovery for a short canonical chain where a recent block was already
|
// Tests a recovery for a short canonical chain where a recent block was already
|
||||||
|
|
@ -1750,7 +1760,17 @@ func testLongReorgedSnapSyncingDeepRepair(t *testing.T, snapshots bool) {
|
||||||
}, snapshots)
|
}, snapshots)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testKey1, _ = crypto.GenerateKey()
|
||||||
|
testAddress1 = crypto.PubkeyToAddress(testKey1.PublicKey)
|
||||||
|
|
||||||
|
testKey2, _ = crypto.GenerateKey()
|
||||||
|
testAddress2 = crypto.PubkeyToAddress(testKey2.PublicKey) //nolint:unused,varcheck
|
||||||
|
)
|
||||||
|
|
||||||
func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
|
t.Skip("need to add a proper signer for Bor consensus")
|
||||||
|
|
||||||
// It's hard to follow the test case, visualize the input
|
// It's hard to follow the test case, visualize the input
|
||||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
// fmt.Println(tt.dump(true))
|
// fmt.Println(tt.dump(true))
|
||||||
|
|
@ -1768,47 +1788,104 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
}
|
}
|
||||||
defer db.Close() // Might double close, should be fine
|
defer db.Close() // Might double close, should be fine
|
||||||
|
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
|
ethAPIMock := api.NewMockCaller(ctrl)
|
||||||
|
ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||||
|
|
||||||
|
spanner := bor.NewMockSpanner(ctrl)
|
||||||
|
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||||
|
{
|
||||||
|
ID: 0,
|
||||||
|
Address: common.Address{0x1},
|
||||||
|
VotingPower: 100,
|
||||||
|
ProposerPriority: 0,
|
||||||
|
},
|
||||||
|
}, nil).AnyTimes()
|
||||||
|
|
||||||
|
heimdallClientMock := mocks.NewMockIHeimdallClient(ctrl)
|
||||||
|
heimdallClientMock.EXPECT().Close().Times(1)
|
||||||
|
|
||||||
|
contractMock := bor.NewMockGenesisContract(ctrl)
|
||||||
|
|
||||||
// Initialize a fresh chain
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
gspec = &core.Genesis{
|
||||||
engine = ethash.NewFullFaker()
|
Config: params.BorUnittestChainConfig,
|
||||||
config = &CacheConfig{
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
|
}
|
||||||
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0, // Disable snapshot by default
|
SnapshotLimit: 0, // Disable snapshot by default
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
engine := miner.NewFakeBor(t, db, params.BorUnittestChainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
|
|
||||||
|
engineBorInternal, ok := engine.(*bor.Bor)
|
||||||
|
if ok {
|
||||||
|
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
|
||||||
|
copy(gspec.ExtraData[32:32+common.AddressLength], testAddress1.Bytes())
|
||||||
|
|
||||||
|
engineBorInternal.Authorize(testAddress1, func(account accounts.Account, s string, data []byte) ([]byte, error) {
|
||||||
|
return crypto.Sign(crypto.Keccak256(data), testKey1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
if snapshots {
|
if snapshots {
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
config.SnapshotWait = true
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
|
||||||
|
chain, err := core.NewBlockChain(db, config, params.BorUnittestChainConfig, engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If sidechain blocks are needed, make a light chain and import it
|
// If sidechain blocks are needed, make a light chain and import it
|
||||||
var sideblocks types.Blocks
|
var sideblocks types.Blocks
|
||||||
if tt.sidechainBlocks > 0 {
|
if tt.sidechainBlocks > 0 {
|
||||||
sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) {
|
sideblocks, _ = core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0x01})
|
b.SetCoinbase(testAddress1)
|
||||||
|
|
||||||
|
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) {
|
||||||
|
b.SetExtra(gspec.ExtraData)
|
||||||
|
} else {
|
||||||
|
b.SetExtra(make([]byte, 32+crypto.SignatureLength))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if _, err := chain.InsertChain(sideblocks); err != nil {
|
if _, err := chain.InsertChain(sideblocks); err != nil {
|
||||||
t.Fatalf("Failed to import side chain: %v", err)
|
t.Fatalf("Failed to import side chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
canonblocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) {
|
|
||||||
|
canonblocks, _ := core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *core.BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0x02})
|
b.SetCoinbase(common.Address{0x02})
|
||||||
b.SetDifficulty(big.NewInt(1000000))
|
b.SetDifficulty(big.NewInt(1000000))
|
||||||
|
|
||||||
|
if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) {
|
||||||
|
b.SetExtra(gspec.ExtraData)
|
||||||
|
} else {
|
||||||
|
b.SetExtra(make([]byte, 32+crypto.SignatureLength))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
if tt.commitBlock > 0 {
|
if tt.commitBlock > 0 {
|
||||||
chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
err = chain.StateCache().TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("on trieDB.Commit", err)
|
||||||
|
}
|
||||||
|
|
||||||
if snapshots {
|
if snapshots {
|
||||||
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
if err := chain.Snaps().Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1837,7 +1914,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
newChain, err := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
newChain, err := core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1888,19 +1965,21 @@ func TestIssue23496(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create temporary datadir: %v", err)
|
t.Fatalf("Failed to create temporary datadir: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.RemoveAll(datadir)
|
os.RemoveAll(datadir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create persistent database: %v", err)
|
t.Fatalf("Failed to create persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.Close() // Might double close, should be fine
|
defer db.Close() // Might double close, should be fine
|
||||||
|
|
||||||
// Initialize a fresh chain
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
engine = ethash.NewFullFaker()
|
engine = ethash.NewFullFaker()
|
||||||
config = &CacheConfig{
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
|
|
@ -1908,11 +1987,13 @@ func TestIssue23496(t *testing.T) {
|
||||||
SnapshotWait: true,
|
SnapshotWait: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
|
||||||
|
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), 4, func(i int, b *BlockGen) {
|
|
||||||
|
blocks, _ := core.GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), 4, func(i int, b *core.BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0x02})
|
b.SetCoinbase(common.Address{0x02})
|
||||||
b.SetDifficulty(big.NewInt(1000000))
|
b.SetDifficulty(big.NewInt(1000000))
|
||||||
})
|
})
|
||||||
|
|
@ -1921,13 +2002,18 @@ func TestIssue23496(t *testing.T) {
|
||||||
if _, err := chain.InsertChain(blocks[:1]); err != nil {
|
if _, err := chain.InsertChain(blocks[:1]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
chain.stateCache.TrieDB().Commit(blocks[0].Root(), true, nil)
|
|
||||||
|
err = chain.StateCache().TrieDB().Commit(blocks[0].Root(), true, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("on trieDB.Commit", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Insert block B2 and commit the snapshot into disk
|
// Insert block B2 and commit the snapshot into disk
|
||||||
if _, err := chain.InsertChain(blocks[1:2]); err != nil {
|
if _, err := chain.InsertChain(blocks[1:2]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
if err := chain.snaps.Cap(blocks[1].Root(), 0); err != nil {
|
|
||||||
|
if err := chain.Snaps().Cap(blocks[1].Root(), 0); err != nil {
|
||||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1935,7 +2021,11 @@ func TestIssue23496(t *testing.T) {
|
||||||
if _, err := chain.InsertChain(blocks[2:3]); err != nil {
|
if _, err := chain.InsertChain(blocks[2:3]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
chain.stateCache.TrieDB().Commit(blocks[2].Root(), true, nil)
|
|
||||||
|
err = chain.StateCache().TrieDB().Commit(blocks[2].Root(), true, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("on trieDB.Commit", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Insert the remaining blocks
|
// Insert the remaining blocks
|
||||||
if _, err := chain.InsertChain(blocks[3:]); err != nil {
|
if _, err := chain.InsertChain(blocks[3:]); err != nil {
|
||||||
|
|
@ -1950,20 +2040,24 @@ func TestIssue23496(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err = core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentBlock(); head.NumberU64() != uint64(1) {
|
if head := chain.CurrentBlock(); head.NumberU64() != uint64(1) {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(1))
|
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(1))
|
||||||
}
|
}
|
||||||
|
|
@ -1972,15 +2066,19 @@ func TestIssue23496(t *testing.T) {
|
||||||
if _, err := chain.InsertChain(blocks[1:]); err != nil {
|
if _, err := chain.InsertChain(blocks[1:]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentBlock(); head.NumberU64() != uint64(4) {
|
if head := chain.CurrentBlock(); head.NumberU64() != uint64(4) {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil {
|
if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil {
|
||||||
t.Error("Failed to regenerate the snapshot of known state")
|
t.Error("Failed to regenerate the snapshot of known state")
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// Tests that setting the chain head backwards doesn't leave the database in some
|
// Tests that setting the chain head backwards doesn't leave the database in some
|
||||||
// strange state with gaps in the chain, nor with block data dangling in the future.
|
// strange state with gaps in the chain, nor with block data dangling in the future.
|
||||||
|
|
||||||
package core
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
@ -1959,79 +1960,98 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create temporary datadir: %v", err)
|
t.Fatalf("Failed to create temporary datadir: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.RemoveAll(datadir)
|
os.RemoveAll(datadir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create persistent database: %v", err)
|
t.Fatalf("Failed to create persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// Initialize a fresh chain
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
engine = ethash.NewFullFaker()
|
engine = ethash.NewFullFaker()
|
||||||
config = &CacheConfig{
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0, // Disable snapshot
|
SnapshotLimit: 0, // Disable snapshot
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if snapshots {
|
if snapshots {
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
config.SnapshotWait = true
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
|
||||||
|
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If sidechain blocks are needed, make a light chain and import it
|
// If sidechain blocks are needed, make a light chain and import it
|
||||||
var sideblocks types.Blocks
|
var sideblocks types.Blocks
|
||||||
if tt.sidechainBlocks > 0 {
|
if tt.sidechainBlocks > 0 {
|
||||||
sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) {
|
sideblocks, _ = core.GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0x01})
|
b.SetCoinbase(common.Address{0x01})
|
||||||
})
|
})
|
||||||
|
|
||||||
if _, err := chain.InsertChain(sideblocks); err != nil {
|
if _, err := chain.InsertChain(sideblocks); err != nil {
|
||||||
t.Fatalf("Failed to import side chain: %v", err)
|
t.Fatalf("Failed to import side chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
canonblocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) {
|
|
||||||
|
canonblocks, _ := core.GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *core.BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0x02})
|
b.SetCoinbase(common.Address{0x02})
|
||||||
b.SetDifficulty(big.NewInt(1000000))
|
b.SetDifficulty(big.NewInt(1000000))
|
||||||
})
|
})
|
||||||
|
|
||||||
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.commitBlock > 0 {
|
if tt.commitBlock > 0 {
|
||||||
chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
err = chain.StateCache().TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("on trieDB.Commit", err)
|
||||||
|
}
|
||||||
|
|
||||||
if snapshots {
|
if snapshots {
|
||||||
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
if err := chain.Snaps().Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil {
|
if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually dereference anything not committed to not have to work with 128+ tries
|
// Manually dereference anything not committed to not have to work with 128+ tries
|
||||||
for _, block := range sideblocks {
|
for _, block := range sideblocks {
|
||||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
chain.StateCache().TrieDB().Dereference(block.Root())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, block := range canonblocks {
|
for _, block := range canonblocks {
|
||||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
chain.StateCache().TrieDB().Dereference(block.Root())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force run a freeze cycle
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
Freeze(threshold uint64) error
|
Freeze(threshold uint64) error
|
||||||
Ancients() (uint64, error)
|
Ancients() (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.(freezer).Freeze(tt.freezeThreshold)
|
db.(freezer).Freeze(tt.freezeThreshold)
|
||||||
|
|
||||||
// Set the simulated pivot block
|
// Set the simulated pivot block
|
||||||
if tt.pivotBlock != nil {
|
if tt.pivotBlock != nil {
|
||||||
rawdb.WriteLastPivotNumber(db, *tt.pivotBlock)
|
rawdb.WriteLastPivotNumber(db, *tt.pivotBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the head of the chain back to the requested number
|
// Set the head of the chain back to the requested number
|
||||||
chain.SetHead(tt.setheadBlock)
|
chain.SetHead(tt.setheadBlock)
|
||||||
|
|
||||||
|
|
@ -2044,12 +2064,15 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
if head := chain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock)
|
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
|
if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock)
|
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
if frozen, err := db.(freezer).Ancients(); err != nil {
|
if frozen, err := db.(freezer).Ancients(); err != nil {
|
||||||
t.Errorf("Failed to retrieve ancient count: %v\n", err)
|
t.Errorf("Failed to retrieve ancient count: %v\n", err)
|
||||||
} else if int(frozen) != tt.expFrozen {
|
} else if int(frozen) != tt.expFrozen {
|
||||||
|
|
@ -2059,7 +2082,8 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
|
|
||||||
// verifyNoGaps checks that there are no gaps after the initial set of blocks in
|
// verifyNoGaps checks that there are no gaps after the initial set of blocks in
|
||||||
// the database and errors if found.
|
// the database and errors if found.
|
||||||
func verifyNoGaps(t *testing.T, chain *BlockChain, canonical bool, inserted types.Blocks) {
|
//nolint:gocognit
|
||||||
|
func verifyNoGaps(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
var end uint64
|
var end uint64
|
||||||
|
|
@ -2111,7 +2135,8 @@ func verifyNoGaps(t *testing.T, chain *BlockChain, canonical bool, inserted type
|
||||||
|
|
||||||
// verifyCutoff checks that there are no chain data available in the chain after
|
// verifyCutoff checks that there are no chain data available in the chain after
|
||||||
// the specified limit, but that it is available before.
|
// the specified limit, but that it is available before.
|
||||||
func verifyCutoff(t *testing.T, chain *BlockChain, canonical bool, inserted types.Blocks, head int) {
|
//nolint:gocognit
|
||||||
|
func verifyCutoff(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks, head int) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
for i := 1; i <= len(inserted); i++ {
|
for i := 1; i <= len(inserted); i++ {
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// Tests that abnormal program termination (i.e.crash) and restart can recovery
|
// Tests that abnormal program termination (i.e.crash) and restart can recovery
|
||||||
// the snapshot properly if the snapshot is enabled.
|
// the snapshot properly if the snapshot is enabled.
|
||||||
|
|
||||||
package core
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
@ -57,7 +58,9 @@ type snapshotTestBasic struct {
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) {
|
func (basic *snapshotTestBasic) prepare(t *testing.T) (*core.BlockChain, []*types.Block) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
// Create a temporary persistent database
|
// Create a temporary persistent database
|
||||||
datadir, err := ioutil.TempDir("", "")
|
datadir, err := ioutil.TempDir("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -71,20 +74,22 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||||
}
|
}
|
||||||
// Initialize a fresh chain
|
// Initialize a fresh chain
|
||||||
var (
|
var (
|
||||||
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
engine = ethash.NewFullFaker()
|
engine = ethash.NewFullFaker()
|
||||||
gendb = rawdb.NewMemoryDatabase()
|
gendb = rawdb.NewMemoryDatabase()
|
||||||
|
|
||||||
// Snapshot is enabled, the first snapshot is created from the Genesis.
|
// Snapshot is enabled, the first snapshot is created from the Genesis.
|
||||||
// The snapshot memory allowance is 256MB, it means no snapshot flush
|
// The snapshot memory allowance is 256MB, it means no snapshot flush
|
||||||
// will happen during the block insertion.
|
// will happen during the block insertion.
|
||||||
cacheConfig = defaultCacheConfig
|
cacheConfig = core.DefaultCacheConfig
|
||||||
)
|
)
|
||||||
chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
|
||||||
|
chain, err := core.NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *BlockGen) {})
|
|
||||||
|
blocks, _ := core.GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *core.BlockGen) {})
|
||||||
|
|
||||||
// Insert the blocks with configured settings.
|
// Insert the blocks with configured settings.
|
||||||
var breakpoints []uint64
|
var breakpoints []uint64
|
||||||
|
|
@ -93,27 +98,39 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||||
} else {
|
} else {
|
||||||
breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock)
|
breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
var startPoint uint64
|
var startPoint uint64
|
||||||
|
|
||||||
for _, point := range breakpoints {
|
for _, point := range breakpoints {
|
||||||
if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil {
|
if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
startPoint = point
|
startPoint = point
|
||||||
|
|
||||||
if basic.commitBlock > 0 && basic.commitBlock == point {
|
if basic.commitBlock > 0 && basic.commitBlock == point {
|
||||||
chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil)
|
err = chain.StateCache().TrieDB().Commit(blocks[point-1].Root(), true, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("on trieDB.Commit", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
|
if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
|
||||||
// Flushing the entire snap tree into the disk, the
|
// Flushing the entire snap tree into the disk, the
|
||||||
// relevant (a) snapshot root and (b) snapshot generator
|
// relevant (a) snapshot root and (b) snapshot generator
|
||||||
// will be persisted atomically.
|
// will be persisted atomically.
|
||||||
chain.snaps.Cap(blocks[point-1].Root(), 0)
|
err = chain.Snaps().Cap(blocks[point-1].Root(), 0)
|
||||||
diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root()
|
if err != nil {
|
||||||
|
t.Fatal("on Snaps.Cap", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
diskRoot, blockRoot := chain.Snaps().DiskRoot(), blocks[point-1].Root()
|
||||||
if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) {
|
if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) {
|
||||||
t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot)
|
t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
|
if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
|
||||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -123,10 +140,13 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||||
basic.db = db
|
basic.db = db
|
||||||
basic.gendb = gendb
|
basic.gendb = gendb
|
||||||
basic.engine = engine
|
basic.engine = engine
|
||||||
|
|
||||||
return chain, blocks
|
return chain, blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks []*types.Block) {
|
func (basic *snapshotTestBasic) verify(t *testing.T, chain *core.BlockChain, blocks []*types.Block) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
// Iterate over all the remaining blocks and ensure there are no gaps
|
// Iterate over all the remaining blocks and ensure there are no gaps
|
||||||
verifyNoGaps(t, chain, true, blocks)
|
verifyNoGaps(t, chain, true, blocks)
|
||||||
verifyCutoff(t, chain, true, blocks, basic.expCanonicalBlocks)
|
verifyCutoff(t, chain, true, blocks, basic.expCanonicalBlocks)
|
||||||
|
|
@ -134,9 +154,11 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [
|
||||||
if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader {
|
if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader {
|
||||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
|
t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
|
if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
|
||||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock)
|
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock {
|
if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock {
|
||||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock)
|
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock)
|
||||||
}
|
}
|
||||||
|
|
@ -145,12 +167,12 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [
|
||||||
block := chain.GetBlockByNumber(basic.expSnapshotBottom)
|
block := chain.GetBlockByNumber(basic.expSnapshotBottom)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom)
|
t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom)
|
||||||
} else if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) {
|
} else if !bytes.Equal(chain.Snaps().DiskRoot().Bytes(), block.Root().Bytes()) {
|
||||||
t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot())
|
t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.Snaps().DiskRoot())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the snapshot, ensure it's integrated
|
// Check the snapshot, ensure it's integrated
|
||||||
if err := chain.snaps.Verify(block.Root()); err != nil {
|
if err := chain.Snaps().Verify(block.Root()); err != nil {
|
||||||
t.Errorf("The disk layer is not integrated %v", err)
|
t.Errorf("The disk layer is not integrated %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,10 +245,12 @@ func (snaptest *snapshotTest) test(t *testing.T) {
|
||||||
|
|
||||||
// Restart the chain normally
|
// Restart the chain normally
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
|
||||||
|
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer newchain.Stop()
|
defer newchain.Stop()
|
||||||
|
|
||||||
snaptest.verify(t, newchain, blocks)
|
snaptest.verify(t, newchain, blocks)
|
||||||
|
|
@ -245,7 +269,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||||
chain, blocks := snaptest.prepare(t)
|
chain, blocks := snaptest.prepare(t)
|
||||||
|
|
||||||
// Pull the plug on the database, simulating a hard crash
|
// Pull the plug on the database, simulating a hard crash
|
||||||
db := chain.db
|
db := chain.DB()
|
||||||
db.Close()
|
db.Close()
|
||||||
|
|
||||||
// Start a new blockchain back up and see where the repair leads us
|
// Start a new blockchain back up and see where the repair leads us
|
||||||
|
|
@ -259,13 +283,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||||
// the crash, we do restart twice here: one after the crash and one
|
// the crash, we do restart twice here: one after the crash and one
|
||||||
// after the normal stop. It's used to ensure the broken snapshot
|
// after the normal stop. It's used to ensure the broken snapshot
|
||||||
// can be detected all the time.
|
// can be detected all the time.
|
||||||
newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -292,27 +316,31 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||||
|
|
||||||
// Insert blocks without enabling snapshot if gapping is required.
|
// Insert blocks without enabling snapshot if gapping is required.
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *BlockGen) {})
|
|
||||||
|
gappedBlocks, _ := core.GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *core.BlockGen) {})
|
||||||
|
|
||||||
// Insert a few more blocks without enabling snapshot
|
// Insert a few more blocks without enabling snapshot
|
||||||
var cacheConfig = &CacheConfig{
|
var cacheConfig = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
}
|
}
|
||||||
newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
|
||||||
|
newchain, err := core.NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newchain.InsertChain(gappedBlocks)
|
newchain.InsertChain(gappedBlocks)
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
// Restart the chain with enabling the snapshot
|
// Restart the chain with enabling the snapshot
|
||||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer newchain.Stop()
|
defer newchain.Stop()
|
||||||
|
|
||||||
snaptest.verify(t, newchain, blocks)
|
snaptest.verify(t, newchain, blocks)
|
||||||
|
|
@ -337,7 +365,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||||
chain.SetHead(snaptest.setHead)
|
chain.SetHead(snaptest.setHead)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -368,11 +396,12 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
||||||
// and state committed.
|
// and state committed.
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
|
|
||||||
|
newBlocks, _ := core.GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *core.BlockGen) {})
|
||||||
newchain.InsertChain(newBlocks)
|
newchain.InsertChain(newBlocks)
|
||||||
|
|
||||||
// Commit the entire snapshot into the disk if requested. Note only
|
// Commit the entire snapshot into the disk if requested. Note only
|
||||||
|
|
@ -385,7 +414,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
||||||
// journal and latest state will be committed
|
// journal and latest state will be committed
|
||||||
|
|
||||||
// Restart the chain after the crash
|
// Restart the chain after the crash
|
||||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -414,38 +443,42 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
// and state committed.
|
// and state committed.
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
config := &CacheConfig{
|
config := &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
}
|
}
|
||||||
newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
|
||||||
|
newchain, err := core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
|
|
||||||
|
newBlocks, _ := core.GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *core.BlockGen) {})
|
||||||
newchain.InsertChain(newBlocks)
|
newchain.InsertChain(newBlocks)
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
// Restart the chain, the wiper should starts working
|
// Restart the chain, the wiper should starts working
|
||||||
config = &CacheConfig{
|
config = &core.CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
TrieDirtyLimit: 256,
|
TrieDirtyLimit: 256,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 256,
|
SnapshotLimit: 256,
|
||||||
SnapshotWait: false, // Don't wait rebuild
|
SnapshotWait: false, // Don't wait rebuild
|
||||||
}
|
}
|
||||||
newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
|
||||||
|
_, err = core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
// Simulate the blockchain crash.
|
// Simulate the blockchain crash.
|
||||||
|
|
||||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
snaptest.verify(t, newchain, blocks)
|
snaptest.verify(t, newchain, blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,24 +1,33 @@
|
||||||
|
# Bor command line interface
|
||||||
# Command line interface
|
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
- [```server```](./server.md)
|
|
||||||
|
|
||||||
- [```debug```](./debug.md)
|
|
||||||
|
|
||||||
- [```account```](./account.md)
|
- [```account```](./account.md)
|
||||||
|
|
||||||
- [```account new```](./account_new.md)
|
- [```account import```](./account_import.md)
|
||||||
|
|
||||||
- [```account list```](./account_list.md)
|
- [```account list```](./account_list.md)
|
||||||
|
|
||||||
- [```account import```](./account_import.md)
|
- [```account new```](./account_new.md)
|
||||||
|
|
||||||
|
- [```attach```](./attach.md)
|
||||||
|
|
||||||
|
- [```bootnode```](./bootnode.md)
|
||||||
|
|
||||||
- [```chain```](./chain.md)
|
- [```chain```](./chain.md)
|
||||||
|
|
||||||
- [```chain sethead```](./chain_sethead.md)
|
- [```chain sethead```](./chain_sethead.md)
|
||||||
|
|
||||||
|
- [```chain watch```](./chain_watch.md)
|
||||||
|
|
||||||
|
- [```debug```](./debug.md)
|
||||||
|
|
||||||
|
- [```debug block```](./debug_block.md)
|
||||||
|
|
||||||
|
- [```debug pprof```](./debug_pprof.md)
|
||||||
|
|
||||||
|
- [```fingerprint```](./fingerprint.md)
|
||||||
|
|
||||||
- [```peers```](./peers.md)
|
- [```peers```](./peers.md)
|
||||||
|
|
||||||
- [```peers add```](./peers_add.md)
|
- [```peers add```](./peers_add.md)
|
||||||
|
|
@ -29,8 +38,8 @@
|
||||||
|
|
||||||
- [```peers status```](./peers_status.md)
|
- [```peers status```](./peers_status.md)
|
||||||
|
|
||||||
|
- [```server```](./server.md)
|
||||||
|
|
||||||
- [```status```](./status.md)
|
- [```status```](./status.md)
|
||||||
|
|
||||||
- [```chain watch```](./chain_watch.md)
|
|
||||||
|
|
||||||
- [```version```](./version.md)
|
- [```version```](./version.md)
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Account
|
# Account
|
||||||
|
|
||||||
The ```account``` command groups actions to interact with accounts:
|
The ```account``` command groups actions to interact with accounts:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
|
|
||||||
# Account import
|
# Account import
|
||||||
|
|
||||||
The ```account import``` command imports an account in Json format to the Bor data directory.
|
The ```account import``` command imports an account in Json format to the Bor data directory.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```datadir```: Path of the data directory to store information
|
||||||
|
|
||||||
|
- ```keystore```: Path of the data directory to store information
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
|
|
||||||
# Account list
|
# Account list
|
||||||
|
|
||||||
The ```account list``` command lists all the accounts in the Bor data directory.
|
The `account list` command lists all the accounts in the Bor data directory.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```datadir```: Path of the data directory to store information
|
||||||
|
|
||||||
|
- ```keystore```: Path of the data directory to store information
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
|
|
||||||
# Account new
|
# Account new
|
||||||
|
|
||||||
The ```account new``` command creates a new local account file on the Bor data directory. Bor should not be running to execute this command.
|
The `account new` command creates a new local account file on the Bor data directory. Bor should not be running to execute this command.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```datadir```: Path of the data directory to store information
|
||||||
|
|
||||||
|
- ```keystore```: Path of the data directory to store information
|
||||||
11
docs/cli/attach.md
Normal file
11
docs/cli/attach.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Attach
|
||||||
|
|
||||||
|
Connect to remote Bor IPC console.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```exec```: Command to run in remote console
|
||||||
|
|
||||||
|
- ```preload```: Comma separated list of JavaScript files to preload into the console
|
||||||
|
|
||||||
|
- ```jspath```: JavaScript root path for `loadScript`
|
||||||
17
docs/cli/bootnode.md
Normal file
17
docs/cli/bootnode.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Bootnode
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```listen-addr```: listening address of bootnode (<ip>:<port>)
|
||||||
|
|
||||||
|
- ```v5```: Enable UDP v5
|
||||||
|
|
||||||
|
- ```log-level```: Log level (trace|debug|info|warn|error|crit)
|
||||||
|
|
||||||
|
- ```nat```: port mapping mechanism (any|none|upnp|pmp|extip:<IP>)
|
||||||
|
|
||||||
|
- ```node-key```: file or hex node key
|
||||||
|
|
||||||
|
- ```save-key```: path to save the ecdsa private key
|
||||||
|
|
||||||
|
- ```dry-run```: validates parameters and prints bootnode configurations, but does not start bootnode
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
# Chain
|
# Chain
|
||||||
|
|
||||||
The ```chain``` command groups actions to interact with the blockchain in the client:
|
The ```chain``` command groups actions to interact with the blockchain in the client:
|
||||||
|
|
||||||
- [```chain sethead```](./chain_sethead.md): Set the current chain to a certain block.
|
- [```chain sethead```](./chain_sethead.md): Set the current chain to a certain block.
|
||||||
|
|
||||||
|
- [```chain watch```](./chain_watch.md): Watch the chainHead, reorg and fork events in real-time.
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Chain sethead
|
# Chain sethead
|
||||||
|
|
||||||
The ```chain sethead <number>``` command sets the current chain to a certain block.
|
The ```chain sethead <number>``` command sets the current chain to a certain block.
|
||||||
|
|
@ -9,4 +8,6 @@ The ```chain sethead <number>``` command sets the current chain to a certain blo
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
- ```yes```: Force set head.
|
- ```address```: Address of the grpc endpoint
|
||||||
|
|
||||||
|
- ```yes```: Force set head
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
|
|
||||||
# Debug
|
# Debug
|
||||||
|
|
||||||
The ```bor debug``` command takes a debug dump of the running client.
|
The ```bor debug``` command takes a debug dump of the running client.
|
||||||
|
|
||||||
## Options
|
- [```bor debug pprof```](./debug_pprof.md): Dumps bor pprof traces.
|
||||||
|
|
||||||
- ```seconds```: Number of seconds to trace cpu and traces.
|
- [```bor debug block <number>```](./debug_block.md): Dumps bor block traces.
|
||||||
|
|
||||||
- ```output```: Output directory for the data dump.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|
|
||||||
9
docs/cli/debug_block.md
Normal file
9
docs/cli/debug_block.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Debug trace
|
||||||
|
|
||||||
|
The ```bor debug block <number>``` command will create an archive containing traces of a bor block.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```address```: Address of the grpc endpoint
|
||||||
|
|
||||||
|
- ```output```: Output directory
|
||||||
11
docs/cli/debug_pprof.md
Normal file
11
docs/cli/debug_pprof.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Debug Pprof
|
||||||
|
|
||||||
|
The ```debug pprof <enode>``` command will create an archive containing bor pprof traces.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```address```: Address of the grpc endpoint
|
||||||
|
|
||||||
|
- ```seconds```: seconds to trace
|
||||||
|
|
||||||
|
- ```output```: Output directory
|
||||||
3
docs/cli/fingerprint.md
Normal file
3
docs/cli/fingerprint.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Fingerprint
|
||||||
|
|
||||||
|
Display the system fingerprint
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Peers
|
# Peers
|
||||||
|
|
||||||
The ```peers``` command groups actions to interact with peers:
|
The ```peers``` command groups actions to interact with peers:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
|
||||||
# Peers add
|
# Peers add
|
||||||
|
|
||||||
The ```peers add <enode>``` command joins the local client to another remote peer.
|
The ```peers add <enode>``` command joins the local client to another remote peer.
|
||||||
|
|
||||||
## Arguments
|
## Options
|
||||||
|
|
||||||
- ```trusted```: Whether the peer is added as a trusted peer.
|
- ```address```: Address of the grpc endpoint
|
||||||
|
|
||||||
|
- ```trusted```: Add the peer as a trusted
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
# Peers add
|
||||||
# Peers list
|
|
||||||
|
|
||||||
The ```peers list``` command lists the connected peers.
|
The ```peers list``` command lists the connected peers.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```address```: Address of the grpc endpoint
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
|
|
||||||
# Peers remove
|
# Peers remove
|
||||||
|
|
||||||
The ```peers remove <enode>``` command disconnects the local client from a connected peer if exists.
|
The ```peers remove <enode>``` command disconnects the local client from a connected peer if exists.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```address```: Address of the grpc endpoint
|
||||||
|
|
||||||
|
- ```trusted```: Add the peer as a trusted
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
|
||||||
# Peers status
|
# Peers status
|
||||||
|
|
||||||
The ```peers status <peer id>``` command displays the status of a peer by its id.
|
The ```peers status <peer id>``` command displays the status of a peer by its id.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- ```address```: Address of the grpc endpoint
|
||||||
|
|
@ -1,45 +1,182 @@
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
|
|
||||||
The ```bor server``` command runs the Bor client.
|
The ```bor server``` command runs the Bor client.
|
||||||
|
|
||||||
## General Options
|
## Options
|
||||||
|
|
||||||
- ```chain```: Name of the chain to sync (mainnet or mumbai).
|
- ```chain```: Name of the chain to sync
|
||||||
|
|
||||||
- ```log-level```: Set log level for the server (info, warn, debug, trace).
|
- ```name```: Name/Identity of the node
|
||||||
|
|
||||||
- ```datadir```: Path of the data directory to store information (defaults to $HOME).
|
- ```log-level```: Set log level for the server
|
||||||
|
|
||||||
- ```config```: List of files that contain the configuration.
|
- ```datadir```: Path of the data directory to store information
|
||||||
|
|
||||||
- ```syncmode```: Blockchain sync mode ("fast", "full", "snap" or "light").
|
- ```keystore```: Path of the directory to store keystores
|
||||||
|
|
||||||
- ```gcmode```: Blockchain garbage collection mode ("full", "archive").
|
- ```config```: File for the config file
|
||||||
|
|
||||||
- ```whitelist```: Comma separated block number-to-hash mappings to enforce (<number>=<hash>).
|
- ```syncmode```: Blockchain sync mode ("fast", "full", or "snap")
|
||||||
|
|
||||||
- ```snapshot```: Enables snapshot-database mode (default = enable).
|
- ```gcmode```: Blockchain garbage collection mode ("full", "archive")
|
||||||
|
|
||||||
- ```bor.heimdall```: URL of Heimdall service.
|
- ```requiredblocks```: Comma separated block number-to-hash mappings to enforce (<number>=<hash>)
|
||||||
|
|
||||||
- ```bor.withoutheimdall```: Run without Heimdall service (for testing purpose).
|
- ```no-snapshot```: Disables the snapshot-database mode (default = false)
|
||||||
|
|
||||||
- ```ethstats```: Reporting URL of a ethstats service (nodename:secret@host:port).
|
- ```bor.heimdall```: URL of Heimdall service
|
||||||
|
|
||||||
- ```gpo.blocks```: Number of recent blocks to check for gas prices.
|
- ```bor.withoutheimdall```: Run without Heimdall service (for testing purpose)
|
||||||
|
|
||||||
- ```gpo.percentile```: Suggested gas price is the given percentile of a set of recent transaction gas prices.
|
- ```ethstats```: Reporting URL of a ethstats service (nodename:secret@host:port)
|
||||||
|
|
||||||
- ```gpo.maxprice```: Maximum gas price will be recommended by gpo.
|
- ```gpo.blocks```: Number of recent blocks to check for gas prices
|
||||||
|
|
||||||
- ```gpo.ignoreprice```: Gas price below which gpo will ignore transactions.
|
- ```gpo.percentile```: Suggested gas price is the given percentile of a set of recent transaction gas prices
|
||||||
|
|
||||||
- ```grpc.addr```: Address and port to bind the GRPC server.
|
- ```gpo.maxprice```: Maximum gas price will be recommended by gpo
|
||||||
|
|
||||||
|
- ```gpo.ignoreprice```: Gas price below which gpo will ignore transactions
|
||||||
|
|
||||||
|
- ```disable-bor-wallet```: Disable the personal wallet endpoints
|
||||||
|
|
||||||
|
- ```grpc.addr```: Address and port to bind the GRPC server
|
||||||
|
|
||||||
|
- ```dev```: Enable developer mode with ephemeral proof-of-authority network and a pre-funded developer account, mining enabled
|
||||||
|
|
||||||
|
- ```dev.period```: Block period to use in developer mode (0 = mine only if transaction pending)
|
||||||
|
|
||||||
|
### Account Management Options
|
||||||
|
|
||||||
|
- ```unlock```: Comma separated list of accounts to unlock
|
||||||
|
|
||||||
|
- ```password```: Password file to use for non-interactive password input
|
||||||
|
|
||||||
|
- ```allow-insecure-unlock```: Allow insecure account unlocking when account-related RPCs are exposed by http
|
||||||
|
|
||||||
|
- ```lightkdf```: Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
||||||
|
|
||||||
|
### Cache Options
|
||||||
|
|
||||||
|
- ```cache```: Megabytes of memory allocated to internal caching (default = 4096 mainnet full node)
|
||||||
|
|
||||||
|
- ```cache.database```: Percentage of cache memory allowance to use for database io
|
||||||
|
|
||||||
|
- ```cache.trie```: Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)
|
||||||
|
|
||||||
|
- ```cache.trie.journal```: Disk journal directory for trie cache to survive node restarts
|
||||||
|
|
||||||
|
- ```cache.trie.rejournal```: Time interval to regenerate the trie cache journal
|
||||||
|
|
||||||
|
- ```cache.gc```: Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)
|
||||||
|
|
||||||
|
- ```cache.snapshot```: Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode)
|
||||||
|
|
||||||
|
- ```cache.noprefetch```: Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)
|
||||||
|
|
||||||
|
- ```cache.preimages```: Enable recording the SHA3/keccak preimages of trie keys
|
||||||
|
|
||||||
|
- ```txlookuplimit```: Number of recent blocks to maintain transactions index for (default = about 56 days, 0 = entire chain)
|
||||||
|
|
||||||
|
### JsonRPC Options
|
||||||
|
|
||||||
|
- ```rpc.gascap```: Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)
|
||||||
|
|
||||||
|
- ```rpc.txfeecap```: Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)
|
||||||
|
|
||||||
|
- ```ipcdisable```: Disable the IPC-RPC server
|
||||||
|
|
||||||
|
- ```ipcpath```: Filename for IPC socket/pipe within the datadir (explicit paths escape it)
|
||||||
|
|
||||||
|
- ```jsonrpc.corsdomain```: Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||||
|
|
||||||
|
- ```jsonrpc.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
||||||
|
|
||||||
|
- ```http```: Enable the HTTP-RPC server
|
||||||
|
|
||||||
|
- ```http.addr```: HTTP-RPC server listening interface
|
||||||
|
|
||||||
|
- ```http.port```: HTTP-RPC server listening port
|
||||||
|
|
||||||
|
- ```http.rpcprefix```: HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
||||||
|
|
||||||
|
- ```http.modules```: API's offered over the HTTP-RPC interface
|
||||||
|
|
||||||
|
- ```ws```: Enable the WS-RPC server
|
||||||
|
|
||||||
|
- ```ws.addr```: WS-RPC server listening interface
|
||||||
|
|
||||||
|
- ```ws.port```: WS-RPC server listening port
|
||||||
|
|
||||||
|
- ```ws.rpcprefix```: HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
||||||
|
|
||||||
|
- ```ws.modules```: API's offered over the WS-RPC interface
|
||||||
|
|
||||||
|
- ```graphql```: Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.
|
||||||
|
|
||||||
|
### P2P Options
|
||||||
|
|
||||||
|
- ```bind```: Network binding address
|
||||||
|
|
||||||
|
- ```port```: Network listening port
|
||||||
|
|
||||||
|
- ```bootnodes```: Comma separated enode URLs for P2P discovery bootstrap
|
||||||
|
|
||||||
|
- ```maxpeers```: Maximum number of network peers (network disabled if set to 0)
|
||||||
|
|
||||||
|
- ```maxpendpeers```: Maximum number of pending connection attempts (defaults used if set to 0)
|
||||||
|
|
||||||
|
- ```nat```: NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)
|
||||||
|
|
||||||
|
- ```nodiscover```: Disables the peer discovery mechanism (manual peer addition)
|
||||||
|
|
||||||
|
- ```v5disc```: Enables the experimental RLPx V5 (Topic Discovery) mechanism
|
||||||
|
|
||||||
|
### Sealer Options
|
||||||
|
|
||||||
|
- ```mine```: Enable mining
|
||||||
|
|
||||||
|
- ```miner.etherbase```: Public address for block mining rewards (default = first account)
|
||||||
|
|
||||||
|
- ```miner.extradata```: Block extra data set by the miner (default = client version)
|
||||||
|
|
||||||
|
- ```miner.gaslimit```: Target gas ceiling for mined blocks
|
||||||
|
|
||||||
|
- ```miner.gasprice```: Minimum gas price for mining a transaction
|
||||||
|
|
||||||
|
### Telemetry Options
|
||||||
|
|
||||||
|
- ```metrics```: Enable metrics collection and reporting
|
||||||
|
|
||||||
|
- ```metrics.expensive```: Enable expensive metrics collection and reporting
|
||||||
|
|
||||||
|
- ```metrics.influxdb```: Enable metrics export/push to an external InfluxDB database (v1)
|
||||||
|
|
||||||
|
- ```metrics.influxdb.endpoint```: InfluxDB API endpoint to report metrics to
|
||||||
|
|
||||||
|
- ```metrics.influxdb.database```: InfluxDB database name to push reported metrics to
|
||||||
|
|
||||||
|
- ```metrics.influxdb.username```: Username to authorize access to the database
|
||||||
|
|
||||||
|
- ```metrics.influxdb.password```: Password to authorize access to the database
|
||||||
|
|
||||||
|
- ```metrics.influxdb.tags```: Comma-separated InfluxDB tags (key/values) attached to all measurements
|
||||||
|
|
||||||
|
- ```metrics.prometheus-addr```: Address for Prometheus Server
|
||||||
|
|
||||||
|
- ```metrics.opencollector-endpoint```: OpenCollector Endpoint (host:port)
|
||||||
|
|
||||||
|
- ```metrics.influxdbv2```: Enable metrics export/push to an external InfluxDB v2 database
|
||||||
|
|
||||||
|
- ```metrics.influxdb.token```: Token to authorize access to the database (v2 only)
|
||||||
|
|
||||||
|
- ```metrics.influxdb.bucket```: InfluxDB bucket name to push reported metrics to (v2 only)
|
||||||
|
|
||||||
|
- ```metrics.influxdb.organization```: InfluxDB organization name (v2 only)
|
||||||
|
|
||||||
### Transaction Pool Options
|
### Transaction Pool Options
|
||||||
|
|
||||||
- ```txpool.locals```: Comma separated accounts to treat as locals (no flush, priority inclusion).
|
- ```txpool.locals```: Comma separated accounts to treat as locals (no flush, priority inclusion)
|
||||||
|
|
||||||
- ```txpool.nolocals```: Disables price exemptions for locally submitted transactions
|
- ```txpool.nolocals```: Disables price exemptions for locally submitted transactions
|
||||||
|
|
||||||
|
|
@ -60,135 +197,3 @@ The ```bor server``` command runs the Bor client.
|
||||||
- ```txpool.globalqueue```: Maximum number of non-executable transaction slots for all accounts
|
- ```txpool.globalqueue```: Maximum number of non-executable transaction slots for all accounts
|
||||||
|
|
||||||
- ```txpool.lifetime```: Maximum amount of time non-executable transaction are queued
|
- ```txpool.lifetime```: Maximum amount of time non-executable transaction are queued
|
||||||
|
|
||||||
### Sealer Options
|
|
||||||
|
|
||||||
- ```mine```: Enable sealing.
|
|
||||||
|
|
||||||
- ```miner.etherbase```: Public address for block mining rewards (default = first account)
|
|
||||||
|
|
||||||
- ```miner.extradata```: Block extra data set by the miner (default = client version).
|
|
||||||
|
|
||||||
- ```miner.gaslimit```: Target gas ceiling for mined blocks.
|
|
||||||
|
|
||||||
- ```miner.gasprice```: Minimum gas price for mining a transaction.
|
|
||||||
|
|
||||||
### Cache Options
|
|
||||||
|
|
||||||
- ```cache```: Megabytes of memory allocated to internal caching (default = 4096 mainnet full node).
|
|
||||||
|
|
||||||
- ```cache.database```: Percentage of cache memory allowance to use for database io.
|
|
||||||
|
|
||||||
- ```cache.trie```: Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode).
|
|
||||||
|
|
||||||
- ```cache.trie.journal```: Disk journal directory for trie cache to survive node restarts.
|
|
||||||
|
|
||||||
- ```cache.trie.rejournal```: Time interval to regenerate the trie cache journal.
|
|
||||||
|
|
||||||
- ```cache.gc```: Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode).
|
|
||||||
|
|
||||||
- ```cache.snapshot```: Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode).
|
|
||||||
|
|
||||||
- ```cache.noprefetch```: Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data).
|
|
||||||
|
|
||||||
- ```cache.preimages```: Enable recording the SHA3/keccak preimages of trie keys.
|
|
||||||
|
|
||||||
- ```txlookuplimit```: Number of recent blocks to maintain transactions index for (default = about 56 days, 0 = entire chain).
|
|
||||||
|
|
||||||
### JsonRPC Options
|
|
||||||
|
|
||||||
- ```rpc.gascap```: Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite).
|
|
||||||
|
|
||||||
- ```rpc.txfeecap```: Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap).
|
|
||||||
|
|
||||||
- ```ipcdisable```: Disable the IPC-RPC server.
|
|
||||||
|
|
||||||
- ```ipcpath```: Filename for IPC socket/pipe within the datadir (explicit paths escape it).
|
|
||||||
|
|
||||||
- ```jsonrpc.corsdomain```: Comma separated list of domains from which to accept cross.
|
|
||||||
|
|
||||||
- ```jsonrpc.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
|
||||||
|
|
||||||
- ```http```: Enable the HTTP-RPC server.
|
|
||||||
|
|
||||||
- ```http.addr```: HTTP-RPC server listening interface.
|
|
||||||
|
|
||||||
- ```http.port```: HTTP-RPC server listening port.
|
|
||||||
|
|
||||||
- ```http.rpcprefix```: HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
|
||||||
|
|
||||||
- ```http.modules```: API's offered over the HTTP-RPC interface.
|
|
||||||
|
|
||||||
- ```ws```: Enable the WS-RPC server.
|
|
||||||
|
|
||||||
- ```ws.addr```: WS-RPC server listening interface.
|
|
||||||
|
|
||||||
- ```ws.port```: WS-RPC server listening port.
|
|
||||||
|
|
||||||
- ```ws.rpcprefix```: HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
|
||||||
|
|
||||||
- ```ws.modules```: API's offered over the WS-RPC interface.
|
|
||||||
|
|
||||||
- ```graphql```: Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.
|
|
||||||
|
|
||||||
### P2P Options
|
|
||||||
|
|
||||||
- ```bind```: Network binding address
|
|
||||||
|
|
||||||
- ```port```: Network listening port
|
|
||||||
|
|
||||||
- ```bootnodes```: Comma separated enode URLs for P2P discovery bootstrap
|
|
||||||
|
|
||||||
- ```maxpeers```: "Maximum number of network peers (network disabled if set to 0)
|
|
||||||
|
|
||||||
- ```maxpendpeers```: Maximum number of pending connection attempts (defaults used if set to 0)
|
|
||||||
|
|
||||||
- ```nat```: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)
|
|
||||||
|
|
||||||
- ```nodiscover```: "Disables the peer discovery mechanism (manual peer addition)
|
|
||||||
|
|
||||||
- ```v5disc```: "Enables the experimental RLPx V5 (Topic Discovery) mechanism
|
|
||||||
|
|
||||||
### Telemetry Options
|
|
||||||
|
|
||||||
- ```metrics```: Enable metrics collection and reporting.
|
|
||||||
|
|
||||||
- ```metrics.expensive```: Enable expensive metrics collection and reporting.
|
|
||||||
|
|
||||||
- ```metrics.influxdb```: Enable metrics export/push to an external InfluxDB database (v1).
|
|
||||||
|
|
||||||
- ```metrics.influxdb.endpoint```: InfluxDB API endpoint to report metrics to.
|
|
||||||
|
|
||||||
- ```metrics.influxdb.database```: InfluxDB database name to push reported metrics to.
|
|
||||||
|
|
||||||
- ```metrics.influxdb.username```: Username to authorize access to the database.
|
|
||||||
|
|
||||||
- ```metrics.influxdb.password```: Password to authorize access to the database.
|
|
||||||
|
|
||||||
- ```metrics.influxdb.tags```: Comma-separated InfluxDB tags (key/values) attached to all measurements.
|
|
||||||
|
|
||||||
- ```metrics.influxdbv2```: Enable metrics export/push to an external InfluxDB v2 database.
|
|
||||||
|
|
||||||
- ```metrics.influxdb.token```: Token to authorize access to the database (v2 only).
|
|
||||||
|
|
||||||
- ```metrics.influxdb.bucket```: InfluxDB bucket name to push reported metrics to (v2 only).
|
|
||||||
|
|
||||||
- ```metrics.influxdb.organization```: InfluxDB organization name (v2 only).
|
|
||||||
|
|
||||||
### Account Management Options
|
|
||||||
|
|
||||||
- ```unlock```: "Comma separated list of accounts to unlock.
|
|
||||||
|
|
||||||
- ```password```: Password file to use for non-interactive password input.
|
|
||||||
|
|
||||||
- ```allow-insecure-unlock```: Allow insecure account unlocking when account-related RPCs are exposed by http.
|
|
||||||
|
|
||||||
- ```lightkdf```: Reduce key-derivation RAM & CPU usage at some expense of KDF strength.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Use multiple files to configure the client:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bor server --config ./legacy-config.toml --config ./config2.hcl
|
|
||||||
```
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
|
|
||||||
The ```status``` command outputs the status of the client.
|
The ```status``` command outputs the status of the client.
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
|
|
||||||
The ```bor version``` command outputs the version of the binary.
|
The ```bor version``` command outputs the version of the binary.
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ type Ethereum struct {
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
accountManager *accounts.Manager
|
accountManager *accounts.Manager
|
||||||
|
authorized bool // If consensus engine is authorized with keystore
|
||||||
|
|
||||||
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
|
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
|
||||||
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
|
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
|
||||||
|
|
@ -155,6 +156,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
chainDb: chainDb,
|
chainDb: chainDb,
|
||||||
eventMux: stack.EventMux(),
|
eventMux: stack.EventMux(),
|
||||||
accountManager: stack.AccountManager(),
|
accountManager: stack.AccountManager(),
|
||||||
|
authorized: false,
|
||||||
engine: nil,
|
engine: nil,
|
||||||
closeBloomHandler: make(chan struct{}),
|
closeBloomHandler: make(chan struct{}),
|
||||||
networkID: config.NetworkId,
|
networkID: config.NetworkId,
|
||||||
|
|
@ -473,8 +475,10 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
if threads == 0 {
|
if threads == 0 {
|
||||||
threads = -1 // Disable the miner from within
|
threads = -1 // Disable the miner from within
|
||||||
}
|
}
|
||||||
|
|
||||||
th.SetThreads(threads)
|
th.SetThreads(threads)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the miner was not running, initialize it
|
// If the miner was not running, initialize it
|
||||||
if !s.IsMining() {
|
if !s.IsMining() {
|
||||||
// Propagate the initial price point to the transaction pool
|
// Propagate the initial price point to the transaction pool
|
||||||
|
|
@ -487,8 +491,13 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
eb, err := s.Etherbase()
|
eb, err := s.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot start mining without etherbase", "err", err)
|
log.Error("Cannot start mining without etherbase", "err", err)
|
||||||
|
|
||||||
return fmt.Errorf("etherbase missing: %v", err)
|
return fmt.Errorf("etherbase missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If personal endpoints are disabled, the server creating
|
||||||
|
// this Ethereum instance has already Authorized consensus.
|
||||||
|
if !s.authorized {
|
||||||
var cli *clique.Clique
|
var cli *clique.Clique
|
||||||
if c, ok := s.engine.(*clique.Clique); ok {
|
if c, ok := s.engine.(*clique.Clique); ok {
|
||||||
cli = c
|
cli = c
|
||||||
|
|
@ -497,28 +506,36 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
cli = c
|
cli = c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli != nil {
|
if cli != nil {
|
||||||
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
||||||
if wallet == nil || err != nil {
|
if wallet == nil || err != nil {
|
||||||
log.Error("Etherbase account unavailable locally", "err", err)
|
log.Error("Etherbase account unavailable locally", "err", err)
|
||||||
|
|
||||||
return fmt.Errorf("signer missing: %v", err)
|
return fmt.Errorf("signer missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cli.Authorize(eb, wallet.SignData)
|
cli.Authorize(eb, wallet.SignData)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bor, ok := s.engine.(*bor.Bor); ok {
|
if bor, ok := s.engine.(*bor.Bor); ok {
|
||||||
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
||||||
if wallet == nil || err != nil {
|
if wallet == nil || err != nil {
|
||||||
log.Error("Etherbase account unavailable locally", "err", err)
|
log.Error("Etherbase account unavailable locally", "err", err)
|
||||||
|
|
||||||
return fmt.Errorf("signer missing: %v", err)
|
return fmt.Errorf("signer missing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bor.Authorize(eb, wallet.SignData)
|
bor.Authorize(eb, wallet.SignData)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// If mining is started, we can disable the transaction rejection mechanism
|
// If mining is started, we can disable the transaction rejection mechanism
|
||||||
// introduced to speed sync times.
|
// introduced to speed sync times.
|
||||||
atomic.StoreUint32(&s.handler.acceptTxs, 1)
|
atomic.StoreUint32(&s.handler.acceptTxs, 1)
|
||||||
|
|
||||||
go s.miner.Start(eb)
|
go s.miner.Start(eb)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -557,6 +574,14 @@ func (s *Ethereum) SyncMode() downloader.SyncMode {
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetAuthorized sets the authorized bool variable
|
||||||
|
// denoting that consensus has been authorized while creation
|
||||||
|
func (s *Ethereum) SetAuthorized(authorized bool) {
|
||||||
|
s.lock.Lock()
|
||||||
|
s.authorized = authorized
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// Protocols returns all the currently configured
|
// Protocols returns all the currently configured
|
||||||
// network protocols to start.
|
// network protocols to start.
|
||||||
func (s *Ethereum) Protocols() []p2p.Protocol {
|
func (s *Ethereum) Protocols() []p2p.Protocol {
|
||||||
|
|
@ -564,6 +589,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
|
||||||
if s.config.SnapshotCache > 0 {
|
if s.config.SnapshotCache > 0 {
|
||||||
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
|
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return protos
|
return protos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -645,7 +671,7 @@ func (s *Ethereum) handleWhitelistCheckpoint() error {
|
||||||
return ErrNotBorConsensus
|
return ErrNotBorConsensus
|
||||||
}
|
}
|
||||||
|
|
||||||
if bor.WithoutHeimdall {
|
if bor.HeimdallClient == nil {
|
||||||
return ErrBorConsensusWithoutHeimdall
|
return ErrBorConsensusWithoutHeimdall
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,7 @@ type BlockChain interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
||||||
|
//nolint: staticcheck
|
||||||
func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func(), whitelistService ChainValidator) *Downloader {
|
func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func(), whitelistService ChainValidator) *Downloader {
|
||||||
if lightchain == nil {
|
if lightchain == nil {
|
||||||
lightchain = chain
|
lightchain = chain
|
||||||
|
|
@ -1379,6 +1380,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||||
if chunkHeaders[len(chunkHeaders)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot {
|
if chunkHeaders[len(chunkHeaders)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot {
|
||||||
frequency = 1
|
frequency = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Although the received headers might be all valid, a legacy
|
// Although the received headers might be all valid, a legacy
|
||||||
// PoW/PoA sync must not accept post-merge headers. Make sure
|
// PoW/PoA sync must not accept post-merge headers. Make sure
|
||||||
// that any transition is rejected at this point.
|
// that any transition is rejected at this point.
|
||||||
|
|
@ -1386,13 +1388,16 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||||
rejected []*types.Header
|
rejected []*types.Header
|
||||||
td *big.Int
|
td *big.Int
|
||||||
)
|
)
|
||||||
|
|
||||||
if !beaconMode && ttd != nil {
|
if !beaconMode && ttd != nil {
|
||||||
td = d.blockchain.GetTd(chunkHeaders[0].ParentHash, chunkHeaders[0].Number.Uint64()-1)
|
td = d.blockchain.GetTd(chunkHeaders[0].ParentHash, chunkHeaders[0].Number.Uint64()-1)
|
||||||
if td == nil {
|
if td == nil {
|
||||||
// This should never really happen, but handle gracefully for now
|
// This should never really happen, but handle gracefully for now
|
||||||
log.Error("Failed to retrieve parent header TD", "number", chunkHeaders[0].Number.Uint64()-1, "hash", chunkHeaders[0].ParentHash)
|
log.Error("Failed to retrieve parent header TD", "number", chunkHeaders[0].Number.Uint64()-1, "hash", chunkHeaders[0].ParentHash)
|
||||||
|
|
||||||
return fmt.Errorf("%w: parent TD missing", errInvalidChain)
|
return fmt.Errorf("%w: parent TD missing", errInvalidChain)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, header := range chunkHeaders {
|
for i, header := range chunkHeaders {
|
||||||
td = new(big.Int).Add(td, header.Difficulty)
|
td = new(big.Int).Add(td, header.Difficulty)
|
||||||
if td.Cmp(ttd) >= 0 {
|
if td.Cmp(ttd) >= 0 {
|
||||||
|
|
@ -1406,10 +1411,12 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||||
} else {
|
} else {
|
||||||
chunkHeaders, rejected = chunkHeaders[:i], chunkHeaders[i:]
|
chunkHeaders, rejected = chunkHeaders[:i], chunkHeaders[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(chunkHeaders) > 0 {
|
if len(chunkHeaders) > 0 {
|
||||||
if n, err := d.lightchain.InsertHeaderChain(chunkHeaders, frequency); err != nil {
|
if n, err := d.lightchain.InsertHeaderChain(chunkHeaders, frequency); err != nil {
|
||||||
rollbackErr = err
|
rollbackErr = err
|
||||||
|
|
@ -1418,12 +1425,15 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||||
if (mode == SnapSync || frequency > 1) && n > 0 && rollback == 0 {
|
if (mode == SnapSync || frequency > 1) && n > 0 && rollback == 0 {
|
||||||
rollback = chunkHeaders[0].Number.Uint64()
|
rollback = chunkHeaders[0].Number.Uint64()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err)
|
log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err)
|
||||||
|
|
||||||
return fmt.Errorf("%w: %v", errInvalidChain, err)
|
return fmt.Errorf("%w: %v", errInvalidChain, err)
|
||||||
}
|
}
|
||||||
// All verifications passed, track all headers within the allowed limits
|
// All verifications passed, track all headers within the allowed limits
|
||||||
if mode == SnapSync {
|
if mode == SnapSync {
|
||||||
head := chunkHeaders[len(chunkHeaders)-1].Number.Uint64()
|
head := chunkHeaders[len(chunkHeaders)-1].Number.Uint64()
|
||||||
|
|
||||||
if head-rollback > uint64(fsHeaderSafetyNet) {
|
if head-rollback > uint64(fsHeaderSafetyNet) {
|
||||||
rollback = head - uint64(fsHeaderSafetyNet)
|
rollback = head - uint64(fsHeaderSafetyNet)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1431,21 +1441,26 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rejected) != 0 {
|
if len(rejected) != 0 {
|
||||||
// Merge threshold reached, stop importing, but don't roll back
|
// Merge threshold reached, stop importing, but don't roll back
|
||||||
rollback = 0
|
rollback = 0
|
||||||
|
|
||||||
log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd)
|
log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd)
|
||||||
|
|
||||||
return ErrMergeTransition
|
return ErrMergeTransition
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rejected) != 0 {
|
if len(rejected) != 0 {
|
||||||
// Merge threshold reached, stop importing, but don't roll back
|
// Merge threshold reached, stop importing, but don't roll back
|
||||||
rollback = 0
|
rollback = 0
|
||||||
|
|
||||||
log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd)
|
log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd)
|
||||||
|
|
||||||
return ErrMergeTransition
|
return ErrMergeTransition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless we're doing light chains, schedule the headers for associated content retrieval
|
// Unless we're doing light chains, schedule the headers for associated content retrieval
|
||||||
if mode == FullSync || mode == SnapSync {
|
if mode == FullSync || mode == SnapSync {
|
||||||
// If we've reached the allowed number of pending headers, stall a bit
|
// If we've reached the allowed number of pending headers, stall a bit
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -62,23 +63,28 @@ func newTester() *downloadTester {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false)
|
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000))
|
core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000))
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tester := &downloadTester{
|
tester := &downloadTester{
|
||||||
freezer: freezer,
|
freezer: freezer,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
peers: make(map[string]*downloadTesterPeer),
|
peers: make(map[string]*downloadTesterPeer),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint: staticcheck
|
||||||
tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, nil, whitelist.NewService(10))
|
tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, nil, whitelist.NewService(10))
|
||||||
|
|
||||||
return tester
|
return tester
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1349,6 +1355,7 @@ func TestRemoteHeaderRequestSpan(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if failed {
|
if failed {
|
||||||
res := strings.Replace(fmt.Sprint(data), " ", ",", -1)
|
res := strings.Replace(fmt.Sprint(data), " ", ",", -1)
|
||||||
exp := strings.Replace(fmt.Sprint(tt.expected), " ", ",", -1)
|
exp := strings.Replace(fmt.Sprint(tt.expected), " ", ",", -1)
|
||||||
|
|
@ -1383,9 +1390,11 @@ func testCheckpointEnforcement(t *testing.T, protocol uint, mode SyncMode) {
|
||||||
if mode == SnapSync || mode == LightSync {
|
if mode == SnapSync || mode == LightSync {
|
||||||
expect = errUnsyncedPeer
|
expect = errUnsyncedPeer
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tester.sync("peer", nil, mode); !errors.Is(err, expect) {
|
if err := tester.sync("peer", nil, mode); !errors.Is(err, expect) {
|
||||||
t.Fatalf("block sync error mismatch: have %v, want %v", err, expect)
|
t.Fatalf("block sync error mismatch: have %v, want %v", err, expect)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode == SnapSync || mode == LightSync {
|
if mode == SnapSync || mode == LightSync {
|
||||||
assertOwnChain(t, tester, 1)
|
assertOwnChain(t, tester, 1)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1409,14 +1418,15 @@ func newWhitelistFake(validate func(count int) (bool, error)) *whitelistFake {
|
||||||
|
|
||||||
// IsValidChain is the mock function which the downloader will use to validate the chain
|
// IsValidChain is the mock function which the downloader will use to validate the chain
|
||||||
// to be received from a peer.
|
// to be received from a peer.
|
||||||
func (w *whitelistFake) IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
func (w *whitelistFake) IsValidChain(_ *types.Header, _ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
w.count++
|
w.count++
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return w.validate(w.count)
|
return w.validate(w.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *whitelistFake) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {}
|
func (w *whitelistFake) ProcessCheckpoint(_ uint64, _ common.Hash) {}
|
||||||
|
|
||||||
func (w *whitelistFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
func (w *whitelistFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1427,6 +1437,8 @@ func (w *whitelistFake) PurgeCheckpointWhitelist() {}
|
||||||
// TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted
|
// TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted
|
||||||
// checkpoint mismatch with opposite peer, the sync should fail.
|
// checkpoint mismatch with opposite peer, the sync should fail.
|
||||||
func TestFakedSyncProgress66WhitelistMismatch(t *testing.T) {
|
func TestFakedSyncProgress66WhitelistMismatch(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
protocol := uint(eth.ETH66)
|
protocol := uint(eth.ETH66)
|
||||||
mode := FullSync
|
mode := FullSync
|
||||||
|
|
||||||
|
|
@ -1450,6 +1462,8 @@ func TestFakedSyncProgress66WhitelistMismatch(t *testing.T) {
|
||||||
// TestFakedSyncProgress66WhitelistMatch tests if in case of whitelisted
|
// TestFakedSyncProgress66WhitelistMatch tests if in case of whitelisted
|
||||||
// checkpoint match with opposite peer, the sync should succeed.
|
// checkpoint match with opposite peer, the sync should succeed.
|
||||||
func TestFakedSyncProgress66WhitelistMatch(t *testing.T) {
|
func TestFakedSyncProgress66WhitelistMatch(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
protocol := uint(eth.ETH66)
|
protocol := uint(eth.ETH66)
|
||||||
mode := FullSync
|
mode := FullSync
|
||||||
|
|
||||||
|
|
@ -1474,6 +1488,8 @@ func TestFakedSyncProgress66WhitelistMatch(t *testing.T) {
|
||||||
// checkpointed blocks with opposite peer, the sync should fail initially but
|
// checkpointed blocks with opposite peer, the sync should fail initially but
|
||||||
// with the retry mechanism, it should succeed eventually.
|
// with the retry mechanism, it should succeed eventually.
|
||||||
func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) {
|
func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
protocol := uint(eth.ETH66)
|
protocol := uint(eth.ETH66)
|
||||||
mode := FullSync
|
mode := FullSync
|
||||||
|
|
||||||
|
|
@ -1483,8 +1499,10 @@ func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) {
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return false, whitelist.ErrNoRemoteCheckoint
|
return false, whitelist.ErrNoRemoteCheckoint
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tester.downloader.ChainValidator = newWhitelistFake(validate)
|
tester.downloader.ChainValidator = newWhitelistFake(validate)
|
||||||
|
|
||||||
defer tester.terminate()
|
defer tester.terminate()
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ var (
|
||||||
func (w *Service) IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
func (w *Service) IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
// We want to validate the chain by comparing the last checkpointed block
|
// We want to validate the chain by comparing the last checkpointed block
|
||||||
// we're storing in `checkpointWhitelist` with the peer's block.
|
// we're storing in `checkpointWhitelist` with the peer's block.
|
||||||
|
//
|
||||||
// Check for availaibility of the last checkpointed block.
|
// Check for availaibility of the last checkpointed block.
|
||||||
// This can be also be empty if our heimdall is not responding
|
// This can be also be empty if our heimdall is not responding
|
||||||
// or we're running without it.
|
// or we're running without it.
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gotest.tools/assert"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"gotest.tools/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewMockService creates a new mock whitelist service
|
// NewMockService creates a new mock whitelist service
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/contract"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -237,7 +240,14 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, et
|
||||||
// In order to pass the ethereum transaction tests, we need to set the burn contract which is in the bor config
|
// In order to pass the ethereum transaction tests, we need to set the burn contract which is in the bor config
|
||||||
// Then, bor != nil will also be enabled for ethash and clique. Only enable Bor for real if there is a validator contract present.
|
// Then, bor != nil will also be enabled for ethash and clique. Only enable Bor for real if there is a validator contract present.
|
||||||
if chainConfig.Bor != nil && chainConfig.Bor.ValidatorContract != "" {
|
if chainConfig.Bor != nil && chainConfig.Bor.ValidatorContract != "" {
|
||||||
return bor.New(chainConfig, db, blockchainAPI, ethConfig.HeimdallURL, ethConfig.WithoutHeimdall)
|
genesisContractsClient := contract.NewGenesisContractsClient(chainConfig, chainConfig.Bor.ValidatorContract, chainConfig.Bor.StateReceiverContract, blockchainAPI)
|
||||||
|
spanner := span.NewChainSpanner(blockchainAPI, contract.ValidatorSet(), chainConfig, common.HexToAddress(chainConfig.Bor.ValidatorContract))
|
||||||
|
|
||||||
|
if ethConfig.WithoutHeimdall {
|
||||||
|
return bor.New(chainConfig, db, blockchainAPI, spanner, nil, genesisContractsClient)
|
||||||
|
} else {
|
||||||
|
return bor.New(chainConfig, db, blockchainAPI, spanner, heimdall.NewHeimdallClient(ethConfig.HeimdallURL), genesisContractsClient)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch config.PowMode {
|
switch config.PowMode {
|
||||||
case ethash.ModeFake:
|
case ethash.ModeFake:
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ type handlerConfig struct {
|
||||||
Network uint64 // Network identifier to adfvertise
|
Network uint64 // Network identifier to adfvertise
|
||||||
Sync downloader.SyncMode // Whether to snap or full sync
|
Sync downloader.SyncMode // Whether to snap or full sync
|
||||||
BloomCache uint64 // Megabytes to alloc for snap sync bloom
|
BloomCache uint64 // Megabytes to alloc for snap sync bloom
|
||||||
EventMux *event.TypeMux // Legacy event mux, deprecate for `feed`
|
EventMux *event.TypeMux //nolint:staticcheck // Legacy event mux, deprecate for `feed`
|
||||||
Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges
|
Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges
|
||||||
EthAPI *ethapi.PublicBlockChainAPI // EthAPI to interact
|
EthAPI *ethapi.PublicBlockChainAPI // EthAPI to interact
|
||||||
|
|
||||||
|
|
|
||||||
150
eth/tracers/api_bor.go
Normal file
150
eth/tracers/api_bor.go
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
package tracers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BlockTraceResult struct {
|
||||||
|
// Trace of each transaction executed
|
||||||
|
Transactions []*TxTraceResult `json:"transactions,omitempty"`
|
||||||
|
|
||||||
|
// Block that we are executing on the trace
|
||||||
|
Block interface{} `json:"block"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TxTraceResult struct {
|
||||||
|
// Trace results produced by the tracer
|
||||||
|
Result interface{} `json:"result,omitempty"`
|
||||||
|
|
||||||
|
// Trace failure produced by the tracer
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
|
||||||
|
// IntermediateHash of the execution if succeeds
|
||||||
|
IntermediateHash common.Hash `json:"intermediatehash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *TraceConfig) (*BlockTraceResult, error) {
|
||||||
|
if block.NumberU64() == 0 {
|
||||||
|
return nil, fmt.Errorf("genesis is not traceable")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &BlockTraceResult{
|
||||||
|
Block: block,
|
||||||
|
}
|
||||||
|
|
||||||
|
// block object cannot be converted to JSON since much of the fields are non-public
|
||||||
|
blockFields, err := ethapi.RPCMarshalBlock(block, true, true, api.backend.ChainConfig())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Block = blockFields
|
||||||
|
|
||||||
|
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reexec := defaultTraceReexec
|
||||||
|
if config != nil && config.Reexec != nil {
|
||||||
|
reexec = *config.Reexec
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: discuss consequences of setting preferDisk false.
|
||||||
|
statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute all the transaction contained within the block concurrently
|
||||||
|
var (
|
||||||
|
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||||
|
txs = block.Transactions()
|
||||||
|
deleteEmptyObjects = api.backend.ChainConfig().IsEIP158(block.Number())
|
||||||
|
)
|
||||||
|
|
||||||
|
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
|
|
||||||
|
traceTxn := func(indx int, tx *types.Transaction) *TxTraceResult {
|
||||||
|
message, _ := tx.AsMessage(signer, block.BaseFee())
|
||||||
|
txContext := core.NewEVMTxContext(message)
|
||||||
|
|
||||||
|
tracer := logger.NewStructLogger(config.Config)
|
||||||
|
|
||||||
|
// Run the transaction with tracing enabled.
|
||||||
|
vmenv := vm.NewEVM(blockCtx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
||||||
|
|
||||||
|
// Call Prepare to clear out the statedb access list
|
||||||
|
// Not sure if we need to do this
|
||||||
|
statedb.Prepare(tx.Hash(), indx)
|
||||||
|
|
||||||
|
execRes, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
|
||||||
|
if err != nil {
|
||||||
|
return &TxTraceResult{
|
||||||
|
Error: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
returnVal := fmt.Sprintf("%x", execRes.Return())
|
||||||
|
if len(execRes.Revert()) > 0 {
|
||||||
|
returnVal = fmt.Sprintf("%x", execRes.Revert())
|
||||||
|
}
|
||||||
|
|
||||||
|
result := ðapi.ExecutionResult{
|
||||||
|
Gas: execRes.UsedGas,
|
||||||
|
Failed: execRes.Failed(),
|
||||||
|
ReturnValue: returnVal,
|
||||||
|
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
||||||
|
}
|
||||||
|
res := &TxTraceResult{
|
||||||
|
Result: result,
|
||||||
|
IntermediateHash: statedb.IntermediateRoot(deleteEmptyObjects),
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
for indx, tx := range txs {
|
||||||
|
res.Transactions = append(res.Transactions, traceTxn(indx, tx))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TraceBlockRequest struct {
|
||||||
|
Number int64
|
||||||
|
Hash string
|
||||||
|
IsBadBlock bool
|
||||||
|
Config *TraceConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you use context as first parameter this function gets exposed automaticall on rpc endpoint
|
||||||
|
func (api *API) TraceBorBlock(req *TraceBlockRequest) (*BlockTraceResult, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
var blockNumber rpc.BlockNumber
|
||||||
|
if req.Number == -1 {
|
||||||
|
blockNumber = rpc.LatestBlockNumber
|
||||||
|
} else {
|
||||||
|
blockNumber = rpc.BlockNumber(req.Number)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Tracing Bor Block", "block number", blockNumber)
|
||||||
|
|
||||||
|
block, err := api.blockByNumber(ctx, blockNumber)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.traceBorBlock(ctx, block, req.Config)
|
||||||
|
}
|
||||||
79
go.mod
79
go.mod
|
|
@ -1,10 +1,9 @@
|
||||||
module github.com/ethereum/go-ethereum
|
module github.com/ethereum/go-ethereum
|
||||||
|
|
||||||
go 1.16
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0
|
||||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
|
||||||
github.com/VictoriaMetrics/fastcache v1.6.0
|
github.com/VictoriaMetrics/fastcache v1.6.0
|
||||||
github.com/aws/aws-sdk-go-v2 v1.2.0
|
github.com/aws/aws-sdk-go-v2 v1.2.0
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.1.1
|
github.com/aws/aws-sdk-go-v2/config v1.1.1
|
||||||
|
|
@ -16,19 +15,15 @@ require (
|
||||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f
|
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set v1.8.0
|
github.com/deckarep/golang-set v1.8.0
|
||||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
|
||||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf
|
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf
|
||||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48
|
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48
|
||||||
github.com/edsrzf/mmap-go v1.0.0
|
github.com/edsrzf/mmap-go v1.0.0
|
||||||
github.com/fatih/color v1.7.0
|
github.com/fatih/color v1.7.0
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
|
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
|
||||||
github.com/go-kit/kit v0.9.0 // indirect
|
|
||||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
|
||||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
|
||||||
github.com/go-stack/stack v1.8.0
|
github.com/go-stack/stack v1.8.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||||
github.com/golang/mock v1.3.1
|
github.com/golang/mock v1.6.0
|
||||||
github.com/golang/protobuf v1.5.2
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/golang/snappy v0.0.4
|
github.com/golang/snappy v0.0.4
|
||||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
|
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
|
||||||
|
|
@ -44,18 +39,15 @@ require (
|
||||||
github.com/imdario/mergo v0.3.11
|
github.com/imdario/mergo v0.3.11
|
||||||
github.com/influxdata/influxdb v1.8.3
|
github.com/influxdata/influxdb v1.8.3
|
||||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
||||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2
|
github.com/jackpal/go-nat-pmp v1.0.2
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/karalabe/usb v0.0.2
|
github.com/karalabe/usb v0.0.2
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.8
|
github.com/mattn/go-colorable v0.1.8
|
||||||
github.com/mattn/go-isatty v0.0.12
|
github.com/mattn/go-isatty v0.0.12
|
||||||
github.com/mitchellh/cli v1.1.2
|
github.com/mitchellh/cli v1.1.2
|
||||||
github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0
|
github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/naoina/go-stringutil v0.1.0 // indirect
|
|
||||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
|
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
|
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
|
||||||
|
|
@ -67,22 +59,81 @@ require (
|
||||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
||||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
|
||||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
|
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
|
||||||
github.com/xsleonard/go-merkle v1.1.0
|
github.com/xsleonard/go-merkle v1.1.0
|
||||||
go.opentelemetry.io/otel v1.2.0
|
go.opentelemetry.io/otel v1.2.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
||||||
go.opentelemetry.io/otel/sdk v1.2.0
|
go.opentelemetry.io/otel/sdk v1.2.0
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
|
go.uber.org/goleak v1.1.12
|
||||||
|
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||||
golang.org/x/tools v0.1.0
|
golang.org/x/tools v0.1.10
|
||||||
google.golang.org/grpc v1.42.0
|
google.golang.org/grpc v1.42.0
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
|
||||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
|
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
|
||||||
gopkg.in/urfave/cli.v1 v1.20.0
|
gopkg.in/urfave/cli.v1 v1.20.0
|
||||||
gotest.tools v2.2.0+incompatible
|
gotest.tools v2.2.0+incompatible
|
||||||
|
pgregory.net/rapid v0.4.7
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
|
||||||
|
github.com/Masterminds/goutils v1.1.0 // indirect
|
||||||
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
|
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||||
|
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||||
|
github.com/agext/levenshtein v1.2.1 // indirect
|
||||||
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect
|
||||||
|
github.com/aws/smithy-go v1.1.0 // indirect
|
||||||
|
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||||
|
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||||
|
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||||
|
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
|
||||||
|
github.com/go-kit/kit v0.9.0 // indirect
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||||
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||||
|
github.com/google/go-cmp v0.5.8 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
|
github.com/hashicorp/go-multierror v1.0.0 // indirect
|
||||||
|
github.com/huandu/xstrings v1.3.2 // indirect
|
||||||
|
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||||
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
|
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||||
|
github.com/naoina/go-stringutil v0.1.0 // indirect
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/posener/complete v1.1.1 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||||
|
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.2.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
40
go.sum
40
go.sum
|
|
@ -49,7 +49,6 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||||
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
|
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
|
||||||
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
|
|
||||||
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
|
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||||
|
|
@ -82,14 +81,12 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=
|
github.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q=
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
|
||||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
|
@ -194,8 +191,9 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
|
@ -229,8 +227,9 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/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.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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64=
|
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64=
|
||||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
|
@ -448,7 +447,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
||||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
|
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
|
||||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
|
@ -479,6 +477,7 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut
|
||||||
github.com/xsleonard/go-merkle v1.1.0 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg=
|
github.com/xsleonard/go-merkle v1.1.0 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg=
|
||||||
github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg=
|
github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg=
|
||||||
github.com/yuin/goldmark v1.2.1/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/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||||
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
|
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
|
||||||
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||||
|
|
@ -500,6 +499,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
|
||||||
go.opentelemetry.io/proto/otlp v0.10.0 h1:n7brgtEbDvXEgGyKKo8SobKT1e9FewlDtXzkVP5djoE=
|
go.opentelemetry.io/proto/otlp v0.10.0 h1:n7brgtEbDvXEgGyKKo8SobKT1e9FewlDtXzkVP5djoE=
|
||||||
go.opentelemetry.io/proto/otlp v0.10.0/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU=
|
go.opentelemetry.io/proto/otlp v0.10.0/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||||
|
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
|
@ -512,8 +513,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
|
||||||
|
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
|
@ -534,6 +536,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
|
@ -541,8 +544,9 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180811021610-c39426892332/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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
|
@ -568,9 +572,11 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
|
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
|
@ -620,11 +626,13 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||||
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
|
@ -668,13 +676,17 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||||
|
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||||
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
||||||
|
|
@ -770,5 +782,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||||
|
pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g=
|
||||||
|
pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
|
|
||||||
33
integration-tests/smoke_test.sh
Normal file
33
integration-tests/smoke_test.sh
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
delay=600
|
||||||
|
|
||||||
|
echo "Wait ${delay} seconds for state-sync..."
|
||||||
|
sleep $delay
|
||||||
|
|
||||||
|
|
||||||
|
balance=$(docker exec bor0 bash -c "bor attach /root/.bor/data/bor.ipc -exec 'Math.round(web3.fromWei(eth.getBalance(eth.accounts[0])))'")
|
||||||
|
|
||||||
|
if ! [[ "$balance" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Something is wrong! Can't find the balance of first account in bor network."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Found matic balance on account[0]: " $balance
|
||||||
|
|
||||||
|
if (( $balance <= 1001 )); then
|
||||||
|
echo "Balance in bor network has not increased. This indicates that something is wrong with state sync."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
checkpointID=$(curl -sL http://localhost:1317/checkpoints/latest | jq .result.id)
|
||||||
|
|
||||||
|
if [ $checkpointID == "null" ]; then
|
||||||
|
echo "Something is wrong! Could not find any checkpoint."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Found checkpoint ID:" $checkpointID
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "All tests have passed!"
|
||||||
|
|
@ -1,11 +1,28 @@
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import "github.com/mitchellh/cli"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
)
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
UI cli.Ui
|
UI cli.Ui
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (a *Account) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Account",
|
||||||
|
"The ```account``` command groups actions to interact with accounts:",
|
||||||
|
"- [```account new```](./account_new.md): Create a new account in the Bor client.",
|
||||||
|
"- [```account list```](./account_list.md): List the wallets in the Bor client.",
|
||||||
|
"- [```account import```](./account_import.md): Import an account to the Bor client.",
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (a *Account) Help() string {
|
func (a *Account) Help() string {
|
||||||
return `Usage: bor account <subcommand>
|
return `Usage: bor account <subcommand>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -12,6 +13,17 @@ type AccountImportCommand struct {
|
||||||
*Meta
|
*Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (a *AccountImportCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Account import",
|
||||||
|
"The ```account import``` command imports an account in Json format to the Bor data directory.",
|
||||||
|
a.Flags().MarkDown(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (a *AccountImportCommand) Help() string {
|
func (a *AccountImportCommand) Help() string {
|
||||||
return `Usage: bor account import
|
return `Usage: bor account import
|
||||||
|
|
@ -47,7 +59,9 @@ func (a *AccountImportCommand) Run(args []string) int {
|
||||||
a.UI.Error("Expected one argument")
|
a.UI.Error("Expected one argument")
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := crypto.LoadECDSA(args[0])
|
key, err := crypto.LoadECDSA(args[0])
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.UI.Error(fmt.Sprintf("Failed to load the private key '%s': %v", args[0], err))
|
a.UI.Error(fmt.Sprintf("Failed to load the private key '%s': %v", args[0], err))
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -69,6 +83,8 @@ func (a *AccountImportCommand) Run(args []string) int {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Could not create the account: %v", err)
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.UI.Output(fmt.Sprintf("Account created: %s", acct.Address.String()))
|
a.UI.Output(fmt.Sprintf("Account created: %s", acct.Address.String()))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||||
|
|
@ -11,6 +12,17 @@ type AccountListCommand struct {
|
||||||
*Meta
|
*Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (a *AccountListCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Account list",
|
||||||
|
"The `account list` command lists all the accounts in the Bor data directory.",
|
||||||
|
a.Flags().MarkDown(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (a *AccountListCommand) Help() string {
|
func (a *AccountListCommand) Help() string {
|
||||||
return `Usage: bor account list
|
return `Usage: bor account list
|
||||||
|
|
@ -42,7 +54,9 @@ func (a *AccountListCommand) Run(args []string) int {
|
||||||
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
a.UI.Output(formatAccounts(keystore.Accounts()))
|
a.UI.Output(formatAccounts(keystore.Accounts()))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,10 +67,12 @@ func formatAccounts(accts []accounts.Account) string {
|
||||||
|
|
||||||
rows := make([]string, len(accts)+1)
|
rows := make([]string, len(accts)+1)
|
||||||
rows[0] = "Index|Address"
|
rows[0] = "Index|Address"
|
||||||
|
|
||||||
for i, d := range accts {
|
for i, d := range accts {
|
||||||
rows[i+1] = fmt.Sprintf("%d|%s",
|
rows[i+1] = fmt.Sprintf("%d|%s",
|
||||||
i,
|
i,
|
||||||
d.Address.String())
|
d.Address.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatList(rows)
|
return formatList(rows)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||||
)
|
)
|
||||||
|
|
@ -10,6 +11,17 @@ type AccountNewCommand struct {
|
||||||
*Meta
|
*Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (a *AccountNewCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Account new",
|
||||||
|
"The `account new` command creates a new local account file on the Bor data directory. Bor should not be running to execute this command.",
|
||||||
|
a.Flags().MarkDown(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (a *AccountNewCommand) Help() string {
|
func (a *AccountNewCommand) Help() string {
|
||||||
return `Usage: bor account new
|
return `Usage: bor account new
|
||||||
|
|
|
||||||
193
internal/cli/attach.go
Normal file
193
internal/cli/attach.go
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/console"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AttachCommand is the command to Connect to remote Bor IPC console
|
||||||
|
type AttachCommand struct {
|
||||||
|
UI cli.Ui
|
||||||
|
Meta *Meta
|
||||||
|
Meta2 *Meta2
|
||||||
|
ExecCMD string
|
||||||
|
Endpoint string
|
||||||
|
PreloadJSFlag string
|
||||||
|
JSpathFlag string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (c *AttachCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Attach",
|
||||||
|
"Connect to remote Bor IPC console.",
|
||||||
|
c.Flags().MarkDown(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help implements the cli.Command interface
|
||||||
|
func (c *AttachCommand) Help() string {
|
||||||
|
return `Usage: bor attach <IPC FILE>
|
||||||
|
|
||||||
|
Connect to remote Bor IPC console.`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis implements the cli.Command interface
|
||||||
|
func (c *AttachCommand) Synopsis() string {
|
||||||
|
return "Connect to Bor via IPC"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AttachCommand) Flags() *flagset.Flagset {
|
||||||
|
f := flagset.NewFlagSet("attach")
|
||||||
|
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "exec",
|
||||||
|
Usage: "Command to run in remote console",
|
||||||
|
Value: &c.ExecCMD,
|
||||||
|
})
|
||||||
|
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "preload",
|
||||||
|
Usage: "Comma separated list of JavaScript files to preload into the console",
|
||||||
|
Value: &c.PreloadJSFlag,
|
||||||
|
})
|
||||||
|
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "jspath",
|
||||||
|
Usage: "JavaScript root path for `loadScript`",
|
||||||
|
Value: &c.JSpathFlag,
|
||||||
|
})
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run implements the cli.Command interface
|
||||||
|
func (c *AttachCommand) Run(args []string) int {
|
||||||
|
flags := c.Flags()
|
||||||
|
|
||||||
|
//check if first arg is flag or IPC location
|
||||||
|
if len(args) == 0 {
|
||||||
|
args = append(args, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if args[0] != "" && strings.HasPrefix(args[0], "--") {
|
||||||
|
if err := flags.Parse(args); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.Endpoint = args[0]
|
||||||
|
if err := flags.Parse(args[1:]); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.remoteConsole(); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// remoteConsole will connect to a remote bor instance, attaching a JavaScript
|
||||||
|
// console to it.
|
||||||
|
// nolint: unparam
|
||||||
|
func (c *AttachCommand) remoteConsole() error {
|
||||||
|
// Attach to a remotely running geth instance and start the JavaScript console
|
||||||
|
path := node.DefaultDataDir()
|
||||||
|
|
||||||
|
if c.Endpoint == "" {
|
||||||
|
if c.Meta.dataDir != "" {
|
||||||
|
path = c.Meta.dataDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if path != "" {
|
||||||
|
homeDir, _ := os.UserHomeDir()
|
||||||
|
path = filepath.Join(homeDir, "/.bor/data")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Endpoint = fmt.Sprintf("%s/bor.ipc", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := dialRPC(c.Endpoint)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Unable to attach to remote bor: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := console.Config{
|
||||||
|
DataDir: path,
|
||||||
|
DocRoot: c.JSpathFlag,
|
||||||
|
Client: client,
|
||||||
|
Preload: c.makeConsolePreloads(),
|
||||||
|
}
|
||||||
|
|
||||||
|
console, err := console.New(config)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to start the JavaScript console: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := console.Stop(false); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if c.ExecCMD != "" {
|
||||||
|
console.Evaluate(c.ExecCMD)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise print the welcome screen and enter interactive mode
|
||||||
|
console.Welcome()
|
||||||
|
console.Interactive()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialRPC returns a RPC client which connects to the given endpoint.
|
||||||
|
// The check for empty endpoint implements the defaulting logic
|
||||||
|
// for "geth attach" with no argument.
|
||||||
|
func dialRPC(endpoint string) (*rpc.Client, error) {
|
||||||
|
if endpoint == "" {
|
||||||
|
endpoint = node.DefaultIPCEndpoint("bor")
|
||||||
|
} else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") {
|
||||||
|
// Backwards compatibility with geth < 1.5 which required
|
||||||
|
// these prefixes.
|
||||||
|
endpoint = endpoint[4:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpc.Dial(endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeConsolePreloads retrieves the absolute paths for the console JavaScript
|
||||||
|
// scripts to preload before starting.
|
||||||
|
func (c *AttachCommand) makeConsolePreloads() []string {
|
||||||
|
// Skip preloading if there's nothing to preload
|
||||||
|
if c.PreloadJSFlag == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Otherwise resolve absolute paths and return them
|
||||||
|
splitFlags := strings.Split(c.PreloadJSFlag, ",")
|
||||||
|
preloads := make([]string, 0, len(splitFlags))
|
||||||
|
|
||||||
|
for _, file := range splitFlags {
|
||||||
|
preloads = append(preloads, strings.TrimSpace(file))
|
||||||
|
}
|
||||||
|
|
||||||
|
return preloads
|
||||||
|
}
|
||||||
230
internal/cli/bootnode.go
Normal file
230
internal/cli/bootnode.go
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BootnodeCommand struct {
|
||||||
|
UI cli.Ui
|
||||||
|
|
||||||
|
listenAddr string
|
||||||
|
v5 bool
|
||||||
|
logLevel string
|
||||||
|
nat string
|
||||||
|
nodeKey string
|
||||||
|
saveKey string
|
||||||
|
dryRun bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help implements the cli.Command interface
|
||||||
|
func (b *BootnodeCommand) Help() string {
|
||||||
|
return `Usage: bor bootnode`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (c *BootnodeCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Bootnode",
|
||||||
|
c.Flags().MarkDown(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BootnodeCommand) Flags() *flagset.Flagset {
|
||||||
|
flags := flagset.NewFlagSet("bootnode")
|
||||||
|
|
||||||
|
flags.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "listen-addr",
|
||||||
|
Default: "0.0.0.0:30303",
|
||||||
|
Usage: "listening address of bootnode (<ip>:<port>)",
|
||||||
|
Value: &b.listenAddr,
|
||||||
|
})
|
||||||
|
flags.BoolFlag(&flagset.BoolFlag{
|
||||||
|
Name: "v5",
|
||||||
|
Default: false,
|
||||||
|
Usage: "Enable UDP v5",
|
||||||
|
Value: &b.v5,
|
||||||
|
})
|
||||||
|
flags.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "log-level",
|
||||||
|
Default: "info",
|
||||||
|
Usage: "Log level (trace|debug|info|warn|error|crit)",
|
||||||
|
Value: &b.logLevel,
|
||||||
|
})
|
||||||
|
flags.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "nat",
|
||||||
|
Default: "none",
|
||||||
|
Usage: "port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
|
||||||
|
Value: &b.nat,
|
||||||
|
})
|
||||||
|
flags.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "node-key",
|
||||||
|
Default: "",
|
||||||
|
Usage: "file or hex node key",
|
||||||
|
Value: &b.nodeKey,
|
||||||
|
})
|
||||||
|
flags.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "save-key",
|
||||||
|
Default: "",
|
||||||
|
Usage: "path to save the ecdsa private key",
|
||||||
|
Value: &b.saveKey,
|
||||||
|
})
|
||||||
|
flags.BoolFlag(&flagset.BoolFlag{
|
||||||
|
Name: "dry-run",
|
||||||
|
Default: false,
|
||||||
|
Usage: "validates parameters and prints bootnode configurations, but does not start bootnode",
|
||||||
|
Value: &b.dryRun,
|
||||||
|
})
|
||||||
|
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis implements the cli.Command interface
|
||||||
|
func (b *BootnodeCommand) Synopsis() string {
|
||||||
|
return "Start a bootnode"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run implements the cli.Command interface
|
||||||
|
// nolint: gocognit
|
||||||
|
func (b *BootnodeCommand) Run(args []string) int {
|
||||||
|
flags := b.Flags()
|
||||||
|
if err := flags.Parse(args); err != nil {
|
||||||
|
b.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
||||||
|
|
||||||
|
lvl, err := log.LvlFromString(strings.ToLower(b.logLevel))
|
||||||
|
if err == nil {
|
||||||
|
glogger.Verbosity(lvl)
|
||||||
|
} else {
|
||||||
|
glogger.Verbosity(log.LvlInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Root().SetHandler(glogger)
|
||||||
|
|
||||||
|
natm, err := nat.Parse(b.nat)
|
||||||
|
if err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("failed to parse nat: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a one time key
|
||||||
|
var nodeKey *ecdsa.PrivateKey
|
||||||
|
// nolint: nestif
|
||||||
|
if b.nodeKey != "" {
|
||||||
|
// try to read the key either from file or command line
|
||||||
|
if _, err := os.Stat(b.nodeKey); errors.Is(err, os.ErrNotExist) {
|
||||||
|
if nodeKey, err = crypto.HexToECDSA(b.nodeKey); err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("failed to parse hex address: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if nodeKey, err = crypto.LoadECDSA(b.nodeKey); err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("failed to load node key: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// generate a new temporal key
|
||||||
|
if nodeKey, err = crypto.GenerateKey(); err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("could not generate key: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if b.saveKey != "" {
|
||||||
|
path := b.saveKey
|
||||||
|
|
||||||
|
// save the private key
|
||||||
|
if err = crypto.SaveECDSA(filepath.Join(path, "priv.key"), nodeKey); err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("failed to write node priv key: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
// save the public key
|
||||||
|
pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := net.ResolveUDPAddr("udp", b.listenAddr)
|
||||||
|
if err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("could not resolve udp addr '%s': %v", b.listenAddr, err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.ListenUDP("udp", addr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
b.UI.Error(fmt.Sprintf("failed to listen udp addr '%s': %v", b.listenAddr, err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
realaddr := conn.LocalAddr().(*net.UDPAddr)
|
||||||
|
if natm != nil {
|
||||||
|
if !realaddr.IP.IsLoopback() {
|
||||||
|
go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ext, err := natm.ExternalIP(); err == nil {
|
||||||
|
// nolint: govet
|
||||||
|
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n := enode.NewV4(&nodeKey.PublicKey, addr.IP, addr.Port, addr.Port)
|
||||||
|
b.UI.Info(n.String())
|
||||||
|
|
||||||
|
if b.dryRun {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
db, _ := enode.OpenDB("")
|
||||||
|
ln := enode.NewLocalNode(db, nodeKey)
|
||||||
|
cfg := discover.Config{
|
||||||
|
PrivateKey: nodeKey,
|
||||||
|
Log: log.Root(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.v5 {
|
||||||
|
if _, err := discover.ListenV5(conn, ln, cfg); err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := discover.ListenUDP(conn, ln, cfg); err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signalCh := make(chan os.Signal, 4)
|
||||||
|
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
|
||||||
|
|
||||||
|
sig := <-signalCh
|
||||||
|
|
||||||
|
b.UI.Output(fmt.Sprintf("Caught signal: %v", sig))
|
||||||
|
b.UI.Output("Gracefully shutting down agent...")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
188
internal/cli/bor_fingerprint.go
Normal file
188
internal/cli/bor_fingerprint.go
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/host"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VersionCommand is the command to show the version of the agent
|
||||||
|
type FingerprintCommand struct {
|
||||||
|
UI cli.Ui
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (c *FingerprintCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Fingerprint",
|
||||||
|
"Display the system fingerprint",
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help implements the cli.Command interface
|
||||||
|
func (c *FingerprintCommand) Help() string {
|
||||||
|
return `Usage: bor fingerprint
|
||||||
|
|
||||||
|
Display the system fingerprint`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis implements the cli.Command interface
|
||||||
|
func (c *FingerprintCommand) Synopsis() string {
|
||||||
|
return "Display the system fingerprint"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCoresCount(cp []cpu.InfoStat) int {
|
||||||
|
cores := 0
|
||||||
|
for i := 0; i < len(cp); i++ {
|
||||||
|
cores += int(cp[i].Cores)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cores
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemoryDetails struct {
|
||||||
|
TotalMem float64 `json:"totalMem"`
|
||||||
|
FreeMem float64 `json:"freeMem"`
|
||||||
|
UsedMem float64 `json:"usedMem"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiskDetails struct {
|
||||||
|
TotalDisk float64 `json:"totalDisk"`
|
||||||
|
FreeDisk float64 `json:"freeDisk"`
|
||||||
|
UsedDisk float64 `json:"usedDisk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BorFingerprint struct {
|
||||||
|
CoresCount int `json:"coresCount"`
|
||||||
|
OsName string `json:"osName"`
|
||||||
|
OsVer string `json:"osVer"`
|
||||||
|
DiskDetails *DiskDetails `json:"diskDetails"`
|
||||||
|
MemoryDetails *MemoryDetails `json:"memoryDetails"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatFingerprint(borFingerprint *BorFingerprint) string {
|
||||||
|
base := formatKV([]string{
|
||||||
|
fmt.Sprintf("Bor Version : %s", params.VersionWithMeta),
|
||||||
|
fmt.Sprintf("CPU : %d cores", borFingerprint.CoresCount),
|
||||||
|
fmt.Sprintf("OS : %s %s ", borFingerprint.OsName, borFingerprint.OsVer),
|
||||||
|
fmt.Sprintf("RAM :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.MemoryDetails.TotalMem, borFingerprint.MemoryDetails.FreeMem, borFingerprint.MemoryDetails.UsedMem),
|
||||||
|
fmt.Sprintf("STORAGE :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.DiskDetails.TotalDisk, borFingerprint.DiskDetails.FreeDisk, borFingerprint.DiskDetails.UsedDisk),
|
||||||
|
})
|
||||||
|
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertBytesToGB(bytesValue uint64) float64 {
|
||||||
|
return math.Floor(float64(bytesValue)/(1024*1024*1024)*100) / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if fio exists on the node
|
||||||
|
func (c *FingerprintCommand) checkFio() error {
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", "fio -v")
|
||||||
|
|
||||||
|
_, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
message := "\nFio package not installed. Install Fio for IOPS Benchmarking :\n\nDebianOS : 'sudo apt-get update && sudo apt-get install fio -y'\nAWS AMI/CentOS : 'sudo yum install fio -y'\nOracle LinuxOS : 'sudo dnf install fio -y'\n"
|
||||||
|
c.UI.Output(message)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the IOPS benchmark for the node
|
||||||
|
func (c *FingerprintCommand) benchmark() error {
|
||||||
|
var b []byte
|
||||||
|
|
||||||
|
err := c.checkFio()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Missing Fio is not a fatal error. A message will be logged in console when it is missing in "checkFio()".
|
||||||
|
return nil //nolint:nilerr
|
||||||
|
}
|
||||||
|
|
||||||
|
c.UI.Output("\nRunning a 10 second test...\n")
|
||||||
|
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", "sudo fio --filename=/file --size=2GB --direct=1 --rw=randrw --bs=64k --ioengine=libaio --iodepth=64 --runtime=10 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1 | grep -e 'read:' -e 'write:' | awk '{print $1,$2}' ")
|
||||||
|
|
||||||
|
b, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := string(b)
|
||||||
|
c.UI.Output(out)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run implements the cli.Command interface
|
||||||
|
func (c *FingerprintCommand) Run(args []string) int {
|
||||||
|
v, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := host.Info()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cp, err := cpu.Info()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := disk.Usage("/")
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
diskDetails := &DiskDetails{
|
||||||
|
TotalDisk: convertBytesToGB(d.Total),
|
||||||
|
FreeDisk: convertBytesToGB(d.Free),
|
||||||
|
UsedDisk: convertBytesToGB(d.Used),
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryDetails := &MemoryDetails{
|
||||||
|
TotalMem: convertBytesToGB(v.Total),
|
||||||
|
FreeMem: convertBytesToGB(v.Available),
|
||||||
|
UsedMem: convertBytesToGB(v.Used),
|
||||||
|
}
|
||||||
|
|
||||||
|
borFingerprint := &BorFingerprint{
|
||||||
|
CoresCount: getCoresCount(cp),
|
||||||
|
OsName: h.OS,
|
||||||
|
OsVer: h.Platform + " - " + h.PlatformVersion + " - " + h.KernelArch,
|
||||||
|
DiskDetails: diskDetails,
|
||||||
|
MemoryDetails: memoryDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.UI.Output(formatFingerprint(borFingerprint))
|
||||||
|
|
||||||
|
if borFingerprint.OsName == "linux" {
|
||||||
|
err = c.benchmark()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -9,6 +11,18 @@ type ChainCommand struct {
|
||||||
UI cli.Ui
|
UI cli.Ui
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (c *ChainCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Chain",
|
||||||
|
"The ```chain``` command groups actions to interact with the blockchain in the client:",
|
||||||
|
"- [```chain sethead```](./chain_sethead.md): Set the current chain to a certain block.",
|
||||||
|
"- [```chain watch```](./chain_watch.md): Watch the chainHead, reorg and fork events in real-time.",
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (c *ChainCommand) Help() string {
|
func (c *ChainCommand) Help() string {
|
||||||
return `Usage: bor chain <subcommand>
|
return `Usage: bor chain <subcommand>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
||||||
|
|
@ -16,6 +17,19 @@ type ChainSetHeadCommand struct {
|
||||||
yes bool
|
yes bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (a *ChainSetHeadCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Chain sethead",
|
||||||
|
"The ```chain sethead <number>``` command sets the current chain to a certain block.",
|
||||||
|
"## Arguments",
|
||||||
|
"- ```number```: The block number to roll back.",
|
||||||
|
a.Flags().MarkDown(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (c *ChainSetHeadCommand) Help() string {
|
func (c *ChainSetHeadCommand) Help() string {
|
||||||
return `Usage: bor chain sethead <number> [--yes]
|
return `Usage: bor chain sethead <number> [--yes]
|
||||||
|
|
@ -32,6 +46,7 @@ func (c *ChainSetHeadCommand) Flags() *flagset.Flagset {
|
||||||
Default: false,
|
Default: false,
|
||||||
Value: &c.yes,
|
Value: &c.yes,
|
||||||
})
|
})
|
||||||
|
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,6 +90,7 @@ func (c *ChainSetHeadCommand) Run(args []string) int {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if response != "y" {
|
if response != "y" {
|
||||||
c.UI.Output("set head aborted")
|
c.UI.Output("set head aborted")
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -87,5 +103,6 @@ func (c *ChainSetHeadCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output("Done!")
|
c.UI.Output("Done!")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -17,6 +18,16 @@ type ChainWatchCommand struct {
|
||||||
*Meta2
|
*Meta2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDown implements cli.MarkDown interface
|
||||||
|
func (c *ChainWatchCommand) MarkDown() string {
|
||||||
|
items := []string{
|
||||||
|
"# Chain watch",
|
||||||
|
"The ```chain watch``` command is used to view the chainHead, reorg and fork events in real-time.",
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(items, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (c *ChainWatchCommand) Help() string {
|
func (c *ChainWatchCommand) Help() string {
|
||||||
return `Usage: bor chain watch
|
return `Usage: bor chain watch
|
||||||
|
|
@ -60,7 +71,10 @@ func (c *ChainWatchCommand) Run(args []string) int {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-signalCh
|
<-signalCh
|
||||||
sub.CloseSend()
|
|
||||||
|
if err := sub.CloseSend(); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
@ -70,6 +84,7 @@ func (c *ChainWatchCommand) Run(args []string) int {
|
||||||
c.UI.Output(err.Error())
|
c.UI.Output(err.Error())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UI.Output(formatHeadEvent(msg))
|
c.UI.Output(formatHeadEvent(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,5 +100,6 @@ func formatHeadEvent(msg *proto.ChainWatchResponse) string {
|
||||||
} else if msg.Type == core.Chain2HeadReorgEvent {
|
} else if msg.Type == core.Chain2HeadReorgEvent {
|
||||||
out = fmt.Sprintf("Reorg Detected \nAdded : %v \nRemoved : %v", msg.Newchain, msg.Oldchain)
|
out = fmt.Sprintf("Reorg Detected \nAdded : %v \nRemoved : %v", msg.Newchain, msg.Oldchain)
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,43 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server"
|
"github.com/ethereum/go-ethereum/internal/cli/server"
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/ryanuber/columnize"
|
"github.com/ryanuber/columnize"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
emptyPlaceHolder = "<none>"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarkDownCommand interface {
|
||||||
|
MarkDown
|
||||||
|
cli.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
type MarkDownCommandFactory func() (MarkDownCommand, error)
|
||||||
|
|
||||||
func Run(args []string) int {
|
func Run(args []string) int {
|
||||||
commands := commands()
|
commands := Commands()
|
||||||
|
|
||||||
|
mappedCommands := make(map[string]cli.CommandFactory)
|
||||||
|
|
||||||
|
for k, v := range commands {
|
||||||
|
// Declare a new v to limit the scope of v to inside the block, so the anonymous function below
|
||||||
|
// can get the "current" value of v, instead of the value of last v in the loop.
|
||||||
|
// See this post: https://stackoverflow.com/questions/10116507/go-transfer-var-into-anonymous-function for more explanation
|
||||||
|
v := v
|
||||||
|
mappedCommands[k] = func() (cli.Command, error) {
|
||||||
|
cmd, err := v()
|
||||||
|
return cmd.(cli.Command), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cli := &cli.CLI{
|
cli := &cli.CLI{
|
||||||
Name: "bor",
|
Name: "bor",
|
||||||
Args: args,
|
Args: args,
|
||||||
Commands: commands,
|
Commands: mappedCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
exitCode, err := cli.Run()
|
exitCode, err := cli.Run()
|
||||||
|
|
@ -28,10 +53,11 @@ func Run(args []string) int {
|
||||||
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
|
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return exitCode
|
return exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
func commands() map[string]cli.CommandFactory {
|
func Commands() map[string]MarkDownCommandFactory {
|
||||||
ui := &cli.BasicUi{
|
ui := &cli.BasicUi{
|
||||||
Reader: os.Stdin,
|
Reader: os.Stdin,
|
||||||
Writer: os.Stdout,
|
Writer: os.Stdout,
|
||||||
|
|
@ -44,87 +70,115 @@ func commands() map[string]cli.CommandFactory {
|
||||||
meta := &Meta{
|
meta := &Meta{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}
|
}
|
||||||
return map[string]cli.CommandFactory{
|
|
||||||
"server": func() (cli.Command, error) {
|
return map[string]MarkDownCommandFactory{
|
||||||
|
"server": func() (MarkDownCommand, error) {
|
||||||
return &server.Command{
|
return &server.Command{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"version": func() (cli.Command, error) {
|
"version": func() (MarkDownCommand, error) {
|
||||||
return &VersionCommand{
|
return &VersionCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"debug": func() (cli.Command, error) {
|
"debug": func() (MarkDownCommand, error) {
|
||||||
return &DebugCommand{
|
return &DebugCommand{
|
||||||
|
UI: ui,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
"debug pprof": func() (MarkDownCommand, error) {
|
||||||
|
return &DebugPprofCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"chain": func() (cli.Command, error) {
|
"debug block": func() (MarkDownCommand, error) {
|
||||||
|
return &DebugBlockCommand{
|
||||||
|
Meta2: meta2,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
"chain": func() (MarkDownCommand, error) {
|
||||||
return &ChainCommand{
|
return &ChainCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"chain watch": func() (cli.Command, error) {
|
"chain watch": func() (MarkDownCommand, error) {
|
||||||
return &ChainWatchCommand{
|
return &ChainWatchCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"chain sethead": func() (cli.Command, error) {
|
"chain sethead": func() (MarkDownCommand, error) {
|
||||||
return &ChainSetHeadCommand{
|
return &ChainSetHeadCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"account": func() (cli.Command, error) {
|
"account": func() (MarkDownCommand, error) {
|
||||||
return &Account{
|
return &Account{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"account new": func() (cli.Command, error) {
|
"account new": func() (MarkDownCommand, error) {
|
||||||
return &AccountNewCommand{
|
return &AccountNewCommand{
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"account import": func() (cli.Command, error) {
|
"account import": func() (MarkDownCommand, error) {
|
||||||
return &AccountImportCommand{
|
return &AccountImportCommand{
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"account list": func() (cli.Command, error) {
|
"account list": func() (MarkDownCommand, error) {
|
||||||
return &AccountListCommand{
|
return &AccountListCommand{
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"peers": func() (cli.Command, error) {
|
"peers": func() (MarkDownCommand, error) {
|
||||||
return &PeersCommand{
|
return &PeersCommand{
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"peers add": func() (cli.Command, error) {
|
"peers add": func() (MarkDownCommand, error) {
|
||||||
return &PeersAddCommand{
|
return &PeersAddCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"peers remove": func() (cli.Command, error) {
|
"peers remove": func() (MarkDownCommand, error) {
|
||||||
return &PeersRemoveCommand{
|
return &PeersRemoveCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"peers list": func() (cli.Command, error) {
|
"peers list": func() (MarkDownCommand, error) {
|
||||||
return &PeersListCommand{
|
return &PeersListCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"peers status": func() (cli.Command, error) {
|
"peers status": func() (MarkDownCommand, error) {
|
||||||
return &PeersStatusCommand{
|
return &PeersStatusCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
"status": func() (cli.Command, error) {
|
"status": func() (MarkDownCommand, error) {
|
||||||
return &StatusCommand{
|
return &StatusCommand{
|
||||||
Meta2: meta2,
|
Meta2: meta2,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
|
"fingerprint": func() (MarkDownCommand, error) {
|
||||||
|
return &FingerprintCommand{
|
||||||
|
UI: ui,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
"attach": func() (MarkDownCommand, error) {
|
||||||
|
return &AttachCommand{
|
||||||
|
UI: ui,
|
||||||
|
Meta: meta,
|
||||||
|
Meta2: meta2,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
"bootnode": func() (MarkDownCommand, error) {
|
||||||
|
return &BootnodeCommand{
|
||||||
|
UI: ui,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,6 +197,7 @@ func (m *Meta2) NewFlagSet(n string) *flagset.Flagset {
|
||||||
Usage: "Address of the grpc endpoint",
|
Usage: "Address of the grpc endpoint",
|
||||||
Default: "127.0.0.1:3131",
|
Default: "127.0.0.1:3131",
|
||||||
})
|
})
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,6 +206,7 @@ func (m *Meta2) Conn() (*grpc.ClientConn, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to connect to server: %v", err)
|
return nil, fmt.Errorf("failed to connect to server: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,6 +215,7 @@ func (m *Meta2) BorConn() (proto.BorClient, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return proto.NewBorClient(conn), nil
|
return proto.NewBorClient(conn), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,18 +263,21 @@ func (m *Meta) GetKeystore() (*keystore.KeyStore, error) {
|
||||||
scryptP := keystore.StandardScryptP
|
scryptP := keystore.StandardScryptP
|
||||||
|
|
||||||
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
|
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
|
||||||
|
|
||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatList(in []string) string {
|
func formatList(in []string) string {
|
||||||
columnConf := columnize.DefaultConfig()
|
columnConf := columnize.DefaultConfig()
|
||||||
columnConf.Empty = "<none>"
|
columnConf.Empty = emptyPlaceHolder
|
||||||
|
|
||||||
return columnize.Format(in, columnConf)
|
return columnize.Format(in, columnConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatKV(in []string) string {
|
func formatKV(in []string) string {
|
||||||
columnConf := columnize.DefaultConfig()
|
columnConf := columnize.DefaultConfig()
|
||||||
columnConf.Empty = "<none>"
|
columnConf.Empty = emptyPlaceHolder
|
||||||
columnConf.Glue = " = "
|
columnConf.Glue = " = "
|
||||||
|
|
||||||
return columnize.Format(in, columnConf)
|
return columnize.Format(in, columnConf)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue