diff --git a/.github/matic-cli-config.yml b/.github/matic-cli-config.yml new file mode 100644 index 0000000000..f643f4b192 --- /dev/null +++ b/.github/matic-cli-config.yml @@ -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" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 727d3a2e22..336b2fea56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,28 +1,183 @@ 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: - build: - runs-on: ubuntu-latest + tests: + 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: - - uses: actions/checkout@v2 - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.17 - - name: "Build binaries" - run: make all - - name: "Run tests" - run: make test - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 - with: - file: ./cover.out - - 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 + - uses: actions/checkout@v3 + - run: | + 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: + go-version: 1.18.x + + - 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 + + - name: Lint + if: runner.os == 'Linux' + run: make lint + + - name: Test + run: make test + + #- name: Data race tests + # run: make test-race + + - name: test-integration + run: make test-integration + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + file: ./cover.out + + # # 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: | + cd bor + 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: + 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 diff --git a/.github/workflows/dockerimage.yml b/.github/workflows/dockerimage.yml deleted file mode 100644 index a8dc11949f..0000000000 --- a/.github/workflows/dockerimage.yml +++ /dev/null @@ -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!" diff --git a/.gitignore b/.gitignore index ad4242c519..50328c8121 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,8 @@ */**/*dapps* build/_vendor/pkg +cover.out + #* .#* *# diff --git a/.golangci.yml b/.golangci.yml index 4950b98c21..89a9e328b8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,7 @@ # This file configures github.com/golangci/golangci-lint. run: + go: '1.18' timeout: 20m tests: true # default is true. Enables skipping of directories: @@ -8,28 +9,139 @@ run: skip-dirs-use-default: true skip-files: - core/genesis_alloc.go + - gen_.*.go + - .*_gen.go linters: - disable-all: true enable: - - deadcode - goconst - goimports - - gosimple - - govet - - ineffassign - misspell - # - staticcheck - unconvert - # - unused - - varcheck + - bodyclose + - 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: gofmt: simplify: true + auto-fix: false + goconst: 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: exclude-rules: @@ -48,3 +160,28 @@ issues: - path: cmd/faucet/ linters: - 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 \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml index 331d8de6b5..d09cc43206 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -7,7 +7,7 @@ release: builds: - id: darwin-amd64 - main: ./cmd/geth + main: ./cmd/cli binary: bor goos: - darwin @@ -22,7 +22,7 @@ builds: -s -w - id: darwin-arm64 - main: ./cmd/geth + main: ./cmd/cli binary: bor goos: - darwin @@ -37,7 +37,7 @@ builds: -s -w - id: linux-amd64 - main: ./cmd/geth + main: ./cmd/cli binary: bor goos: - linux @@ -53,7 +53,7 @@ builds: -s -w -extldflags "-static" - id: linux-arm64 - main: ./cmd/geth + main: ./cmd/cli binary: bor goos: - linux diff --git a/Dockerfile b/Dockerfile index 8af791ab3f..7a2770ce9a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,9 @@ RUN apt-get update -y && apt-get upgrade -y \ WORKDIR ${BOR_DIR} COPY . . -RUN make bor-all +RUN make bor + +RUN cp build/bin/bor /usr/local/bin/ ENV SHELL /bin/bash EXPOSE 8545 8546 8547 30303 30303/udp diff --git a/Dockerfile.classic b/Dockerfile.classic deleted file mode 100644 index 2fa38f08f9..0000000000 --- a/Dockerfile.classic +++ /dev/null @@ -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 diff --git a/Makefile b/Makefile index b283928b81..46ecdec886 100644 --- a/Makefile +++ b/Makefile @@ -2,27 +2,35 @@ # with Go source code. If you know what GOPATH is then you probably # 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 +GOBIN = $(CURDIR)/build/bin GORUN = env GO111MODULE=on go run GOPATH = $(shell go env GOPATH) -bor: - $(GORUN) build/ci.go install ./cmd/geth - mkdir -p $(GOPATH)/bin/ - cp $(GOBIN)/geth $(GOBIN)/bor - cp $(GOBIN)/* $(GOPATH)/bin/ +GIT_COMMIT ?= $(shell git rev-list -1 HEAD) +GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) +GIT_TAG ?= $(shell git describe --tags `git rev-list --tags="v*" --max-count=1`) -bor-all: - $(GORUN) build/ci.go install +PACKAGE = github.com/ethereum/go-ethereum +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/ - cp $(GOBIN)/geth $(GOBIN)/bor - cp $(GOBIN)/* $(GOPATH)/bin/ + go build -o $(GOBIN)/bor ./cmd/cli/main.go protoc: - protoc --go_out=. --go-grpc_out=. ./command/server/proto/*.proto + protoc --go_out=. --go-grpc_out=. ./internal/cli/server/proto/*.proto geth: $(GORUN) build/ci.go install ./cmd/geth @@ -45,11 +53,29 @@ ios: @echo "Import \"$(GOBIN)/Geth.framework\" to use the library." test: - # Skip mobile and cmd tests since they are being deprecated - go test -v $$(go list ./... | grep -v go-ethereum/cmd/) -cover -coverprofile=cover.out + $(GOTEST) --timeout 5m -shuffle=on -cover -coverprofile=cover.out $(TESTALL) -lint: ## Run linters. - $(GORUN) build/ci.go lint +test-race: + $(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: 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'. devtools: - env GOBIN= go install golang.org/x/tools/cmd/stringer@latest - env GOBIN= go install github.com/kevinburke/go-bindata/go-bindata@latest - env GOBIN= go install github.com/fjl/gencodec@latest - env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest - env GOBIN= go install ./cmd/abigen + # Notice! If you adding new binary - add it also to tests/deps/fake.go file + $(GOBUILD) -o $(GOBIN)/stringer github.com/golang.org/x/tools/cmd/stringer + $(GOBUILD) -o $(GOBIN)/go-bindata github.com/kevinburke/go-bindata/go-bindata + $(GOBUILD) -o $(GOBIN)/codecgen github.com/ugorji/go/codec/codecgen + $(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 ./core/types PATH=$(GOBIN):$(PATH) go generate ./consensus/bor @@ -71,7 +99,6 @@ devtools: @type "protoc" 2> /dev/null || echo 'Please install protoc' # Cross Compilation Targets (xgo) - geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios @echo "Full cross compilation done:" @ls -ld $(GOBIN)/geth-* diff --git a/README.md b/README.md index 1dacae0219..4e33a551d0 100644 --- a/README.md +++ b/README.md @@ -63,12 +63,6 @@ them using your favourite package manager. Once the dependencies are installed, $ make bor ``` -- or, to build the full suite of utilities: - - ```shell - $ make bor-all - ``` - ### Make awesome changes! 1. Create new branch for your changes @@ -113,12 +107,6 @@ them using your favourite package manager. Once the dependencies are installed,
-Build the beta client: - -```shell -go build -o bor-beta command/*.go -``` - ## License The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 8a0cbe3357..7df1a823ec 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -27,10 +27,13 @@ import ( "testing" "time" + "go.uber.org/goleak" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "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/types" "github.com/ethereum/go-ethereum/crypto" @@ -38,6 +41,8 @@ import ( ) func TestSimulatedBackend(t *testing.T) { + defer goleak.VerifyNone(t, leak.IgnoreList()...) + var gasLimit uint64 = 8000029 key, _ := crypto.GenerateKey() // nolint: gosec auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) diff --git a/builder/files/bor.service b/builder/files/bor.service index fa84320a6c..28fda79814 100644 --- a/builder/files/bor.service +++ b/builder/files/bor.service @@ -6,21 +6,25 @@ [Service] Restart=on-failure RestartSec=5s - ExecStart=/usr/local/bin/bor \ - --bor-mumbai \ - # --bor-mainnet \ - --datadir /var/lib/bor/data \ - --bootnodes "enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303,enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303" + ExecStart=/usr/local/bin/bor server \ + -chain=mumbai \ + # -chain=mainnet \ + -datadir /var/lib/bor/data \ + -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 - # Uncomment and configure the following lines in case you run a validator - # --keystore /var/lib/bor/keystore \ - # --unlock [VALIDATOR ADDRESS] \ - # --password /var/lib/bor/password.txt \ - # --allow-insecure-unlock \ - # --nodiscover --maxpeers 1 \ - # --mine + # Uncomment and configure the following lines in case you run a validator. Don't forget to add backslash (\) + # to previous command line. + # -keystore /var/lib/bor/keystore \ + # -unlock [VALIDATOR ADDRESS] \ + # -password /var/lib/bor/password.txt \ + # -allow-insecure-unlock \ + # -nodiscover -maxpeers 1 \ + # -miner.etherbase [VALIDATOR ADDRESS] \ + # -mine Type=simple - User=root + User=ubuntu KillSignal=SIGINT TimeoutStopSec=120 diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go new file mode 100644 index 0000000000..07efc04556 --- /dev/null +++ b/cmd/clidoc/main.go @@ -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) + } +} diff --git a/common/debug/debug.go b/common/debug/debug.go new file mode 100644 index 0000000000..6a677e495d --- /dev/null +++ b/common/debug/debug.go @@ -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 +} diff --git a/common/leak/ignore_list.go b/common/leak/ignore_list.go new file mode 100644 index 0000000000..56134dcabc --- /dev/null +++ b/common/leak/ignore_list.go @@ -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"), + } +} diff --git a/common/set/slice.go b/common/set/slice.go new file mode 100644 index 0000000000..36f11e67fe --- /dev/null +++ b/common/set/slice.go @@ -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 +} diff --git a/consensus/bor/abi/interface.go b/consensus/bor/abi/interface.go new file mode 100644 index 0000000000..bb05bf0b23 --- /dev/null +++ b/consensus/bor/abi/interface.go @@ -0,0 +1,6 @@ +package abi + +type ABI interface { + Pack(name string, args ...interface{}) ([]byte, error) + UnpackIntoInterface(v interface{}, name string, data []byte) error +} diff --git a/consensus/bor/api.go b/consensus/bor/api.go index 12841290af..26d1efdaf1 100644 --- a/consensus/bor/api.go +++ b/consensus/bor/api.go @@ -4,14 +4,17 @@ import ( "encoding/hex" "math" "math/big" + "sort" "strconv" "sync" "github.com/ethereum/go-ethereum/common" "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/crypto" "github.com/ethereum/go-ethereum/rpc" + lru "github.com/hashicorp/golang-lru" "github.com/xsleonard/go-merkle" "golang.org/x/crypto/sha3" @@ -43,9 +46,88 @@ func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { if header == nil { return nil, errUnknownBlock } + 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. func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) { // 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 { return nil, errUnknownBlock } + author, err := api.bor.Author(header) + return &author, err } @@ -69,6 +153,7 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { if header == nil { return nil, errUnknownBlock } + 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 { return nil, errUnknownBlock } + snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) + if err != nil { return nil, err } + return snap.signers(), nil } @@ -98,10 +186,13 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { if header == nil { return nil, errUnknownBlock } + snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) + if err != nil { return nil, err } + return snap.signers(), nil } @@ -111,15 +202,17 @@ func (api *API) GetCurrentProposer() (common.Address, error) { if err != nil { return common.Address{}, err } + return snap.ValidatorSet.GetProposer().Address, nil } // GetCurrentValidators gets the current validators -func (api *API) GetCurrentValidators() ([]*Validator, error) { +func (api *API) GetCurrentValidators() ([]*valset.Validator, error) { snap, err := api.GetSnapshot(nil) if err != nil { - return make([]*Validator, 0), err + return make([]*valset.Validator, 0), err } + 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 { return "", err } + key := getRootHashKey(start, end) + if root, known := api.rootHashCache.Get(key); known { return root.(string), nil } - length := uint64(end - start + 1) + + length := end - start + 1 + if length > MaxCheckpointLength { return "", &MaxCheckpointLengthExceededError{start, end} } + currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64() + 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) wg := new(sync.WaitGroup) concurrent := make(chan bool, 20) + for i := start; i <= end; i++ { wg.Add(1) concurrent <- true + go func(number uint64) { - blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number)) + blockHeaders[number-start] = api.chain.GetHeaderByNumber(number) + <-concurrent wg.Done() }(i) @@ -156,6 +259,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) { close(concurrent) headers := make([][32]byte, nextPowerOfTwo(length)) + for i := 0; i < len(blockHeaders); i++ { blockHeader := blockHeaders[i] header := crypto.Keccak256(appendBytes32( @@ -166,6 +270,7 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) { )) var arr [32]byte + copy(arr[:], header) 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 { return "", err } + root := hex.EncodeToString(tree.Root().Hash) api.rootHashCache.Add(key, root) + return root, nil } @@ -184,6 +291,7 @@ func (api *API) initializeRootHashCache() error { if api.rootHashCache == nil { api.rootHashCache, err = lru.NewARC(10) } + return err } diff --git a/consensus/bor/api/caller.go b/consensus/bor/api/caller.go new file mode 100644 index 0000000000..d5fe259c97 --- /dev/null +++ b/consensus/bor/api/caller.go @@ -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) +} diff --git a/consensus/bor/api/caller_mock.go b/consensus/bor/api/caller_mock.go new file mode 100644 index 0000000000..940c99d178 --- /dev/null +++ b/consensus/bor/api/caller_mock.go @@ -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) +} diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 2eb2645f18..826a45dae2 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -2,38 +2,34 @@ package bor import ( "bytes" - "context" "encoding/hex" "encoding/json" "errors" "fmt" "io" - "math" "math/big" "sort" "strconv" - "strings" "sync" "time" lru "github.com/hashicorp/golang-lru" "golang.org/x/crypto/sha3" - ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/bor/api" + "github.com/ethereum/go-ethereum/consensus/bor/clerk" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" + "github.com/ethereum/go-ethereum/consensus/bor/statefull" + "github.com/ethereum/go-ethereum/consensus/bor/valset" "github.com/ethereum/go-ethereum/consensus/misc" "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/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" - "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" @@ -56,11 +52,7 @@ var ( uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW. - diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures - diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures - validatorHeaderBytesLength = common.AddressLength + 20 // address + power - systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") ) // Various error messages to mark blocks invalid. These should be private to @@ -72,18 +64,6 @@ var ( // that is not part of the local blockchain. errUnknownBlock = errors.New("unknown block") - // errInvalidCheckpointBeneficiary is returned if a checkpoint/epoch transition - // block has a beneficiary set to non-zeroes. - errInvalidCheckpointBeneficiary = errors.New("beneficiary in checkpoint block non-zero") - - // errInvalidVote is returned if a nonce value is something else that the two - // allowed constants of 0x00..0 or 0xff..f. - errInvalidVote = errors.New("vote nonce not 0x00..0 or 0xff..f") - - // errInvalidCheckpointVote is returned if a checkpoint/epoch transition block - // has a vote nonce set to non-zeroes. - errInvalidCheckpointVote = errors.New("vote nonce in checkpoint block non-zero") - // errMissingVanity is returned if a block's extra-data section is shorter than // 32 bytes, which is required to store the signer vanity. errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing") @@ -116,9 +96,6 @@ var ( // errOutOfRangeChain is returned if an authorization list is attempted to // be modified via out-of-range or non-contiguous headers. errOutOfRangeChain = errors.New("out of range or non-contiguous chain") - - // errShutdownDetected is returned if a shutdown was detected - errShutdownDetected = errors.New("shutdown detected") ) // SignerFn is a signer callback function to request a header to be signed by a @@ -136,6 +113,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache, c *params.BorConfig if len(header.Extra) < extraSeal { return common.Address{}, errMissingSignature } + signature := header.Extra[len(header.Extra)-extraSeal:] // Recover the public key and the Ethereum address @@ -143,10 +121,13 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache, c *params.BorConfig if err != nil { return common.Address{}, err } + var signer common.Address + copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) sigcache.Add(hash, signer) + return signer, nil } @@ -155,6 +136,7 @@ func SealHash(header *types.Header, c *params.BorConfig) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() encodeSigHeader(hasher, header, c) hasher.Sum(hash[:0]) + return hash } @@ -176,11 +158,13 @@ func encodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) { header.MixDigest, header.Nonce, } + if c.IsJaipur(header.Number.Uint64()) { if header.BaseFee != nil { enc = append(enc, header.BaseFee) } } + if err := rlp.Encode(w, enc); err != nil { panic("can't encode: " + err.Error()) } @@ -194,9 +178,11 @@ func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint6 if number%c.Sprint == 0 { delay = c.ProducerDelay } + if succession > 0 { delay += uint64(succession) * c.CalculateBackupMultiplier(number) } + return delay } @@ -210,6 +196,7 @@ func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint6 func BorRLP(header *types.Header, c *params.BorConfig) []byte { b := new(bytes.Buffer) encodeSigHeader(b, header, c) + return b.Bytes() } @@ -226,25 +213,25 @@ type Bor struct { signFn SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields - ethAPI *ethapi.PublicBlockChainAPI - GenesisContractsClient *GenesisContractsClient - validatorSetABI abi.ABI - stateReceiverABI abi.ABI + ethAPI api.Caller + spanner Spanner + GenesisContractsClient GenesisContract HeimdallClient IHeimdallClient - WithoutHeimdall bool - scope event.SubscriptionScope // The fields below are for testing only fakeDiff bool // Skip difficulty verifications + + closeOnce sync.Once } // New creates a Matic Bor consensus engine. func New( chainConfig *params.ChainConfig, db ethdb.Database, - ethAPI *ethapi.PublicBlockChainAPI, - heimdallURL string, - withoutHeimdall bool, + ethAPI api.Caller, + spanner Spanner, + heimdallClient IHeimdallClient, + genesisContracts GenesisContract, ) *Bor { // get bor config borConfig := chainConfig.Bor @@ -253,14 +240,10 @@ func New( if borConfig != nil && borConfig.Sprint == 0 { borConfig.Sprint = defaultSprintLength } - // Allocate the snapshot caches and create the engine recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySignatures) - vABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) - sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI)) - heimdallClient, _ := NewHeimdallClient(heimdallURL) - genesisContractsClient := NewGenesisContractsClient(chainConfig, borConfig.ValidatorContract, borConfig.StateReceiverContract, ethAPI) + c := &Bor{ chainConfig: chainConfig, config: borConfig, @@ -268,11 +251,9 @@ func New( ethAPI: ethAPI, recents: recents, signatures: signatures, - validatorSetABI: vABI, - stateReceiverABI: sABI, - GenesisContractsClient: genesisContractsClient, + spanner: spanner, + GenesisContractsClient: genesisContracts, HeimdallClient: heimdallClient, - WithoutHeimdall: withoutHeimdall, } // make sure we can decode all the GenesisAlloc in the BorConfig. @@ -314,6 +295,7 @@ func (c *Bor) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types. } } }() + return abort, results } @@ -325,6 +307,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head if header.Number == nil { return errUnknownBlock } + number := header.Number.Uint64() // Don't waste time checking blocks from the future @@ -337,39 +320,47 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head } // check extr adata - isSprintEnd := (number+1)%c.config.Sprint == 0 + isSprintEnd := IsSprintStart(number+1, c.config.Sprint) // Ensure that the extra-data contains a signer list on checkpoint, but none otherwise signersBytes := len(header.Extra) - extraVanity - extraSeal if !isSprintEnd && signersBytes != 0 { return errExtraValidators } + if isSprintEnd && signersBytes%validatorHeaderBytesLength != 0 { return errInvalidSpanValidators } + // Ensure that the mix digest is zero as we don't have fork protection currently if header.MixDigest != (common.Hash{}) { return errInvalidMixDigest } + // Ensure that the block doesn't contain any uncles which are meaningless in PoA if header.UncleHash != uncleHash { return errInvalidUncleHash } + // Ensure that the block's difficulty is meaningful (may not be correct at this point) if number > 0 { if header.Difficulty == nil { return errInvalidDifficulty } } + // Verify that the gas limit is <= 2^63-1 - cap := uint64(0x7fffffffffffffff) - if header.GasLimit > cap { - return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) + gasCap := uint64(0x7fffffffffffffff) + + if header.GasLimit > gasCap { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, gasCap) } + // If all checks passed, validate any special fields for hard forks if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { return err } + // All basic checks passed, verify cascading fields return c.verifyCascadingFields(chain, header, parents) } @@ -380,9 +371,11 @@ func validateHeaderExtraField(extraBytes []byte) error { if len(extraBytes) < extraVanity { return errMissingVanity } + if len(extraBytes) < extraVanity+extraSeal { return errMissingSignature } + return nil } @@ -393,12 +386,14 @@ func validateHeaderExtraField(extraBytes []byte) error { func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error { // The genesis block is the always valid dead-end number := header.Number.Uint64() + if number == 0 { return nil } // Ensure that the block's timestamp isn't too close to it's parent var parent *types.Header + if len(parents) > 0 { parent = parents[len(parents)-1] } else { @@ -413,11 +408,13 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t if header.GasUsed > header.GasLimit { return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) } + if !chain.Config().IsLondon(header.Number) { // Verify BaseFee not present before EIP-1559 fork. if header.BaseFee != nil { return fmt.Errorf("invalid baseFee before fork: have %d, want ", header.BaseFee) } + if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { return err } @@ -437,13 +434,14 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t } // verify the validator list in the last sprint block - if isSprintStart(number, c.config.Sprint) { + if IsSprintStart(number, c.config.Sprint) { parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal] validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength) currentValidators := snap.ValidatorSet.Copy().Validators // sort validator by address - sort.Sort(ValidatorsByAddress(currentValidators)) + sort.Sort(valset.ValidatorsByAddress(currentValidators)) + for i, validator := range currentValidators { copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes()) } @@ -458,25 +456,29 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t } // snapshot retrieves the authorization snapshot at a given point in time. +// nolint: gocognit func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) { // Search for a snapshot in memory or on disk for checkpoints - var ( - headers []*types.Header - snap *Snapshot - ) + var snap *Snapshot + headers := make([]*types.Header, 0, 16) + + //nolint:govet for snap == nil { // If an in-memory snapshot was found, use that if s, ok := c.recents.Get(hash); ok { snap = s.(*Snapshot) + break } // If an on-disk checkpoint snapshot can be found, use that if number%checkpointInterval == 0 { - if s, err := loadSnapshot(c.config, c.signatures, c.db, hash, c.ethAPI); err == nil { + if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil { log.Trace("Loaded snapshot from disk", "number", number, "hash", hash) + snap = s + break } } @@ -486,6 +488,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co // up more headers than allowed to be reorged (chain reinit from a freezer), // consider the checkpoint trusted and snapshot it. // TODO fix this + // nolint:nestif if number == 0 { checkpoint := chain.GetHeaderByNumber(number) if checkpoint != nil { @@ -493,17 +496,19 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co hash := checkpoint.Hash() // get validators and current span - validators, err := c.GetCurrentValidators(hash, number+1) + validators, err := c.spanner.GetCurrentValidators(hash, number+1) if err != nil { return nil, err } // new snap shot - snap = newSnapshot(c.config, c.signatures, number, hash, validators, c.ethAPI) + snap = newSnapshot(c.config, c.signatures, number, hash, validators) if err := snap.store(c.db); err != nil { return nil, err } + log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash) + break } } @@ -516,6 +521,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co if header.Hash() != hash || header.Number.Uint64() != number { return nil, consensus.ErrUnknownAncestor } + parents = parents[:len(parents)-1] } else { // No explicit parents (or no more left), reach out to the database @@ -524,10 +530,13 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co return nil, consensus.ErrUnknownAncestor } } + headers = append(headers, header) number, hash = number-1, header.ParentHash } + log.Info("Snapshot has been found in", "headers depth", len(headers)) + // check if snapshot is nil if snap == nil { return nil, fmt.Errorf("Unknown error while retrieving snapshot at block number %v", number) @@ -542,6 +551,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co if err != nil { return nil, err } + c.recents.Add(snap.Hash, snap) // If we've generated a new checkpoint snapshot, save to disk @@ -549,8 +559,10 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co if err = snap.store(c.db); err != nil { return nil, err } + log.Trace("Stored snapshot to disk", "number", snap.Number, "hash", snap.Hash) } + return snap, err } @@ -560,6 +572,7 @@ func (c *Bor) VerifyUncles(chain consensus.ChainReader, block *types.Block) erro if len(block.Uncles()) > 0 { return errors.New("uncles not allowed") } + return nil } @@ -590,6 +603,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header if err != nil { return err } + if !snap.ValidatorSet.HasAddress(signer.Bytes()) { // Check the UnauthorizedSignerError.Error() msg to see why we pass number-1 return &UnauthorizedSignerError{number - 1, signer.Bytes()} @@ -643,17 +657,19 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e if len(header.Extra) < extraVanity { header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...) } + header.Extra = header.Extra[:extraVanity] // get validator set if number - if (number+1)%c.config.Sprint == 0 { - newValidators, err := c.GetCurrentValidators(header.ParentHash, number+1) + if IsSprintStart(number+1, c.config.Sprint) { + newValidators, err := c.spanner.GetCurrentValidators(header.ParentHash, number+1) if err != nil { return errors.New("unknown validators") } // sort validator by address - sort.Sort(ValidatorsByAddress(newValidators)) + sort.Sort(valset.ValidatorsByAddress(newValidators)) + for _, validator := range newValidators { header.Extra = append(header.Extra, validator.HeaderBytes()...) } @@ -673,7 +689,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e var succession int // if signer is not empty - if bytes.Compare(c.signer.Bytes(), common.Address{}.Bytes()) != 0 { + if c.signer != (common.Address{}) { succession, err = snap.GetSignerSuccessionNumber(c.signer) if err != nil { return err @@ -684,6 +700,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e if header.Time < uint64(time.Now().Unix()) { header.Time = uint64(time.Now().Unix()) } + return nil } @@ -693,16 +710,18 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header, stateSyncData := []*types.StateSyncData{} var err error + headerNumber := header.Number.Uint64() + if headerNumber%c.config.Sprint == 0 { - cx := chainContext{Chain: chain, Bor: c} + cx := statefull.ChainContext{Chain: chain, Bor: c} // check and commit span if err := c.checkAndCommitSpan(state, header, cx); err != nil { log.Error("Error while committing span", "error", err) return } - if !c.WithoutHeimdall { + if c.HeimdallClient != nil { // commit statees stateSyncData, err = c.CommitStates(state, header, cx) if err != nil { @@ -728,13 +747,16 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header, func decodeGenesisAlloc(i interface{}) (core.GenesisAlloc, error) { var alloc core.GenesisAlloc + b, err := json.Marshal(i) if err != nil { return nil, err } + if err := json.Unmarshal(b, &alloc); err != nil { return nil, err } + return alloc, nil } @@ -745,12 +767,14 @@ func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.State if err != nil { return fmt.Errorf("failed to decode genesis alloc: %v", err) } + for addr, account := range allocs { log.Info("change contract code", "address", addr) state.SetCode(addr, account.Code) } } } + return nil } @@ -762,7 +786,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ headerNumber := header.Number.Uint64() if headerNumber%c.config.Sprint == 0 { - cx := chainContext{Chain: chain, Bor: c} + cx := statefull.ChainContext{Chain: chain, Bor: c} // check and commit span err := c.checkAndCommitSpan(state, header, cx) @@ -771,7 +795,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ return nil, err } - if !c.WithoutHeimdall { + if c.HeimdallClient != nil { // commit states stateSyncData, err = c.CommitStates(state, header, cx) if err != nil { @@ -794,7 +818,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ block := types.NewBlock(header, txs, nil, receipts, new(trie.Trie)) // set state sync - bc := chain.(*core.BlockChain) + bc := chain.(core.BorStateSyncer) bc.SetStateSync(stateSyncData) // return the final block for sealing @@ -852,14 +876,14 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result wiggle := time.Duration(successionNumber) * time.Duration(c.config.CalculateBackupMultiplier(number)) * time.Second // Sign all the things! - sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header, c.config)) + err = Sign(signFn, signer, header, c.config) if err != nil { return err } - copy(header.Extra[len(header.Extra)-extraSeal:], sighash) // Wait until sealing is terminated or delay timeout. - log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay)) + log.Info("Waiting for slot to sign and propagate", "number", number, "hash", header.Hash, "delay-in-sec", uint(delay), "delay", common.PrettyDuration(delay)) + go func() { select { case <-stop: @@ -870,10 +894,13 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result log.Info( "Sealing out-of-turn", "number", number, + "hash", header.Hash, + "wiggle-in-sec", uint(wiggle), "wiggle", common.PrettyDuration(wiggle), "in-turn-signer", snap.ValidatorSet.GetProposer().Address.Hex(), ) } + log.Info( "Sealing successful", "number", number, @@ -887,6 +914,18 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header, c.config)) } }() + + return nil +} + +func Sign(signFn SignerFn, signer common.Address, header *types.Header, c *params.BorConfig) error { + sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header, c)) + if err != nil { + return err + } + + copy(header.Extra[len(header.Extra)-extraSeal:], sighash) + return nil } @@ -898,6 +937,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, par if err != nil { return nil } + return new(big.Int).SetUint64(snap.Difficulty(c.signer)) } @@ -919,112 +959,13 @@ func (c *Bor) APIs(chain consensus.ChainHeaderReader) []rpc.API { // Close implements consensus.Engine. It's a noop for bor as there are no background threads. func (c *Bor) Close() error { - c.HeimdallClient.Close() - return nil -} - -// GetCurrentSpan get current span from contract -func (c *Bor) GetCurrentSpan(headerHash common.Hash) (*Span, error) { - // block - blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false) - - // method - method := "getCurrentSpan" - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - data, err := c.validatorSetABI.Pack(method) - if err != nil { - log.Error("Unable to pack tx for getCurrentSpan", "error", err) - return nil, err - } - - msgData := (hexutil.Bytes)(data) - toAddress := common.HexToAddress(c.config.ValidatorContract) - gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := c.ethAPI.Call(ctx, 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.validatorSetABI.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 *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*Validator, error) { - // block - blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false) - - // method - method := "getBorValidators" - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - data, err := c.validatorSetABI.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 := common.HexToAddress(c.config.ValidatorContract) - gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ - Gas: &gas, - To: &toAddress, - Data: &msgData, - }, blockNr, nil) - if err != nil { - panic(err) - // return nil, err - } - - var ( - ret0 = new([]common.Address) - ret1 = new([]*big.Int) - ) - out := &[]interface{}{ - ret0, - ret1, - } - - if err := c.validatorSetABI.UnpackIntoInterface(out, method, result); err != nil { - return nil, err - } - - valz := make([]*Validator, len(*ret0)) - for i, a := range *ret0 { - valz[i] = &Validator{ - Address: a, - VotingPower: (*ret1)[i].Int64(), + c.closeOnce.Do(func() { + if c.HeimdallClient != nil { + c.HeimdallClient.Close() } - } + }) - return valz, nil + return nil } func (c *Bor) checkAndCommitSpan( @@ -1033,18 +974,20 @@ func (c *Bor) checkAndCommitSpan( chain core.ChainContext, ) error { headerNumber := header.Number.Uint64() - span, err := c.GetCurrentSpan(header.ParentHash) + + span, err := c.spanner.GetCurrentSpan(header.ParentHash) if err != nil { return err } + if c.needToCommitSpan(span, headerNumber) { - err := c.fetchAndCommitSpan(span.ID+1, state, header, chain) - return err + return c.FetchAndCommitSpan(span.ID+1, state, header, chain) } + return nil } -func (c *Bor) needToCommitSpan(span *Span, headerNumber uint64) bool { +func (c *Bor) needToCommitSpan(span *span.Span, headerNumber uint64) bool { // if span is nil if span == nil { return false @@ -1063,99 +1006,52 @@ func (c *Bor) needToCommitSpan(span *Span, headerNumber uint64) bool { return false } -func (c *Bor) fetchAndCommitSpan( +func (c *Bor) FetchAndCommitSpan( newSpanID uint64, state *state.StateDB, header *types.Header, chain core.ChainContext, ) error { - var heimdallSpan HeimdallSpan + var heimdallSpan span.HeimdallSpan - if c.WithoutHeimdall { - s, err := c.getNextHeimdallSpanForTest(newSpanID, state, header, chain) + if c.HeimdallClient == nil { + // fixme: move to a new mock or fake and remove c.HeimdallClient completely + s, err := c.getNextHeimdallSpanForTest(newSpanID, header, chain) if err != nil { return err } + heimdallSpan = *s } else { - response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "") + response, err := c.HeimdallClient.Span(newSpanID) if err != nil { return err } - if err := json.Unmarshal(response.Result, &heimdallSpan); err != nil { - return err - } + heimdallSpan = *response } - // check if chain id matches with heimdall span + // check if chain id matches with Heimdall span if heimdallSpan.ChainID != c.chainConfig.ChainID.String() { return fmt.Errorf( - "Chain id proposed span, %s, and bor chain id, %s, doesn't match", + "chain id proposed span, %s, and bor chain id, %s, doesn't match", heimdallSpan.ChainID, c.chainConfig.ChainID, ) } - // get validators bytes - var validators []MinimalVal - for _, val := range heimdallSpan.ValidatorSet.Validators { - validators = append(validators, val.MinimalVal()) - } - validatorBytes, err := rlp.EncodeToBytes(validators) - if err != nil { - return err - } - - // get producers bytes - var producers []MinimalVal - for _, val := range heimdallSpan.SelectedProducers { - producers = append(producers, val.MinimalVal()) - } - producerBytes, err := rlp.EncodeToBytes(producers) - if err != nil { - return err - } - - // method - method := "commitSpan" - log.Info("✅ Committing new span", - "id", heimdallSpan.ID, - "startBlock", heimdallSpan.StartBlock, - "endBlock", heimdallSpan.EndBlock, - "validatorBytes", hex.EncodeToString(validatorBytes), - "producerBytes", hex.EncodeToString(producerBytes), - ) - - // get packed data - data, err := c.validatorSetABI.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 := getSystemMessage(common.HexToAddress(c.config.ValidatorContract), data) - - // apply message - _, err = applyMessage(msg, state, header, c.chainConfig, chain) - return err + return c.spanner.CommitSpan(heimdallSpan, state, header, chain) } // CommitStates commit states func (c *Bor) CommitStates( state *state.StateDB, header *types.Header, - chain chainContext, + chain statefull.ChainContext, ) ([]*types.StateSyncData, error) { stateSyncs := make([]*types.StateSyncData, 0) number := header.Number.Uint64() + _lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1) if err != nil { return nil, err @@ -1163,11 +1059,17 @@ func (c *Bor) CommitStates( to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0) lastStateID := _lastStateID.Uint64() + log.Info( "Fetching state updates from Heimdall", "fromID", lastStateID+1, "to", to.Format(time.RFC3339)) - eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix()) + + eventRecords, err := c.HeimdallClient.StateSyncEvents(lastStateID+1, to.Unix()) + if err != nil { + log.Error("Error occurred when fetching state sync events", "stateID", lastStateID+1, "error", err) + } + if c.config.OverrideStateSyncRecords != nil { if val, ok := c.config.OverrideStateSyncRecords[strconv.FormatUint(number, 10)]; ok { eventRecords = eventRecords[0:val] @@ -1177,12 +1079,14 @@ func (c *Bor) CommitStates( totalGas := 0 /// limit on gas for state sync per block chainID := c.chainConfig.ChainID.String() + for _, eventRecord := range eventRecords { if eventRecord.ID <= lastStateID { continue } + if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil { - log.Error(err.Error()) + log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error()) break } @@ -1192,25 +1096,30 @@ func (c *Bor) CommitStates( Data: hex.EncodeToString(eventRecord.Data), TxHash: eventRecord.TxHash, } + stateSyncs = append(stateSyncs, &stateData) gasUsed, err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain) if err != nil { return nil, err } + totalGas += int(gasUsed) lastStateID++ } + log.Info("StateSyncData", "Gas", totalGas, "Block-number", number, "LastStateID", lastStateID, "TotalRecords", len(eventRecords)) + return stateSyncs, nil } -func validateEventRecord(eventRecord *EventRecordWithTime, number uint64, to time.Time, lastStateID uint64, chainID string) error { +func validateEventRecord(eventRecord *clerk.EventRecordWithTime, number uint64, to time.Time, lastStateID uint64, chainID string) error { // event id should be sequential and event.Time should lie in the range [from, to) if lastStateID+1 != eventRecord.ID || eventRecord.ChainID != chainID || !eventRecord.Time.Before(to) { return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord} } + return nil } @@ -1218,24 +1127,28 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) { c.HeimdallClient = h } +func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { + return c.spanner.GetCurrentValidators(headerHash, blockNumber) +} + // // Private methods // func (c *Bor) getNextHeimdallSpanForTest( newSpanID uint64, - state *state.StateDB, header *types.Header, chain core.ChainContext, -) (*HeimdallSpan, error) { +) (*span.HeimdallSpan, error) { headerNumber := header.Number.Uint64() - span, err := c.GetCurrentSpan(header.ParentHash) + + spanBor, err := c.spanner.GetCurrentSpan(header.ParentHash) if err != nil { return nil, err } // get local chain context object - localContext := chain.(chainContext) + localContext := chain.(statefull.ChainContext) // Retrieve the snapshot needed to verify this header and cache it snap, err := c.snapshot(localContext.Chain, headerNumber-1, header.ParentHash, nil) if err != nil { @@ -1243,20 +1156,22 @@ func (c *Bor) getNextHeimdallSpanForTest( } // new span - span.ID = newSpanID - if span.EndBlock == 0 { - span.StartBlock = 256 + spanBor.ID = newSpanID + if spanBor.EndBlock == 0 { + spanBor.StartBlock = 256 } else { - span.StartBlock = span.EndBlock + 1 + spanBor.StartBlock = spanBor.EndBlock + 1 } - span.EndBlock = span.StartBlock + (100 * c.config.Sprint) - 1 - selectedProducers := make([]Validator, len(snap.ValidatorSet.Validators)) + spanBor.EndBlock = spanBor.StartBlock + (100 * c.config.Sprint) - 1 + + selectedProducers := make([]valset.Validator, len(snap.ValidatorSet.Validators)) for i, v := range snap.ValidatorSet.Validators { selectedProducers[i] = *v } - heimdallSpan := &HeimdallSpan{ - Span: *span, + + heimdallSpan := &span.HeimdallSpan{ + Span: *spanBor, ValidatorSet: *snap.ValidatorSet, SelectedProducers: selectedProducers, ChainID: c.chainConfig.ChainID.String(), @@ -1265,98 +1180,22 @@ func (c *Bor) getNextHeimdallSpanForTest( return heimdallSpan, nil } -// -// Chain context -// - -// chain context -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 -} - -func validatorContains(a []*Validator, x *Validator) (*Validator, bool) { +func validatorContains(a []*valset.Validator, x *valset.Validator) (*valset.Validator, bool) { for _, n := range a { - if bytes.Compare(n.Address.Bytes(), x.Address.Bytes()) == 0 { + if n.Address == x.Address { return n, true } } + return nil, false } -func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator) *ValidatorSet { +func getUpdatedValidatorSet(oldValidatorSet *valset.ValidatorSet, newVals []*valset.Validator) *valset.ValidatorSet { v := oldValidatorSet oldVals := v.Validators - var changes []*Validator + changes := make([]*valset.Validator, 0, len(oldVals)) + for _, ov := range oldVals { if f, ok := validatorContains(newVals, ov); ok { ov.VotingPower = f.VotingPower @@ -1373,10 +1212,13 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator) } } - v.UpdateWithChangeSet(changes) + if err := v.UpdateWithChangeSet(changes); err != nil { + log.Error("Error while updating change set", "error", err) + } + return v } -func isSprintStart(number, sprint uint64) bool { +func IsSprintStart(number, sprint uint64) bool { return number%sprint == 0 } diff --git a/consensus/bor/bor_test.go b/consensus/bor/bor_test.go index b0ebc96861..6225532ca9 100644 --- a/consensus/bor/bor_test.go +++ b/consensus/bor/bor_test.go @@ -4,6 +4,8 @@ import ( "math/big" "testing" + "github.com/stretchr/testify/assert" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" @@ -12,10 +14,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" - "github.com/stretchr/testify/assert" ) func TestGenesisContractChange(t *testing.T) { + t.Parallel() + addr0 := common.Address{0x1} b := &Bor{ @@ -101,6 +104,8 @@ func TestGenesisContractChange(t *testing.T) { } func TestEncodeSigHeaderJaipur(t *testing.T) { + t.Parallel() + // 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 // block is a hard fork to fix that. diff --git a/consensus/bor/clerk.go b/consensus/bor/clerk/clerk.go similarity index 98% rename from consensus/bor/clerk.go rename to consensus/bor/clerk/clerk.go index 5524e249f2..fedca3df16 100644 --- a/consensus/bor/clerk.go +++ b/consensus/bor/clerk/clerk.go @@ -1,4 +1,4 @@ -package bor +package clerk import ( "fmt" diff --git a/consensus/bor/contract/client.go b/consensus/bor/contract/client.go new file mode 100644 index 0000000000..d65fb5bb15 --- /dev/null +++ b/consensus/bor/contract/client.go @@ -0,0 +1,133 @@ +package contract + +import ( + "context" + "math" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/bor/api" + "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" + "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" +) + +var ( + vABI, _ = abi.JSON(strings.NewReader(validatorsetABI)) + sABI, _ = abi.JSON(strings.NewReader(stateReceiverABI)) +) + +func ValidatorSet() abi.ABI { + return vABI +} + +func StateReceiver() abi.ABI { + return sABI +} + +type GenesisContractsClient struct { + validatorSetABI abi.ABI + stateReceiverABI abi.ABI + ValidatorContract string + StateReceiverContract string + chainConfig *params.ChainConfig + ethAPI api.Caller +} + +const ( + validatorsetABI = `[{"constant":true,"inputs":[],"name":"SPRINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FIRST_END_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"producers","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ROUND_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BOR_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spanNumbers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"VOTE_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"validators","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spans","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"endBlock","type":"uint256"}],"name":"NewSpan","type":"event"},{"constant":true,"inputs":[],"name":"currentSprint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getValidatorsTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getProducersTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"getValidatorBySigner","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct BorValidatorSet.Validator","name":"result","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newSpan","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"bytes","name":"validatorBytes","type":"bytes"},{"internalType":"bytes","name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"sigs","type":"bytes"}],"name":"getStakePowerBySigs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"d","type":"bytes32"}],"name":"leafNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"left","type":"bytes32"},{"internalType":"bytes32","name":"right","type":"bytes32"}],"name":"innerNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"}]` + stateReceiverABI = `[{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastStateId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"syncTime","type":"uint256"},{"internalType":"bytes","name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` +) + +func NewGenesisContractsClient( + chainConfig *params.ChainConfig, + validatorContract, + stateReceiverContract string, + ethAPI api.Caller, +) *GenesisContractsClient { + return &GenesisContractsClient{ + validatorSetABI: ValidatorSet(), + stateReceiverABI: StateReceiver(), + ValidatorContract: validatorContract, + StateReceiverContract: stateReceiverContract, + chainConfig: chainConfig, + ethAPI: ethAPI, + } +} + +func (gc *GenesisContractsClient) CommitState( + event *clerk.EventRecordWithTime, + state *state.StateDB, + header *types.Header, + chCtx statefull.ChainContext, +) (uint64, error) { + eventRecord := event.BuildEventRecord() + + recordBytes, err := rlp.EncodeToBytes(eventRecord) + if err != nil { + return 0, err + } + + const method = "commitState" + + t := event.Time.Unix() + + data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes) + if err != nil { + log.Error("Unable to pack tx for commitState", "error", err) + return 0, err + } + + msg := statefull.GetSystemMessage(common.HexToAddress(gc.StateReceiverContract), data) + gasUsed, err := statefull.ApplyMessage(msg, state, header, gc.chainConfig, chCtx) + + // Logging event log with time and individual gasUsed + log.Info("→ committing new state", "eventRecord", event.String(gasUsed)) + + if err != nil { + return 0, err + } + + return gasUsed, nil +} + +func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) { + blockNr := rpc.BlockNumber(snapshotNumber) + method := "lastStateId" + + data, err := gc.stateReceiverABI.Pack(method) + if err != nil { + log.Error("Unable to pack tx for LastStateId", "error", err) + + return nil, err + } + + msgData := (hexutil.Bytes)(data) + toAddress := common.HexToAddress(gc.StateReceiverContract) + gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) + + result, err := gc.ethAPI.Call(context.Background(), ethapi.TransactionArgs{ + Gas: &gas, + To: &toAddress, + Data: &msgData, + }, rpc.BlockNumberOrHash{BlockNumber: &blockNr}, nil) + if err != nil { + return nil, err + } + + ret := new(*big.Int) + if err := gc.stateReceiverABI.UnpackIntoInterface(ret, method, result); err != nil { + return nil, err + } + + return *ret, nil +} diff --git a/consensus/bor/errors.go b/consensus/bor/errors.go index df01b405b6..67f7ef53f3 100644 --- a/consensus/bor/errors.go +++ b/consensus/bor/errors.go @@ -3,37 +3,10 @@ package bor import ( "fmt" "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 { Start uint64 End uint64 @@ -129,7 +102,7 @@ type InvalidStateReceivedError struct { Number uint64 LastStateID uint64 To *time.Time - Event *EventRecordWithTime + Event *clerk.EventRecordWithTime } func (e *InvalidStateReceivedError) Error() string { diff --git a/consensus/bor/genesis.go b/consensus/bor/genesis.go new file mode 100644 index 0000000000..33de53f9ba --- /dev/null +++ b/consensus/bor/genesis.go @@ -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) +} diff --git a/consensus/bor/genesis_contract_mock.go b/consensus/bor/genesis_contract_mock.go new file mode 100644 index 0000000000..dfe9390509 --- /dev/null +++ b/consensus/bor/genesis_contract_mock.go @@ -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) +} diff --git a/consensus/bor/genesis_contracts_client.go b/consensus/bor/genesis_contracts_client.go deleted file mode 100644 index 79a2a254c4..0000000000 --- a/consensus/bor/genesis_contracts_client.go +++ /dev/null @@ -1,105 +0,0 @@ -package bor - -import ( - "context" - "math" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "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 GenesisContractsClient struct { - validatorSetABI abi.ABI - stateReceiverABI abi.ABI - ValidatorContract string - StateReceiverContract string - chainConfig *params.ChainConfig - ethAPI *ethapi.PublicBlockChainAPI -} - -const validatorsetABI = `[{"constant":true,"inputs":[],"name":"SPRINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FIRST_END_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"producers","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ROUND_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BOR_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spanNumbers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"VOTE_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"validators","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spans","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"endBlock","type":"uint256"}],"name":"NewSpan","type":"event"},{"constant":true,"inputs":[],"name":"currentSprint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getValidatorsTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getProducersTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"getValidatorBySigner","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct BorValidatorSet.Validator","name":"result","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newSpan","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"bytes","name":"validatorBytes","type":"bytes"},{"internalType":"bytes","name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"sigs","type":"bytes"}],"name":"getStakePowerBySigs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"d","type":"bytes32"}],"name":"leafNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"left","type":"bytes32"},{"internalType":"bytes32","name":"right","type":"bytes32"}],"name":"innerNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"}]` -const stateReceiverABI = `[{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastStateId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"syncTime","type":"uint256"},{"internalType":"bytes","name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` - -func NewGenesisContractsClient( - chainConfig *params.ChainConfig, - validatorContract, - stateReceiverContract string, - ethAPI *ethapi.PublicBlockChainAPI, -) *GenesisContractsClient { - vABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) - sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI)) - return &GenesisContractsClient{ - validatorSetABI: vABI, - stateReceiverABI: sABI, - ValidatorContract: validatorContract, - StateReceiverContract: stateReceiverContract, - chainConfig: chainConfig, - ethAPI: ethAPI, - } -} - -func (gc *GenesisContractsClient) CommitState( - event *EventRecordWithTime, - state *state.StateDB, - header *types.Header, - chCtx chainContext, -) (uint64, error) { - eventRecord := event.BuildEventRecord() - recordBytes, err := rlp.EncodeToBytes(eventRecord) - if err != nil { - return 0, err - } - method := "commitState" - t := event.Time.Unix() - data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes) - if err != nil { - log.Error("Unable to pack tx for commitState", "error", err) - return 0, err - } - msg := getSystemMessage(common.HexToAddress(gc.StateReceiverContract), data) - gasUsed, err := applyMessage(msg, state, header, gc.chainConfig, chCtx) - // Logging event log with time and individual gasUsed - log.Info("→ committing new state", "eventRecord", event.String(gasUsed)) - if err != nil { - return 0, err - } - return gasUsed, nil -} - -func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) { - blockNr := rpc.BlockNumber(snapshotNumber) - method := "lastStateId" - data, err := gc.stateReceiverABI.Pack(method) - if err != nil { - log.Error("Unable to pack tx for LastStateId", "error", err) - return nil, err - } - - msgData := (hexutil.Bytes)(data) - toAddress := common.HexToAddress(gc.StateReceiverContract) - gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := gc.ethAPI.Call(context.Background(), ethapi.TransactionArgs{ - Gas: &gas, - To: &toAddress, - Data: &msgData, - }, rpc.BlockNumberOrHash{BlockNumber: &blockNr}, nil) - if err != nil { - return nil, err - } - - var ret = new(*big.Int) - if err := gc.stateReceiverABI.UnpackIntoInterface(ret, method, result); err != nil { - return nil, err - } - return *ret, nil -} diff --git a/consensus/bor/heimdall.go b/consensus/bor/heimdall.go new file mode 100644 index 0000000000..217de13fe9 --- /dev/null +++ b/consensus/bor/heimdall.go @@ -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() +} diff --git a/consensus/bor/heimdall/checkpoint/checkpoint.go b/consensus/bor/heimdall/checkpoint/checkpoint.go new file mode 100644 index 0000000000..77569293ad --- /dev/null +++ b/consensus/bor/heimdall/checkpoint/checkpoint.go @@ -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"` +} diff --git a/consensus/bor/heimdall/client.go b/consensus/bor/heimdall/client.go new file mode 100644 index 0000000000..2d42cfc31b --- /dev/null +++ b/consensus/bor/heimdall/client.go @@ -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() +} diff --git a/consensus/bor/heimdall/client_test.go b/consensus/bor/heimdall/client_test.go new file mode 100644 index 0000000000..c423a6f659 --- /dev/null +++ b/consensus/bor/heimdall/client_test.go @@ -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) + } +} diff --git a/consensus/bor/heimdall/span/span.go b/consensus/bor/heimdall/span/span.go new file mode 100644 index 0000000000..5bf85fb341 --- /dev/null +++ b/consensus/bor/heimdall/span/span.go @@ -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"` +} diff --git a/consensus/bor/heimdall/span/spanner.go b/consensus/bor/heimdall/span/spanner.go new file mode 100644 index 0000000000..7bf6e350ee --- /dev/null +++ b/consensus/bor/heimdall/span/spanner.go @@ -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 +} diff --git a/consensus/bor/merkle.go b/consensus/bor/merkle.go index bdfbaba983..ef1b4eb87e 100644 --- a/consensus/bor/merkle.go +++ b/consensus/bor/merkle.go @@ -2,12 +2,12 @@ package bor func appendBytes32(data ...[]byte) []byte { var result []byte + for _, v := range data { - paddedV, err := convertTo32(v) - if err == nil { - result = append(result, paddedV[:]...) - } + paddedV := convertTo32(v) + result = append(result, paddedV[:]...) } + return result } @@ -24,25 +24,29 @@ func nextPowerOfTwo(n uint64) uint64 { n |= n >> 16 n |= n >> 32 n++ + return n } -func convertTo32(input []byte) (output [32]byte, err error) { +func convertTo32(input []byte) (output [32]byte) { l := len(input) if l > 32 || l == 0 { return } + copy(output[32-l:], input[:]) + return } func convert(input []([32]byte)) [][]byte { - var output [][]byte + output := make([][]byte, 0, len(input)) + for _, in := range input { newInput := make([]byte, len(in[:])) copy(newInput, in[:]) output = append(output, newInput) - } + return output } diff --git a/consensus/bor/rest.go b/consensus/bor/rest.go deleted file mode 100644 index 86f6146e77..0000000000 --- a/consensus/bor/rest.go +++ /dev/null @@ -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() -} diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go index 8d212f33ef..f71ceae0ad 100644 --- a/consensus/bor/snapshot.go +++ b/consensus/bor/snapshot.go @@ -1,37 +1,29 @@ package bor import ( - "bytes" "encoding/json" + "github.com/ethereum/go-ethereum/consensus/bor/valset" + lru "github.com/hashicorp/golang-lru" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/params" ) // Snapshot is the state of the authorization voting at a given point in time. type Snapshot struct { 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 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 } -// 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 // method does not initialize the set of recent signers, so only ever use if for // the genesis block. @@ -40,37 +32,38 @@ func newSnapshot( sigcache *lru.ARCCache, number uint64, hash common.Hash, - validators []*Validator, - ethAPI *ethapi.PublicBlockChainAPI, + validators []*valset.Validator, ) *Snapshot { snap := &Snapshot{ config: config, - ethAPI: ethAPI, sigcache: sigcache, Number: number, Hash: hash, - ValidatorSet: NewValidatorSet(validators), + ValidatorSet: valset.NewValidatorSet(validators), Recents: make(map[uint64]common.Address), } + return snap } // 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[:]...)) if err != nil { return nil, err } + snap := new(Snapshot) + if err := json.Unmarshal(blob, snap); err != nil { return nil, err } + snap.config = config snap.sigcache = sigcache - snap.ethAPI = ethAPI // update total voting power - if err := snap.ValidatorSet.updateTotalVotingPower(); err != nil { + if err := snap.ValidatorSet.UpdateTotalVotingPower(); err != nil { return nil, err } @@ -83,6 +76,7 @@ func (s *Snapshot) store(db ethdb.Database) error { if err != nil { return err } + 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 { cpy := &Snapshot{ config: s.config, - ethAPI: s.ethAPI, sigcache: s.sigcache, Number: s.Number, Hash: s.Hash, @@ -115,6 +108,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { return nil, errOutOfRangeChain } } + if headers[0].Number.Uint64() != s.Number+1 { return nil, errOutOfRangeChain } @@ -126,7 +120,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { number := header.Number.Uint64() // 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) } @@ -153,15 +147,17 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { if err := validateHeaderExtraField(header.Extra); err != nil { return nil, err } + validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal] // 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.IncrementProposerPriority(1) snap.ValidatorSet = v } } + snap.Number += uint64(len(headers)) snap.Hash = headers[len(headers)-1].Hash() @@ -173,10 +169,13 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error) validators := s.ValidatorSet.Validators proposer := s.ValidatorSet.GetProposer().Address proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer) + if proposerIndex == -1 { return -1, &UnauthorizedProposerError{s.Number, proposer.Bytes()} } + signerIndex, _ := s.ValidatorSet.GetByAddress(signer) + if signerIndex == -1 { return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()} } @@ -187,6 +186,7 @@ func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error) tempIndex = tempIndex + len(validators) } } + return tempIndex - proposerIndex, nil } @@ -196,13 +196,14 @@ func (s *Snapshot) signers() []common.Address { for _, sig := range s.ValidatorSet.Validators { sigs = append(sigs, sig.Address) } + return sigs } // Difficulty returns the difficulty for a particular signer at the current snapshot number func (s *Snapshot) Difficulty(signer common.Address) uint64 { // if signer is empty - if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 { + if signer == (common.Address{}) { return 1 } diff --git a/consensus/bor/snapshot_test.go b/consensus/bor/snapshot_test.go index 6bb8547843..1a3e967613 100644 --- a/consensus/bor/snapshot_test.go +++ b/consensus/bor/snapshot_test.go @@ -7,8 +7,11 @@ import ( "time" "github.com/stretchr/testify/assert" + "pgregory.net/rapid" "github.com/ethereum/go-ethereum/common" + unique "github.com/ethereum/go-ethereum/common/set" + "github.com/ethereum/go-ethereum/consensus/bor/valset" ) const ( @@ -16,8 +19,10 @@ const ( ) func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) { + t.Parallel() + validators := buildRandomValidatorSet(numVals) - validatorSet := NewValidatorSet(validators) + validatorSet := valset.NewValidatorSet(validators) snap := Snapshot{ ValidatorSet: validatorSet, } @@ -28,20 +33,24 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) { if err != nil { t.Fatalf("%s", err) } + assert.Equal(t, 0, successionNumber) } func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) { + t.Parallel() + validators := buildRandomValidatorSet(numVals) // sort validators by address, which is what NewValidatorSet also does - sort.Sort(ValidatorsByAddress(validators)) + sort.Sort(valset.ValidatorsByAddress(validators)) + proposerIndex := 32 signerIndex := 56 // give highest ProposerPriority to a particular val, so that they become the proposer validators[proposerIndex].VotingPower = 200 snap := Snapshot{ - ValidatorSet: NewValidatorSet(validators), + ValidatorSet: valset.NewValidatorSet(validators), } // choose a signer at an index greater than proposer index @@ -50,17 +59,20 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) { if err != nil { t.Fatalf("%s", err) } + assert.Equal(t, signerIndex-proposerIndex, successionNumber) } func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) { + t.Parallel() + validators := buildRandomValidatorSet(numVals) proposerIndex := 98 signerIndex := 11 // give highest ProposerPriority to a particular val, so that they become the proposer validators[proposerIndex].VotingPower = 200 snap := Snapshot{ - ValidatorSet: NewValidatorSet(validators), + ValidatorSet: valset.NewValidatorSet(validators), } // choose a signer at an index greater than proposer index @@ -69,29 +81,38 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) { if err != nil { t.Fatalf("%s", err) } + assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber) } func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) { + t.Parallel() + validators := buildRandomValidatorSet(numVals) snap := Snapshot{ - ValidatorSet: NewValidatorSet(validators), + ValidatorSet: valset.NewValidatorSet(validators), } + dummyProposerAddress := randomAddress() - snap.ValidatorSet.Proposer = &Validator{Address: dummyProposerAddress} + snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress} + // choose any signer signer := snap.ValidatorSet.Validators[3].Address + _, err := snap.GetSignerSuccessionNumber(signer) assert.NotNil(t, err) + e, ok := err.(*UnauthorizedProposerError) assert.True(t, ok) assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer) } func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) { + t.Parallel() + validators := buildRandomValidatorSet(numVals) snap := Snapshot{ - ValidatorSet: NewValidatorSet(validators), + ValidatorSet: valset.NewValidatorSet(validators), } dummySignerAddress := randomAddress() _, err := snap.GetSignerSuccessionNumber(dummySignerAddress) @@ -101,24 +122,78 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) { 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()) - validators := make([]*Validator, numVals) + + validators := make([]*valset.Validator, numVals) + valAddrs := randomAddresses(numVals) + for i := 0; i < numVals; i++ { - validators[i] = &Validator{ - Address: randomAddress(), + validators[i] = &valset.Validator{ + Address: valAddrs[i], // cannot process validators with voting power 0, hence +1 VotingPower: int64(rand.Intn(99) + 1), } } // sort validators by address, which is what NewValidatorSet also does - sort.Sort(ValidatorsByAddress(validators)) + sort.Sort(valset.ValidatorsByAddress(validators)) + return validators } func randomAddress() common.Address { bytes := make([]byte, 32) rand.Read(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)) + } + }) +} diff --git a/consensus/bor/span.go b/consensus/bor/span.go index 2fd0cf1079..4867635b8e 100644 --- a/consensus/bor/span.go +++ b/consensus/bor/span.go @@ -1,16 +1,17 @@ package bor -// Span 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"` -} +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" + "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" +) -// HeimdallSpan represents span from heimdall APIs -type HeimdallSpan struct { - Span - ValidatorSet ValidatorSet `json:"validator_set" yaml:"validator_set"` - SelectedProducers []Validator `json:"selected_producers" yaml:"selected_producers"` - ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"` +//go:generate mockgen -destination=./span_mock.go -package=bor . Spanner +type Spanner interface { + GetCurrentSpan(headerHash common.Hash) (*span.Span, error) + GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) + CommitSpan(heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error } diff --git a/consensus/bor/span_mock.go b/consensus/bor/span_mock.go new file mode 100644 index 0000000000..12ed945234 --- /dev/null +++ b/consensus/bor/span_mock.go @@ -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) +} diff --git a/consensus/bor/statefull/processor.go b/consensus/bor/statefull/processor.go new file mode 100644 index 0000000000..e30fb4fd21 --- /dev/null +++ b/consensus/bor/statefull/processor.go @@ -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 +} diff --git a/consensus/bor/validators_getter.go b/consensus/bor/validators_getter.go new file mode 100644 index 0000000000..90d1fccf6e --- /dev/null +++ b/consensus/bor/validators_getter.go @@ -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) +} diff --git a/consensus/bor/validators_getter_mock.go b/consensus/bor/validators_getter_mock.go new file mode 100644 index 0000000000..ad99489d8e --- /dev/null +++ b/consensus/bor/validators_getter_mock.go @@ -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) +} diff --git a/consensus/bor/valset/error.go b/consensus/bor/valset/error.go new file mode 100644 index 0000000000..37add21683 --- /dev/null +++ b/consensus/bor/valset/error.go @@ -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, + ) +} diff --git a/consensus/bor/validator.go b/consensus/bor/valset/validator.go similarity index 99% rename from consensus/bor/validator.go rename to consensus/bor/valset/validator.go index 00e9fdc645..250206c1f3 100644 --- a/consensus/bor/validator.go +++ b/consensus/bor/valset/validator.go @@ -1,8 +1,7 @@ -package bor +package valset import ( "bytes" - // "encoding/json" "errors" "fmt" "math/big" @@ -43,9 +42,12 @@ func (v *Validator) Cmp(other *Validator) *Validator { if v == nil { return other } + if other == nil { return v } + + // nolint:nestif if v.ProposerPriority > other.ProposerPriority { return v } else if v.ProposerPriority < other.ProposerPriority { @@ -66,6 +68,7 @@ func (v *Validator) String() string { if v == nil { return "nil-Validator" } + return fmt.Sprintf("Validator{%v Power:%v Priority:%v}", v.Address.Hex(), v.VotingPower, @@ -87,6 +90,7 @@ func (v *Validator) HeaderBytes() []byte { result := make([]byte, 40) copy(result[:20], v.Address.Bytes()) copy(result[20:], v.PowerBytes()) + return result } @@ -95,6 +99,7 @@ func (v *Validator) PowerBytes() []byte { powerBytes := big.NewInt(0).SetInt64(v.VotingPower).Bytes() result := make([]byte, 20) copy(result[20-len(powerBytes):], powerBytes) + return result } @@ -114,6 +119,7 @@ func ParseValidators(validatorsBytes []byte) ([]*Validator, error) { } result := make([]*Validator, len(validatorsBytes)/40) + for i := 0; i < len(validatorsBytes); i += 40 { address := make([]byte, 20) power := make([]byte, 20) @@ -142,6 +148,7 @@ func SortMinimalValByAddress(a []MinimalVal) []MinimalVal { sort.Slice(a, func(i, j int) bool { return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0 }) + return a } @@ -150,5 +157,6 @@ func ValidatorsToMinimalValidators(vals []Validator) (minVals []MinimalVal) { for _, val := range vals { minVals = append(minVals, val.MinimalVal()) } + return } diff --git a/consensus/bor/validator_set.go b/consensus/bor/valset/validator_set.go similarity index 97% rename from consensus/bor/validator_set.go rename to consensus/bor/valset/validator_set.go index 0b5c10ebd0..19e6c681fe 100644 --- a/consensus/bor/validator_set.go +++ b/consensus/bor/valset/validator_set.go @@ -1,4 +1,4 @@ -package bor +package valset // Tendermint leader selection algorithm @@ -55,13 +55,16 @@ type ValidatorSet struct { // function panics. func NewValidatorSet(valz []*Validator) *ValidatorSet { vals := &ValidatorSet{} + err := vals.updateWithChangeSet(valz, false) if err != nil { panic(fmt.Sprintf("cannot create validator set: %s", err)) } + if len(valz) > 0 { vals.IncrementProposerPriority(1) } + return vals } @@ -72,9 +75,10 @@ func (vals *ValidatorSet) IsNilOrEmpty() bool { // Increment ProposerPriority and update the proposer on a copy, and return it. func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet { - copy := vals.Copy() - copy.IncrementProposerPriority(times) - return copy + validatorCopy := vals.Copy() + validatorCopy.IncrementProposerPriority(times) + + return validatorCopy } // IncrementProposerPriority increments ProposerPriority of each validator and updates the @@ -84,6 +88,7 @@ func (vals *ValidatorSet) IncrementProposerPriority(times int) { if vals.IsNilOrEmpty() { panic("empty validator set") } + if times <= 0 { 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. diff := computeMaxMinPriorityDiff(vals) ratio := (diff + diffMax - 1) / diffMax + if diff > diffMax { for _, val := range vals.Validators { val.ProposerPriority = val.ProposerPriority / ratio @@ -145,10 +151,13 @@ func (vals *ValidatorSet) incrementProposerPriority() *Validator { func (vals *ValidatorSet) computeAvgProposerPriority() int64 { n := int64(len(vals.Validators)) sum := big.NewInt(0) + for _, val := range vals.Validators { sum.Add(sum, big.NewInt(val.ProposerPriority)) } + avg := sum.Div(sum, big.NewInt(n)) + if avg.IsInt64() { return avg.Int64() } @@ -162,17 +171,22 @@ func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 { if vals.IsNilOrEmpty() { panic("empty validator set") } + max := int64(math.MinInt64) min := int64(math.MaxInt64) + for _, v := range vals.Validators { if v.ProposerPriority < min { min = v.ProposerPriority } + if v.ProposerPriority > max { max = v.ProposerPriority } } + diff := max - min + if diff < 0 { return -1 * diff } else { @@ -185,6 +199,7 @@ func (vals *ValidatorSet) getValWithMostPriority() *Validator { for _, val := range vals.Validators { res = res.Cmp(val) } + return res } @@ -192,7 +207,9 @@ func (vals *ValidatorSet) shiftByAvgProposerPriority() { if vals.IsNilOrEmpty() { panic("empty validator set") } + avgProposerPriority := vals.computeAvgProposerPriority() + for _, val := range vals.Validators { val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority) } @@ -203,10 +220,13 @@ func validatorListCopy(valsList []*Validator) []*Validator { if valsList == nil { return nil } + valsCopy := make([]*Validator, len(valsList)) + for i, val := range valsList { valsCopy[i] = val.Copy() } + return valsCopy } @@ -225,6 +245,7 @@ func (vals *ValidatorSet) HasAddress(address []byte) bool { idx := sort.Search(len(vals.Validators), func(i int) bool { return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0 }) + 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 { 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 -1, nil } @@ -247,7 +269,9 @@ func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) if index < 0 || index >= len(vals.Validators) { return nil, nil } + val = vals.Validators[index] + return val.Address.Bytes(), val.Copy() } @@ -257,8 +281,7 @@ func (vals *ValidatorSet) Size() int { } // Force recalculation of the set's total voting power. -func (vals *ValidatorSet) updateTotalVotingPower() error { - +func (vals *ValidatorSet) UpdateTotalVotingPower() error { sum := int64(0) for _, val := range vals.Validators { // mind overflow @@ -267,7 +290,9 @@ func (vals *ValidatorSet) updateTotalVotingPower() error { return &TotalVotingPowerExceededError{sum, vals.Validators} } } + vals.totalVotingPower = sum + return nil } @@ -276,11 +301,13 @@ func (vals *ValidatorSet) updateTotalVotingPower() error { func (vals *ValidatorSet) TotalVotingPower() int64 { if vals.totalVotingPower == 0 { log.Info("invoking updateTotalVotingPower before returning it") - if err := vals.updateTotalVotingPower(); err != nil { + + if err := vals.UpdateTotalVotingPower(); err != nil { // Can/should we do better? panic(err) } } + return vals.totalVotingPower } @@ -290,9 +317,11 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) { if len(vals.Validators) == 0 { return nil } + if vals.Proposer == nil { vals.Proposer = vals.findProposer() } + return vals.Proposer.Copy() } @@ -303,6 +332,7 @@ func (vals *ValidatorSet) findProposer() *Validator { proposer = proposer.Cmp(val) } } + return proposer } @@ -343,6 +373,7 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e removals = make([]*Validator, 0, len(changes)) updates = make([]*Validator, 0, len(changes)) + var prevAddr common.Address // 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) return nil, nil, err } + if valUpdate.VotingPower < 0 { err = fmt.Errorf("voting power can't be negative: %v", valUpdate) return nil, nil, err } + if valUpdate.VotingPower > MaxTotalVotingPower { err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ", MaxTotalVotingPower, valUpdate) return nil, nil, err } + if valUpdate.VotingPower == 0 { removals = append(removals, valUpdate) } else { updates = append(updates, valUpdate) } + prevAddr = valUpdate.Address } + return updates, removals, err } @@ -382,12 +418,12 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e // by processChanges for duplicates and invalid values. // No changes are made to the validator set 'vals'. func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) { - updatedTotalVotingPower = vals.TotalVotingPower() for _, valUpdate := range updates { address := valUpdate.Address _, val := vals.GetByAddress(address) + if val == nil { // New validator, add its voting power the the total. updatedTotalVotingPower += valUpdate.VotingPower @@ -396,11 +432,14 @@ func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVoting // Updated validator, add the difference in power to the total. updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower } + overflow := updatedTotalVotingPower > MaxTotalVotingPower + if overflow { err = fmt.Errorf( "failed to add/update validator %v, total voting power would exceed the max allowed %v", valUpdate, MaxTotalVotingPower) + 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. // No changes are made to the validator set 'vals'. func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotalVotingPower int64) { - for _, valUpdate := range updates { address := valUpdate.Address _, val := vals.GetByAddress(address) + if val == nil { // add val // 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 } } - } // 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, // must have been validated with verifyUpdates() and priorities computed with computeNewPriorities(). func (vals *ValidatorSet) applyUpdates(updates []*Validator) { - existing := vals.Validators merged := make([]*Validator, len(existing)+len(updates)) 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. // No changes are made to the validator set 'vals'. func verifyRemovals(deletes []*Validator, vals *ValidatorSet) error { - for _, valUpdate := range deletes { address := valUpdate.Address _, val := vals.GetByAddress(address) + if val == nil { return fmt.Errorf("failed to find validator %X to remove", address) } } + if len(deletes) > len(vals.Validators) { panic("more deletes than validators") } + return nil } // Removes the validators specified in 'deletes' from validator set 'vals'. // Should not fail as verification has been done before. func (vals *ValidatorSet) applyRemovals(deletes []*Validator) { - existing := vals.Validators merged := make([]*Validator, len(existing)-len(deletes)) @@ -509,6 +547,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) { merged[i] = existing[0] i++ } + 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'. // The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet(). func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error { - if len(changes) <= 0 { return nil } @@ -564,7 +602,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes vals.applyUpdates(updates) vals.applyRemovals(deletes) - if err := vals.updateTotalVotingPower(); err != nil { + if err := vals.UpdateTotalVotingPower(); err != nil { return err } @@ -596,19 +634,19 @@ func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator) error { func IsErrTooMuchChange(err error) bool { switch err.(type) { - case errTooMuchChange: + case tooMuchChangeError: return true default: return false } } -type errTooMuchChange struct { +type tooMuchChangeError struct { got 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) } @@ -622,11 +660,14 @@ func (vals *ValidatorSet) StringIndented(indent string) string { if vals == nil { return "nil-ValidatorSet" } + var valStrings []string + vals.Iterate(func(index int, val *Validator) bool { valStrings = append(valStrings, val.String()) return false }) + return fmt.Sprintf(`ValidatorSet{ %s Proposer: %v %s Validators: @@ -636,7 +677,6 @@ func (vals *ValidatorSet) StringIndented(indent string) string { indent, indent, strings.Join(valStrings, "\n"+indent+" "), indent) - } //------------------------------------- @@ -668,6 +708,7 @@ func safeAdd(a, b int64) (int64, bool) { } else if b < 0 && a < math.MinInt64-b { return -1, true } + return a + b, false } @@ -677,6 +718,7 @@ func safeSub(a, b int64) (int64, bool) { } else if b < 0 && a > math.MaxInt64+b { return -1, true } + return a - b, false } @@ -686,8 +728,10 @@ func safeAddClip(a, b int64) int64 { if b < 0 { return math.MinInt64 } + return math.MaxInt64 } + return c } @@ -697,7 +741,9 @@ func safeSubClip(a, b int64) int64 { if b > 0 { return math.MinInt64 } + return math.MaxInt64 } + return c } diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go index c34e76aec2..a9e96af866 100644 --- a/consensus/ethash/sealer_test.go +++ b/consensus/ethash/sealer_test.go @@ -70,7 +70,7 @@ func TestRemoteNotify(t *testing.T) { if want := common.BytesToHash(target.Bytes()).Hex(); 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") } } diff --git a/consensus/merger.go b/consensus/merger.go index ffbcbf2b85..c435ecf91e 100644 --- a/consensus/merger.go +++ b/consensus/merger.go @@ -45,12 +45,14 @@ type Merger struct { // NewMerger creates a new Merger which stores its transition status in the provided db. func NewMerger(db ethdb.KeyValueStore) *Merger { var status transitionStatus + blob := rawdb.ReadTransitionStatus(db) if len(blob) != 0 { if err := rlp.DecodeBytes(blob, &status); err != nil { log.Crit("Failed to decode the transition status", "err", err) } } + return &Merger{ db: db, status: status, diff --git a/core/bench_test.go b/core/bench_test.go index 959979763d..ad6179d0a8 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -305,7 +305,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) { } makeChainForBench(db, full, count) db.Close() - cacheConfig := *defaultCacheConfig + + cacheConfig := *DefaultCacheConfig cacheConfig.TrieDirtyDisabled = true b.ReportAllocs() diff --git a/core/blockchain.go b/core/blockchain.go index 1b11c781c5..8a4c581f66 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -27,6 +27,8 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" @@ -43,7 +45,6 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" - lru "github.com/hashicorp/golang-lru" ) 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 } -// 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). -var defaultCacheConfig = &CacheConfig{ +var DefaultCacheConfig = &CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, @@ -222,7 +223,7 @@ type BlockChain struct { // 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) { if cacheConfig == nil { - cacheConfig = defaultCacheConfig + cacheConfig = DefaultCacheConfig } bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index b93444b8cd..f61f930496 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "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)) } +// 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 // +type BorStateSyncer interface { + SetStateSync(stateData []*types.StateSyncData) + SubscribeStateSyncEvent(ch chan<- StateSyncEvent) event.Subscription +} + // SetStateSync set sync data in state_data func (bc *BlockChain) SetStateSync(stateData []*types.StateSyncData) { bc.stateSyncData = stateData diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 37a1a42d0c..de97000918 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -920,7 +920,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveDb, delfn := makeDb() defer delfn() - archiveCaching := *defaultCacheConfig + archiveCaching := *DefaultCacheConfig archiveCaching.TrieDirtyDisabled = true archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) diff --git a/core/chain_makers.go b/core/chain_makers.go index c7bf60a4b0..4b2d2082df 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" ) @@ -334,7 +335,10 @@ func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethd } type fakeChainReader struct { - config *params.ChainConfig + config *params.ChainConfig + stateSyncData []*types.StateSyncData + stateSyncFeed event.Feed + scope event.SubscriptionScope } // 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) GetBlock(hash common.Hash, number uint64) *types.Block { 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)) +} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 7d6939e1dc..158e8c1eeb 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -21,6 +21,8 @@ import ( "math/big" "testing" + "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" @@ -32,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" - "golang.org/x/crypto/sha3" ) // 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{ ParentHash: parent.Hash(), 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(), Time: parent.Time(), Difficulty: parent.Difficulty(), diff --git a/core/blockchain_repair_test.go b/core/tests/blockchain_repair_test.go similarity index 93% rename from core/blockchain_repair_test.go rename to core/tests/blockchain_repair_test.go index 9133671796..b52bf76fd9 100644 --- a/core/blockchain_repair_test.go +++ b/core/tests/blockchain_repair_test.go @@ -18,7 +18,7 @@ // the database in some strange state with gaps in the chain, nor with block data // dangling in the future. -package core +package tests import ( "io/ioutil" @@ -27,12 +27,22 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" + + "github.com/ethereum/go-ethereum/accounts" "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/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "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/tests/bor/mocks" ) // 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) } +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) { + t.Skip("need to add a proper signer for Bor consensus") + // 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)))) // 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 + 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 var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) - engine = ethash.NewFullFaker() - config = &CacheConfig{ + gspec = &core.Genesis{ + Config: params.BorUnittestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), + } + config = &core.CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, // Disable snapshot by default } ) + + engine := miner.NewFakeBor(t, db, params.BorUnittestChainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock) 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 { config.SnapshotLimit = 256 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 { t.Fatalf("Failed to create chain: %v", err) } + // If sidechain blocks are needed, make a light chain and import it var sideblocks types.Blocks if tt.sidechainBlocks > 0 { - sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) { - b.SetCoinbase(common.Address{0x01}) + sideblocks, _ = core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) { + 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 { 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.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 { t.Fatalf("Failed to import canonical chain start: %v", err) } 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 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) } } @@ -1837,7 +1914,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { } 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 { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1888,19 +1965,21 @@ func TestIssue23496(t *testing.T) { if err != nil { t.Fatalf("Failed to create temporary datadir: %v", err) } + os.RemoveAll(datadir) db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } + defer db.Close() // Might double close, should be fine // Initialize a fresh chain var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) engine = ethash.NewFullFaker() - config = &CacheConfig{ + config = &core.CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, @@ -1908,11 +1987,13 @@ func TestIssue23496(t *testing.T) { 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 { 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.SetDifficulty(big.NewInt(1000000)) }) @@ -1921,13 +2002,18 @@ func TestIssue23496(t *testing.T) { if _, err := chain.InsertChain(blocks[:1]); err != nil { 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 if _, err := chain.InsertChain(blocks[1:2]); err != nil { 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) } @@ -1935,7 +2021,11 @@ func TestIssue23496(t *testing.T) { if _, err := chain.InsertChain(blocks[2:3]); err != nil { 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 if _, err := chain.InsertChain(blocks[3:]); err != nil { @@ -1950,20 +2040,24 @@ func TestIssue23496(t *testing.T) { if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } + 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 { t.Fatalf("Failed to recreate chain: %v", err) } + defer chain.Stop() if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) { t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4) } + if head := chain.CurrentFastBlock(); 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) { 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 { t.Fatalf("Failed to import canonical chain tail: %v", err) } + if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) { t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4) } + if head := chain.CurrentFastBlock(); 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) { t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(4)) } + if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil { t.Error("Failed to regenerate the snapshot of known state") } diff --git a/core/blockchain_sethead_test.go b/core/tests/blockchain_sethead_test.go similarity index 98% rename from core/blockchain_sethead_test.go rename to core/tests/blockchain_sethead_test.go index b2b3a058a4..3a2d87c4eb 100644 --- a/core/blockchain_sethead_test.go +++ b/core/tests/blockchain_sethead_test.go @@ -17,7 +17,7 @@ // 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. -package core +package tests import ( "fmt" @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common" "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/types" "github.com/ethereum/go-ethereum/core/vm" @@ -1959,79 +1960,98 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { if err != nil { t.Fatalf("Failed to create temporary datadir: %v", err) } + os.RemoveAll(datadir) db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } + defer db.Close() // Initialize a fresh chain var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) engine = ethash.NewFullFaker() - config = &CacheConfig{ + config = &core.CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, // Disable snapshot } ) + if snapshots { config.SnapshotLimit = 256 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 { t.Fatalf("Failed to create chain: %v", err) } + // If sidechain blocks are needed, make a light chain and import it var sideblocks types.Blocks 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}) }) + if _, err := chain.InsertChain(sideblocks); err != nil { 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.SetDifficulty(big.NewInt(1000000)) }) + if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } + 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 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) } } } + if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil { t.Fatalf("Failed to import canonical chain tail: %v", err) } + // Manually dereference anything not committed to not have to work with 128+ tries for _, block := range sideblocks { - chain.stateCache.TrieDB().Dereference(block.Root()) + chain.StateCache().TrieDB().Dereference(block.Root()) } + for _, block := range canonblocks { - chain.stateCache.TrieDB().Dereference(block.Root()) + chain.StateCache().TrieDB().Dereference(block.Root()) } + // Force run a freeze cycle type freezer interface { Freeze(threshold uint64) error Ancients() (uint64, error) } + db.(freezer).Freeze(tt.freezeThreshold) // Set the simulated pivot block if tt.pivotBlock != nil { rawdb.WriteLastPivotNumber(db, *tt.pivotBlock) } + // Set the head of the chain back to the requested number 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 { t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader) } + if head := chain.CurrentFastBlock(); 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 { t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock) } + if frozen, err := db.(freezer).Ancients(); err != nil { t.Errorf("Failed to retrieve ancient count: %v\n", err) } 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 // 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() 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 // 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() for i := 1; i <= len(inserted); i++ { diff --git a/core/blockchain_snapshot_test.go b/core/tests/blockchain_snapshot_test.go similarity index 87% rename from core/blockchain_snapshot_test.go rename to core/tests/blockchain_snapshot_test.go index a8044ecb4d..fb4c09867c 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/tests/blockchain_snapshot_test.go @@ -17,7 +17,7 @@ // Tests that abnormal program termination (i.e.crash) and restart can recovery // the snapshot properly if the snapshot is enabled. -package core +package tests import ( "bytes" @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "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/types" "github.com/ethereum/go-ethereum/core/vm" @@ -57,7 +58,9 @@ type snapshotTestBasic struct { 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 datadir, err := ioutil.TempDir("", "") if err != nil { @@ -71,20 +74,22 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo } // Initialize a fresh chain var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) engine = ethash.NewFullFaker() gendb = rawdb.NewMemoryDatabase() // Snapshot is enabled, the first snapshot is created from the Genesis. // The snapshot memory allowance is 256MB, it means no snapshot flush // 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 { 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. var breakpoints []uint64 @@ -93,27 +98,39 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo } else { breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock) } + var startPoint uint64 + for _, point := range breakpoints { if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } + startPoint = 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 { // Flushing the entire snap tree into the disk, the // relevant (a) snapshot root and (b) snapshot generator // will be persisted atomically. - chain.snaps.Cap(blocks[point-1].Root(), 0) - diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root() + err = chain.Snaps().Cap(blocks[point-1].Root(), 0) + 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()) { t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot) } } } + if _, err := chain.InsertChain(blocks[startPoint:]); err != nil { 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.gendb = gendb basic.engine = engine + 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 verifyNoGaps(t, chain, true, blocks) 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 { t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader) } + if head := chain.CurrentFastBlock(); 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 { 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) if block == nil { 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()) { - t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot()) + } 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()) } // 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) } } @@ -223,10 +245,12 @@ func (snaptest *snapshotTest) test(t *testing.T) { // Restart the chain normally 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 { t.Fatalf("Failed to recreate chain: %v", err) } + defer newchain.Stop() snaptest.verify(t, newchain, blocks) @@ -245,7 +269,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { chain, blocks := snaptest.prepare(t) // Pull the plug on the database, simulating a hard crash - db := chain.db + db := chain.DB() db.Close() // 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 // after the normal stop. It's used to ensure the broken snapshot // 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 { t.Fatalf("Failed to recreate chain: %v", err) } 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 { 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. 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 - var cacheConfig = &CacheConfig{ + var cacheConfig = &core.CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, 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 { t.Fatalf("Failed to recreate chain: %v", err) } + newchain.InsertChain(gappedBlocks) newchain.Stop() // 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 { t.Fatalf("Failed to recreate chain: %v", err) } + defer newchain.Stop() snaptest.verify(t, newchain, blocks) @@ -337,7 +365,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) { chain.SetHead(snaptest.setHead) 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 { t.Fatalf("Failed to recreate chain: %v", err) } @@ -368,11 +396,12 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) { // and state committed. 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 { 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) // 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 // 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 { t.Fatalf("Failed to recreate chain: %v", err) } @@ -414,38 +443,42 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { // and state committed. chain.Stop() - config := &CacheConfig{ + config := &core.CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, 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 { 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.Stop() // Restart the chain, the wiper should starts working - config = &CacheConfig{ + config = &core.CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, 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 { t.Fatalf("Failed to recreate chain: %v", err) } // 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 { t.Fatalf("Failed to recreate chain: %v", err) } + snaptest.verify(t, newchain, blocks) } diff --git a/docs/cli/README.md b/docs/cli/README.md index ed8a3f5977..d92a7b5a05 100644 --- a/docs/cli/README.md +++ b/docs/cli/README.md @@ -1,24 +1,33 @@ - -# Command line interface +# Bor command line interface ## Commands -- [```server```](./server.md) - -- [```debug```](./debug.md) - - [```account```](./account.md) -- [```account new```](./account_new.md) +- [```account import```](./account_import.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 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 add```](./peers_add.md) @@ -29,8 +38,8 @@ - [```peers status```](./peers_status.md) +- [```server```](./server.md) + - [```status```](./status.md) -- [```chain watch```](./chain_watch.md) - -- [```version```](./version.md) +- [```version```](./version.md) \ No newline at end of file diff --git a/docs/cli/account.md b/docs/cli/account.md index 00fd6cbe65..b3659952f6 100644 --- a/docs/cli/account.md +++ b/docs/cli/account.md @@ -1,4 +1,3 @@ - # Account The ```account``` command groups actions to interact with accounts: @@ -7,4 +6,4 @@ The ```account``` command groups actions to interact with accounts: - [```account list```](./account_list.md): List the wallets in the Bor client. -- [```account import```](./account_import.md): Import an account to the Bor client. +- [```account import```](./account_import.md): Import an account to the Bor client. \ No newline at end of file diff --git a/docs/cli/account_import.md b/docs/cli/account_import.md index 2a515866cf..d7b02195bc 100644 --- a/docs/cli/account_import.md +++ b/docs/cli/account_import.md @@ -1,4 +1,9 @@ - # Account import 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 \ No newline at end of file diff --git a/docs/cli/account_list.md b/docs/cli/account_list.md index 4a2d28de92..61ebf9e776 100644 --- a/docs/cli/account_list.md +++ b/docs/cli/account_list.md @@ -1,4 +1,9 @@ - # 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 \ No newline at end of file diff --git a/docs/cli/account_new.md b/docs/cli/account_new.md index 41e53767a1..dd62061ba0 100644 --- a/docs/cli/account_new.md +++ b/docs/cli/account_new.md @@ -1,4 +1,9 @@ - # 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 \ No newline at end of file diff --git a/docs/cli/attach.md b/docs/cli/attach.md new file mode 100644 index 0000000000..6e323b8d18 --- /dev/null +++ b/docs/cli/attach.md @@ -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` \ No newline at end of file diff --git a/docs/cli/bootnode.md b/docs/cli/bootnode.md new file mode 100644 index 0000000000..48e933a934 --- /dev/null +++ b/docs/cli/bootnode.md @@ -0,0 +1,17 @@ +# Bootnode + +## Options + +- ```listen-addr```: listening address of bootnode (:) + +- ```v5```: Enable UDP v5 + +- ```log-level```: Log level (trace|debug|info|warn|error|crit) + +- ```nat```: port mapping mechanism (any|none|upnp|pmp|extip:) + +- ```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 \ No newline at end of file diff --git a/docs/cli/chain.md b/docs/cli/chain.md index e55a90f122..8412588e37 100644 --- a/docs/cli/chain.md +++ b/docs/cli/chain.md @@ -1,6 +1,7 @@ - # 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. \ No newline at end of file diff --git a/docs/cli/chain_sethead.md b/docs/cli/chain_sethead.md index 985383988f..bf97990e62 100644 --- a/docs/cli/chain_sethead.md +++ b/docs/cli/chain_sethead.md @@ -1,4 +1,3 @@ - # Chain sethead The ```chain sethead ``` command sets the current chain to a certain block. @@ -9,4 +8,6 @@ The ```chain sethead ``` command sets the current chain to a certain blo ## Options -- ```yes```: Force set head. +- ```address```: Address of the grpc endpoint + +- ```yes```: Force set head \ No newline at end of file diff --git a/docs/cli/chain_watch.md b/docs/cli/chain_watch.md index 4844bb7618..252ac02531 100644 --- a/docs/cli/chain_watch.md +++ b/docs/cli/chain_watch.md @@ -1,3 +1,3 @@ # Chain watch -The ```chain watch``` command is used to view the chainHead, reorg and fork events in real-time. +The ```chain watch``` command is used to view the chainHead, reorg and fork events in real-time. \ No newline at end of file diff --git a/docs/cli/debug.md b/docs/cli/debug.md index c75ae79e49..a59e465745 100644 --- a/docs/cli/debug.md +++ b/docs/cli/debug.md @@ -1,13 +1,10 @@ - # Debug 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. - -- ```output```: Output directory for the data dump. +- [```bor debug block ```](./debug_block.md): Dumps bor block traces. ## Examples @@ -15,8 +12,8 @@ By default it creates a tar.gz file with the output: ``` $ bor debug -Starting debugger... - +Starting debugger... + Created debug archive: bor-debug-2021-10-26-073819Z.tar.gz ``` @@ -27,4 +24,4 @@ $ bor debug --output data Starting debugger... Created debug directory: data/bor-debug-2021-10-26-075437Z -``` +``` \ No newline at end of file diff --git a/docs/cli/debug_block.md b/docs/cli/debug_block.md new file mode 100644 index 0000000000..ced7e482ee --- /dev/null +++ b/docs/cli/debug_block.md @@ -0,0 +1,9 @@ +# Debug trace + +The ```bor debug block ``` command will create an archive containing traces of a bor block. + +## Options + +- ```address```: Address of the grpc endpoint + +- ```output```: Output directory \ No newline at end of file diff --git a/docs/cli/debug_pprof.md b/docs/cli/debug_pprof.md new file mode 100644 index 0000000000..86a84b6065 --- /dev/null +++ b/docs/cli/debug_pprof.md @@ -0,0 +1,11 @@ +# Debug Pprof + +The ```debug pprof ``` command will create an archive containing bor pprof traces. + +## Options + +- ```address```: Address of the grpc endpoint + +- ```seconds```: seconds to trace + +- ```output```: Output directory \ No newline at end of file diff --git a/docs/cli/fingerprint.md b/docs/cli/fingerprint.md new file mode 100644 index 0000000000..8bb7cb1542 --- /dev/null +++ b/docs/cli/fingerprint.md @@ -0,0 +1,3 @@ +# Fingerprint + +Display the system fingerprint \ No newline at end of file diff --git a/docs/cli/peers.md b/docs/cli/peers.md index 57b4889a00..ac6dfd676e 100644 --- a/docs/cli/peers.md +++ b/docs/cli/peers.md @@ -1,4 +1,3 @@ - # Peers The ```peers``` command groups actions to interact with peers: @@ -9,4 +8,4 @@ The ```peers``` command groups actions to interact with peers: - [```peers remove```](./peers_remove.md): Disconnects the local client from a connected peer if exists. -- [```peers status```](./peers_status.md): Display the status of a peer by its id. +- [```peers status```](./peers_status.md): Display the status of a peer by its id. \ No newline at end of file diff --git a/docs/cli/peers_add.md b/docs/cli/peers_add.md index 35e5ece450..5bc4ed1448 100644 --- a/docs/cli/peers_add.md +++ b/docs/cli/peers_add.md @@ -1,8 +1,9 @@ - # Peers add The ```peers add ``` 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 \ No newline at end of file diff --git a/docs/cli/peers_list.md b/docs/cli/peers_list.md index cb1ef2f599..41f398b764 100644 --- a/docs/cli/peers_list.md +++ b/docs/cli/peers_list.md @@ -1,4 +1,7 @@ - -# Peers list +# Peers add The ```peers list``` command lists the connected peers. + +## Options + +- ```address```: Address of the grpc endpoint \ No newline at end of file diff --git a/docs/cli/peers_remove.md b/docs/cli/peers_remove.md index e2fa0a71df..2cac1e7656 100644 --- a/docs/cli/peers_remove.md +++ b/docs/cli/peers_remove.md @@ -1,4 +1,9 @@ - # Peers remove The ```peers remove ``` 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 \ No newline at end of file diff --git a/docs/cli/peers_status.md b/docs/cli/peers_status.md index 56343c8d6b..65a0fe9d8f 100644 --- a/docs/cli/peers_status.md +++ b/docs/cli/peers_status.md @@ -1,4 +1,7 @@ - # Peers status The ```peers status ``` command displays the status of a peer by its id. + +## Options + +- ```address```: Address of the grpc endpoint \ No newline at end of file diff --git a/docs/cli/server.md b/docs/cli/server.md index 5a3e7e1052..0803208e3a 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -1,45 +1,182 @@ - # Server 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 (=). +- ```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 (=) -- ```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:) + +- ```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 -- ```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 @@ -59,136 +196,4 @@ The ```bor server``` command runs the Bor client. - ```txpool.globalqueue```: Maximum number of non-executable transaction slots for all accounts -- ```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:) - -- ```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 -``` +- ```txpool.lifetime```: Maximum amount of time non-executable transaction are queued \ No newline at end of file diff --git a/docs/cli/status.md b/docs/cli/status.md index fb7bddb182..9fa8e25905 100644 --- a/docs/cli/status.md +++ b/docs/cli/status.md @@ -1,4 +1,3 @@ - # Status -The ```status``` command outputs the status of the client. +The ```status``` command outputs the status of the client. \ No newline at end of file diff --git a/docs/cli/version.md b/docs/cli/version.md index 156bdf607c..87e7cf44a8 100644 --- a/docs/cli/version.md +++ b/docs/cli/version.md @@ -1,4 +1,3 @@ - # Version The ```bor version``` command outputs the version of the binary. @@ -8,4 +7,4 @@ The ```bor version``` command outputs the version of the binary. ``` $ bor version 0.2.9-stable -``` +``` \ No newline at end of file diff --git a/eth/backend.go b/eth/backend.go index fcba1c573b..0b8a956cfa 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -82,6 +82,7 @@ type Ethereum struct { eventMux *event.TypeMux engine consensus.Engine accountManager *accounts.Manager + authorized bool // If consensus engine is authorized with keystore bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 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, eventMux: stack.EventMux(), accountManager: stack.AccountManager(), + authorized: false, engine: nil, closeBloomHandler: make(chan struct{}), networkID: config.NetworkId, @@ -473,8 +475,10 @@ func (s *Ethereum) StartMining(threads int) error { if threads == 0 { threads = -1 // Disable the miner from within } + th.SetThreads(threads) } + // If the miner was not running, initialize it if !s.IsMining() { // Propagate the initial price point to the transaction pool @@ -487,31 +491,43 @@ func (s *Ethereum) StartMining(threads int) error { eb, err := s.Etherbase() if err != nil { log.Error("Cannot start mining without etherbase", "err", err) + return fmt.Errorf("etherbase missing: %v", err) } - var cli *clique.Clique - if c, ok := s.engine.(*clique.Clique); ok { - cli = c - } else if cl, ok := s.engine.(*beacon.Beacon); ok { - if c, ok := cl.InnerEngine().(*clique.Clique); ok { + + // If personal endpoints are disabled, the server creating + // this Ethereum instance has already Authorized consensus. + if !s.authorized { + var cli *clique.Clique + if c, ok := s.engine.(*clique.Clique); ok { cli = c + } else if cl, ok := s.engine.(*beacon.Beacon); ok { + if c, ok := cl.InnerEngine().(*clique.Clique); ok { + cli = c + } } - } - if cli != nil { - wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) - if wallet == nil || err != nil { - log.Error("Etherbase account unavailable locally", "err", err) - return fmt.Errorf("signer missing: %v", err) + + if cli != nil { + wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", 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 { - wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) - if wallet == nil || err != nil { - log.Error("Etherbase account unavailable locally", "err", err) - return fmt.Errorf("signer missing: %v", err) + + if bor, ok := s.engine.(*bor.Bor); ok { + wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", 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 // introduced to speed sync times. @@ -519,6 +535,7 @@ func (s *Ethereum) StartMining(threads int) error { go s.miner.Start(eb) } + return nil } @@ -557,6 +574,14 @@ func (s *Ethereum) SyncMode() downloader.SyncMode { 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 // network protocols to start. func (s *Ethereum) Protocols() []p2p.Protocol { @@ -564,6 +589,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol { if s.config.SnapshotCache > 0 { protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) } + return protos } @@ -645,7 +671,7 @@ func (s *Ethereum) handleWhitelistCheckpoint() error { return ErrNotBorConsensus } - if bor.WithoutHeimdall { + if bor.HeimdallClient == nil { return ErrBorConsensusWithoutHeimdall } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index b82a622893..1a9d815ccd 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -215,6 +215,7 @@ type BlockChain interface { } // 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 { if lightchain == nil { 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 { frequency = 1 } + // Although the received headers might be all valid, a legacy // PoW/PoA sync must not accept post-merge headers. Make sure // 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 td *big.Int ) + if !beaconMode && ttd != nil { td = d.blockchain.GetTd(chunkHeaders[0].ParentHash, chunkHeaders[0].Number.Uint64()-1) if td == nil { // 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) + return fmt.Errorf("%w: parent TD missing", errInvalidChain) } + for i, header := range chunkHeaders { td = new(big.Int).Add(td, header.Difficulty) if td.Cmp(ttd) >= 0 { @@ -1406,10 +1411,12 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } else { chunkHeaders, rejected = chunkHeaders[:i], chunkHeaders[i:] } + break } } } + if len(chunkHeaders) > 0 { if n, err := d.lightchain.InsertHeaderChain(chunkHeaders, frequency); err != nil { 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 { rollback = chunkHeaders[0].Number.Uint64() } + 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) } // All verifications passed, track all headers within the allowed limits if mode == SnapSync { head := chunkHeaders[len(chunkHeaders)-1].Number.Uint64() + if head-rollback > uint64(fsHeaderSafetyNet) { rollback = head - uint64(fsHeaderSafetyNet) } else { @@ -1431,21 +1441,26 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } } } + if len(rejected) != 0 { // Merge threshold reached, stop importing, but don't roll back rollback = 0 log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd) + return ErrMergeTransition } + if len(rejected) != 0 { // Merge threshold reached, stop importing, but don't roll back rollback = 0 log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd) + return ErrMergeTransition } } + // Unless we're doing light chains, schedule the headers for associated content retrieval if mode == FullSync || mode == SnapSync { // If we've reached the allowed number of pending headers, stall a bit diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index bf9158d220..37b07424dd 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -43,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/stretchr/testify/assert" ) @@ -62,23 +63,28 @@ func newTester() *downloadTester { if err != nil { panic(err) } + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false) if err != nil { panic(err) } + core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000)) chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { panic(err) } + tester := &downloadTester{ freezer: freezer, chain: chain, peers: make(map[string]*downloadTesterPeer), } + //nolint: staticcheck tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, nil, whitelist.NewService(10)) + return tester } @@ -1349,6 +1355,7 @@ func TestRemoteHeaderRequestSpan(t *testing.T) { } } } + if failed { res := strings.Replace(fmt.Sprint(data), " ", ",", -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 { expect = errUnsyncedPeer } + if err := tester.sync("peer", nil, mode); !errors.Is(err, expect) { t.Fatalf("block sync error mismatch: have %v, want %v", err, expect) } + if mode == SnapSync || mode == LightSync { assertOwnChain(t, tester, 1) } 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 // 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() { 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 { return nil @@ -1427,6 +1437,8 @@ func (w *whitelistFake) PurgeCheckpointWhitelist() {} // TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted // checkpoint mismatch with opposite peer, the sync should fail. func TestFakedSyncProgress66WhitelistMismatch(t *testing.T) { + t.Parallel() + protocol := uint(eth.ETH66) mode := FullSync @@ -1450,6 +1462,8 @@ func TestFakedSyncProgress66WhitelistMismatch(t *testing.T) { // TestFakedSyncProgress66WhitelistMatch tests if in case of whitelisted // checkpoint match with opposite peer, the sync should succeed. func TestFakedSyncProgress66WhitelistMatch(t *testing.T) { + t.Parallel() + protocol := uint(eth.ETH66) mode := FullSync @@ -1474,6 +1488,8 @@ func TestFakedSyncProgress66WhitelistMatch(t *testing.T) { // checkpointed blocks with opposite peer, the sync should fail initially but // with the retry mechanism, it should succeed eventually. func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) { + t.Parallel() + protocol := uint(eth.ETH66) mode := FullSync @@ -1483,8 +1499,10 @@ func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) { if count == 0 { return false, whitelist.ErrNoRemoteCheckoint } + return true, nil } + tester.downloader.ChainValidator = newWhitelistFake(validate) defer tester.terminate() diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 428e3cb706..872bfcd1a9 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -65,9 +65,9 @@ type chainData struct { } var ( - chain *chainData + chain *chainData chainLongerFork *chainData - emptyChain *chainData + emptyChain *chainData ) func init() { @@ -78,7 +78,7 @@ func init() { blocks, _ = makeChain(targetBlocks, 0, genesis, true) emptyChain = &chainData{blocks, 0} - + chainLongerForkBlocks, _ := makeChain(1024, 0, blocks[len(blocks)-1], false) chainLongerFork = &chainData{chainLongerForkBlocks, 0} } diff --git a/eth/downloader/whitelist/service.go b/eth/downloader/whitelist/service.go index c3b6ad6462..7036f24a8f 100644 --- a/eth/downloader/whitelist/service.go +++ b/eth/downloader/whitelist/service.go @@ -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) { // We want to validate the chain by comparing the last checkpointed block // we're storing in `checkpointWhitelist` with the peer's block. - + // // Check for availaibility of the last checkpointed block. // This can be also be empty if our heimdall is not responding // or we're running without it. diff --git a/eth/downloader/whitelist/service_test.go b/eth/downloader/whitelist/service_test.go index 79a92da826..ca202cc3ad 100644 --- a/eth/downloader/whitelist/service_test.go +++ b/eth/downloader/whitelist/service_test.go @@ -5,9 +5,10 @@ import ( "math/big" "testing" + "gotest.tools/assert" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "gotest.tools/assert" ) // NewMockService creates a new mock whitelist service diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index cb0c5a0aae..091600d8b5 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -29,6 +29,9 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "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/ethash" "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 // 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 != "" { - 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 { switch config.PowMode { case ethash.ModeFake: diff --git a/eth/handler.go b/eth/handler.go index 96eb3dc7be..ab95f5f769 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -86,7 +86,7 @@ type handlerConfig struct { Network uint64 // Network identifier to adfvertise Sync downloader.SyncMode // Whether to snap or full sync 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 EthAPI *ethapi.PublicBlockChainAPI // EthAPI to interact diff --git a/eth/tracers/api_bor.go b/eth/tracers/api_bor.go new file mode 100644 index 0000000000..6ab1a4290a --- /dev/null +++ b/eth/tracers/api_bor.go @@ -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) +} diff --git a/go.mod b/go.mod index 176df53a40..1b452a67a1 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,9 @@ module github.com/ethereum/go-ethereum -go 1.16 +go 1.18 require ( 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/aws/aws-sdk-go-v2 v1.2.0 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/davecgh/go-spew v1.1.1 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/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48 github.com/edsrzf/mmap-go v1.0.0 github.com/fatih/color v1.7.0 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 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/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/snappy v0.0.4 github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa @@ -44,18 +39,15 @@ require ( github.com/imdario/mergo v0.3.11 github.com/influxdata/influxdb v1.8.3 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/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 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-isatty v0.0.12 github.com/mitchellh/cli v1.1.2 github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0 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/olekukonko/tablewriter v0.0.5 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/stretchr/testify v1.7.0 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/xsleonard/go-merkle v1.1.0 go.opentelemetry.io/otel v1.2.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc 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/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/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/protobuf v1.27.1 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 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 ) diff --git a/go.sum b/go.sum index ec2f200044..374ab3066e 100644 --- a/go.sum +++ b/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/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-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/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= 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/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/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= 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/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= 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/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/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 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/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.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.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.2.0/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.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.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.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/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/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.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= 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.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/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg= 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.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA= 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/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU= 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/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 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-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-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-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-20180807140117-3d87b88a115f/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-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-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= 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-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.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.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= 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-20180811021610-c39426892332/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-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-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-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-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-20190226205417-e64efc72b421/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-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-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-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-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= 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-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.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= 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-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-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-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-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 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.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 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/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/integration-tests/smoke_test.sh b/integration-tests/smoke_test.sh new file mode 100644 index 0000000000..6f41aa5c16 --- /dev/null +++ b/integration-tests/smoke_test.sh @@ -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!" \ No newline at end of file diff --git a/internal/cli/account.go b/internal/cli/account.go index b8661821d0..bb8b30b892 100644 --- a/internal/cli/account.go +++ b/internal/cli/account.go @@ -1,11 +1,28 @@ package cli -import "github.com/mitchellh/cli" +import ( + "strings" + + "github.com/mitchellh/cli" +) type Account struct { 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 func (a *Account) Help() string { return `Usage: bor account diff --git a/internal/cli/account_import.go b/internal/cli/account_import.go index 8c9ff40e58..a3f65ab512 100644 --- a/internal/cli/account_import.go +++ b/internal/cli/account_import.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "strings" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/crypto" @@ -12,6 +13,17 @@ type AccountImportCommand struct { *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 func (a *AccountImportCommand) Help() string { return `Usage: bor account import @@ -47,7 +59,9 @@ func (a *AccountImportCommand) Run(args []string) int { a.UI.Error("Expected one argument") return 1 } + key, err := crypto.LoadECDSA(args[0]) + if err != nil { a.UI.Error(fmt.Sprintf("Failed to load the private key '%s': %v", args[0], err)) return 1 @@ -69,6 +83,8 @@ func (a *AccountImportCommand) Run(args []string) int { if err != nil { utils.Fatalf("Could not create the account: %v", err) } + a.UI.Output(fmt.Sprintf("Account created: %s", acct.Address.String())) + return 0 } diff --git a/internal/cli/account_list.go b/internal/cli/account_list.go index 360d41b558..854934c447 100644 --- a/internal/cli/account_list.go +++ b/internal/cli/account_list.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "strings" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/internal/cli/flagset" @@ -11,6 +12,17 @@ type AccountListCommand struct { *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 func (a *AccountListCommand) Help() string { 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)) return 1 } + a.UI.Output(formatAccounts(keystore.Accounts())) + return 0 } @@ -53,10 +67,12 @@ func formatAccounts(accts []accounts.Account) string { rows := make([]string, len(accts)+1) rows[0] = "Index|Address" + for i, d := range accts { rows[i+1] = fmt.Sprintf("%d|%s", i, d.Address.String()) } + return formatList(rows) } diff --git a/internal/cli/account_new.go b/internal/cli/account_new.go index 3334384cb0..aef272a389 100644 --- a/internal/cli/account_new.go +++ b/internal/cli/account_new.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "strings" "github.com/ethereum/go-ethereum/internal/cli/flagset" ) @@ -10,6 +11,17 @@ type AccountNewCommand struct { *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 func (a *AccountNewCommand) Help() string { return `Usage: bor account new diff --git a/internal/cli/attach.go b/internal/cli/attach.go new file mode 100644 index 0000000000..134a282180 --- /dev/null +++ b/internal/cli/attach.go @@ -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 + + 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 +} diff --git a/internal/cli/bootnode.go b/internal/cli/bootnode.go new file mode 100644 index 0000000000..9e1a0fcde9 --- /dev/null +++ b/internal/cli/bootnode.go @@ -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 (:)", + 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:)", + 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 +} diff --git a/internal/cli/bor_fingerprint.go b/internal/cli/bor_fingerprint.go new file mode 100644 index 0000000000..4e21f02956 --- /dev/null +++ b/internal/cli/bor_fingerprint.go @@ -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 +} diff --git a/internal/cli/chain.go b/internal/cli/chain.go index b43f22f999..9a7e9e8537 100644 --- a/internal/cli/chain.go +++ b/internal/cli/chain.go @@ -1,6 +1,8 @@ package cli import ( + "strings" + "github.com/mitchellh/cli" ) @@ -9,6 +11,18 @@ type ChainCommand struct { 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 func (c *ChainCommand) Help() string { return `Usage: bor chain diff --git a/internal/cli/chain_sethead.go b/internal/cli/chain_sethead.go index 127ac38f15..718ada4648 100644 --- a/internal/cli/chain_sethead.go +++ b/internal/cli/chain_sethead.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strconv" + "strings" "github.com/ethereum/go-ethereum/internal/cli/flagset" "github.com/ethereum/go-ethereum/internal/cli/server/proto" @@ -16,6 +17,19 @@ type ChainSetHeadCommand struct { yes bool } +// MarkDown implements cli.MarkDown interface +func (a *ChainSetHeadCommand) MarkDown() string { + items := []string{ + "# Chain sethead", + "The ```chain sethead ``` 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 func (c *ChainSetHeadCommand) Help() string { return `Usage: bor chain sethead [--yes] @@ -32,6 +46,7 @@ func (c *ChainSetHeadCommand) Flags() *flagset.Flagset { Default: false, Value: &c.yes, }) + return flags } @@ -75,6 +90,7 @@ func (c *ChainSetHeadCommand) Run(args []string) int { c.UI.Error(err.Error()) return 1 } + if response != "y" { c.UI.Output("set head aborted") return 0 @@ -87,5 +103,6 @@ func (c *ChainSetHeadCommand) Run(args []string) int { } c.UI.Output("Done!") + return 0 } diff --git a/internal/cli/chain_watch.go b/internal/cli/chain_watch.go index 9469c1df00..17a65a8d99 100644 --- a/internal/cli/chain_watch.go +++ b/internal/cli/chain_watch.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "os/signal" + "strings" "syscall" "github.com/ethereum/go-ethereum/core" @@ -17,6 +18,16 @@ type ChainWatchCommand struct { *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 func (c *ChainWatchCommand) Help() string { return `Usage: bor chain watch @@ -60,7 +71,10 @@ func (c *ChainWatchCommand) Run(args []string) int { go func() { <-signalCh - sub.CloseSend() + + if err := sub.CloseSend(); err != nil { + c.UI.Error(err.Error()) + } }() for { @@ -70,6 +84,7 @@ func (c *ChainWatchCommand) Run(args []string) int { c.UI.Output(err.Error()) break } + c.UI.Output(formatHeadEvent(msg)) } @@ -85,5 +100,6 @@ func formatHeadEvent(msg *proto.ChainWatchResponse) string { } else if msg.Type == core.Chain2HeadReorgEvent { out = fmt.Sprintf("Reorg Detected \nAdded : %v \nRemoved : %v", msg.Newchain, msg.Oldchain) } + return out } diff --git a/internal/cli/command.go b/internal/cli/command.go index d164791f80..1ff95b410f 100644 --- a/internal/cli/command.go +++ b/internal/cli/command.go @@ -9,18 +9,43 @@ import ( "github.com/ethereum/go-ethereum/internal/cli/server" "github.com/ethereum/go-ethereum/internal/cli/server/proto" "github.com/ethereum/go-ethereum/node" + "github.com/mitchellh/cli" "github.com/ryanuber/columnize" "google.golang.org/grpc" ) +const ( + emptyPlaceHolder = "" +) + +type MarkDownCommand interface { + MarkDown + cli.Command +} + +type MarkDownCommandFactory func() (MarkDownCommand, error) + 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{ Name: "bor", Args: args, - Commands: commands, + Commands: mappedCommands, } exitCode, err := cli.Run() @@ -28,10 +53,11 @@ func Run(args []string) int { fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error()) return 1 } + return exitCode } -func commands() map[string]cli.CommandFactory { +func Commands() map[string]MarkDownCommandFactory { ui := &cli.BasicUi{ Reader: os.Stdin, Writer: os.Stdout, @@ -44,87 +70,115 @@ func commands() map[string]cli.CommandFactory { meta := &Meta{ UI: ui, } - return map[string]cli.CommandFactory{ - "server": func() (cli.Command, error) { + + return map[string]MarkDownCommandFactory{ + "server": func() (MarkDownCommand, error) { return &server.Command{ UI: ui, }, nil }, - "version": func() (cli.Command, error) { + "version": func() (MarkDownCommand, error) { return &VersionCommand{ UI: ui, }, nil }, - "debug": func() (cli.Command, error) { + "debug": func() (MarkDownCommand, error) { return &DebugCommand{ + UI: ui, + }, nil + }, + "debug pprof": func() (MarkDownCommand, error) { + return &DebugPprofCommand{ Meta2: meta2, }, nil }, - "chain": func() (cli.Command, error) { + "debug block": func() (MarkDownCommand, error) { + return &DebugBlockCommand{ + Meta2: meta2, + }, nil + }, + "chain": func() (MarkDownCommand, error) { return &ChainCommand{ UI: ui, }, nil }, - "chain watch": func() (cli.Command, error) { + "chain watch": func() (MarkDownCommand, error) { return &ChainWatchCommand{ Meta2: meta2, }, nil }, - "chain sethead": func() (cli.Command, error) { + "chain sethead": func() (MarkDownCommand, error) { return &ChainSetHeadCommand{ Meta2: meta2, }, nil }, - "account": func() (cli.Command, error) { + "account": func() (MarkDownCommand, error) { return &Account{ UI: ui, }, nil }, - "account new": func() (cli.Command, error) { + "account new": func() (MarkDownCommand, error) { return &AccountNewCommand{ Meta: meta, }, nil }, - "account import": func() (cli.Command, error) { + "account import": func() (MarkDownCommand, error) { return &AccountImportCommand{ Meta: meta, }, nil }, - "account list": func() (cli.Command, error) { + "account list": func() (MarkDownCommand, error) { return &AccountListCommand{ Meta: meta, }, nil }, - "peers": func() (cli.Command, error) { + "peers": func() (MarkDownCommand, error) { return &PeersCommand{ UI: ui, }, nil }, - "peers add": func() (cli.Command, error) { + "peers add": func() (MarkDownCommand, error) { return &PeersAddCommand{ Meta2: meta2, }, nil }, - "peers remove": func() (cli.Command, error) { + "peers remove": func() (MarkDownCommand, error) { return &PeersRemoveCommand{ Meta2: meta2, }, nil }, - "peers list": func() (cli.Command, error) { + "peers list": func() (MarkDownCommand, error) { return &PeersListCommand{ Meta2: meta2, }, nil }, - "peers status": func() (cli.Command, error) { + "peers status": func() (MarkDownCommand, error) { return &PeersStatusCommand{ Meta2: meta2, }, nil }, - "status": func() (cli.Command, error) { + "status": func() (MarkDownCommand, error) { return &StatusCommand{ Meta2: meta2, }, 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", Default: "127.0.0.1:3131", }) + return f } @@ -151,6 +206,7 @@ func (m *Meta2) Conn() (*grpc.ClientConn, error) { if err != nil { return nil, fmt.Errorf("failed to connect to server: %v", err) } + return conn, nil } @@ -159,6 +215,7 @@ func (m *Meta2) BorConn() (proto.BorClient, error) { if err != nil { return nil, err } + return proto.NewBorClient(conn), nil } @@ -206,18 +263,21 @@ func (m *Meta) GetKeystore() (*keystore.KeyStore, error) { scryptP := keystore.StandardScryptP keys := keystore.NewKeyStore(keydir, scryptN, scryptP) + return keys, nil } func formatList(in []string) string { columnConf := columnize.DefaultConfig() - columnConf.Empty = "" + columnConf.Empty = emptyPlaceHolder + return columnize.Format(in, columnConf) } func formatKV(in []string) string { columnConf := columnize.DefaultConfig() - columnConf.Empty = "" + columnConf.Empty = emptyPlaceHolder columnConf.Glue = " = " + return columnize.Format(in, columnConf) } diff --git a/internal/cli/debug.go b/internal/cli/debug.go index a6b6ff7973..6e083a6974 100644 --- a/internal/cli/debug.go +++ b/internal/cli/debug.go @@ -1,11 +1,8 @@ package cli -// Based on https://github.com/hashicorp/nomad/blob/main/command/operator_debug.go - import ( "archive/tar" "compress/gzip" - "context" "fmt" "io" "io/ioutil" @@ -16,194 +13,187 @@ import ( "syscall" "time" - "github.com/ethereum/go-ethereum/internal/cli/flagset" + "github.com/mitchellh/cli" + "github.com/ethereum/go-ethereum/internal/cli/server/proto" - "github.com/golang/protobuf/jsonpb" - gproto "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/empty" + + "github.com/golang/protobuf/jsonpb" // nolint:staticcheck + gproto "github.com/golang/protobuf/proto" // nolint:staticcheck grpc_net_conn "github.com/mitchellh/go-grpc-net-conn" + "google.golang.org/grpc" + "google.golang.org/protobuf/runtime/protoiface" ) +// DebugCommand is the command to group the peers commands type DebugCommand struct { - *Meta2 + UI cli.Ui +} - seconds uint64 - output string +// MarkDown implements cli.MarkDown interface +func (d *DebugCommand) MarkDown() string { + examples := []string{ + "## Examples", + "By default it creates a tar.gz file with the output:", + CodeBlock([]string{ + "$ bor debug", + "Starting debugger...\n", + "Created debug archive: bor-debug-2021-10-26-073819Z.tar.gz", + }), + "Send the output to a specific directory:", + CodeBlock([]string{ + "$ bor debug --output data", + "Starting debugger...\n", + "Created debug directory: data/bor-debug-2021-10-26-075437Z", + }), + } + + items := []string{ + "# Debug", + "The ```bor debug``` command takes a debug dump of the running client.", + "- [```bor debug pprof```](./debug_pprof.md): Dumps bor pprof traces.", + "- [```bor debug block ```](./debug_block.md): Dumps bor block traces.", + } + items = append(items, examples...) + + return strings.Join(items, "\n\n") } // Help implements the cli.Command interface -func (d *DebugCommand) Help() string { - return `Usage: bor debug +func (c *DebugCommand) Help() string { + return `Usage: bor debug - Build an archive containing Bor pprof traces + This command takes a debug dump of the running client. + + Get the pprof traces: - ` + d.Flags().Help() -} + $ bor debug pprof -func (d *DebugCommand) Flags() *flagset.Flagset { - flags := d.NewFlagSet("debug") + Get the block traces: - flags.Uint64Flag(&flagset.Uint64Flag{ - Name: "seconds", - Usage: "seconds to trace", - Value: &d.seconds, - Default: 2, - }) - flags.StringFlag(&flagset.StringFlag{ - Name: "output", - Value: &d.output, - Usage: "Output directory", - }) - - return flags + $ bor debug block ` } // Synopsis implements the cli.Command interface -func (d *DebugCommand) Synopsis() string { - return "Build an archive containing Bor pprof traces" +func (c *DebugCommand) Synopsis() string { + return "Get traces of the running client" } // Run implements the cli.Command interface -func (d *DebugCommand) Run(args []string) int { - flags := d.Flags() - if err := flags.Parse(args); err != nil { - d.UI.Error(err.Error()) - return 1 - } +func (c *DebugCommand) Run(args []string) int { + return cli.RunResultHelp +} - clt, err := d.BorConn() - if err != nil { - d.UI.Error(err.Error()) - return 1 - } +type debugEnv struct { + output string + prefix string - stamped := "bor-debug-" + time.Now().UTC().Format("2006-01-02-150405Z") + name string + dst string +} + +func (d *debugEnv) init() error { + d.name = d.prefix + time.Now().UTC().Format("2006-01-02-150405Z") + + var err error // Create the output directory var tmp string if d.output != "" { // User specified output directory - tmp = filepath.Join(d.output, stamped) + tmp = filepath.Join(d.output, d.name) _, err := os.Stat(tmp) + if !os.IsNotExist(err) { - d.UI.Error("Output directory already exists") - return 1 + return fmt.Errorf("output directory already exists") } } else { // Generate temp directory - tmp, err = ioutil.TempDir(os.TempDir(), stamped) + tmp, err = ioutil.TempDir(os.TempDir(), d.name) if err != nil { - d.UI.Error(fmt.Sprintf("Error creating tmp directory: %s", err.Error())) - return 1 + return fmt.Errorf("error creating tmp directory: %s", err.Error()) } - defer os.RemoveAll(tmp) } - d.UI.Output("Starting debugger...") - d.UI.Output("") - // ensure destine folder exists if err := os.MkdirAll(tmp, os.ModePerm); err != nil { - d.UI.Error(fmt.Sprintf("failed to create parent directory: %v", err)) - return 1 + return fmt.Errorf("failed to create parent directory: %v", err) } - pprofProfile := func(ctx context.Context, profile string, filename string) error { - req := &proto.PprofRequest{ - Seconds: int64(d.seconds), - } - switch profile { - case "cpu": - req.Type = proto.PprofRequest_CPU - case "trace": - req.Type = proto.PprofRequest_TRACE - default: - req.Type = proto.PprofRequest_LOOKUP - req.Profile = profile - } - stream, err := clt.Pprof(ctx, req) - if err != nil { - return err - } - // wait for open request - msg, err := stream.Recv() - if err != nil { - return err - } - if _, ok := msg.Event.(*proto.PprofResponse_Open_); !ok { - return fmt.Errorf("expected open message") - } + d.dst = tmp - // create the stream - conn := &grpc_net_conn.Conn{ - Stream: stream, - Response: &proto.PprofResponse_Input{}, - Decode: grpc_net_conn.SimpleDecoder(func(msg gproto.Message) *[]byte { - return &msg.(*proto.PprofResponse_Input).Data - }), - } + return nil +} - file, err := os.OpenFile(filepath.Join(tmp, filename+".prof"), os.O_RDWR|os.O_CREATE, 0644) - if err != nil { - return err - } - defer file.Close() +func (d *debugEnv) tarName() string { + return d.name + ".tar.gz" +} - if _, err := io.Copy(file, conn); err != nil { - return err - } +func (d *debugEnv) finish() error { + // Exit before archive if output directory was specified + if d.output != "" { return nil } - ctx, cancelFn := context.WithCancel(context.Background()) - trapSignal(cancelFn) - - profiles := map[string]string{ - "heap": "heap", - "cpu": "cpu", - "trace": "trace", - } - for profile, filename := range profiles { - if err := pprofProfile(ctx, profile, filename); err != nil { - d.UI.Error(fmt.Sprintf("Error creating profile '%s': %v", profile, err)) - return 1 - } - } - - // append the status - { - statusResp, err := clt.Status(ctx, &empty.Empty{}) - if err != nil { - d.UI.Output(fmt.Sprintf("Failed to get status: %v", err)) - return 1 - } - m := jsonpb.Marshaler{} - data, err := m.MarshalToString(statusResp) - if err != nil { - d.UI.Output(err.Error()) - return 1 - } - if err := ioutil.WriteFile(filepath.Join(tmp, "status.json"), []byte(data), 0644); err != nil { - d.UI.Output(fmt.Sprintf("Failed to write status: %v", err)) - return 1 - } - } - - // Exit before archive if output directory was specified - if d.output != "" { - d.UI.Output(fmt.Sprintf("Created debug directory: %s", tmp)) - return 0 - } - // Create archive tarball - archiveFile := stamped + ".tar.gz" - if err = tarCZF(archiveFile, tmp, stamped); err != nil { - d.UI.Error(fmt.Sprintf("Error creating archive: %s", err.Error())) - return 1 + archiveFile := d.tarName() + if err := tarCZF(archiveFile, d.dst, d.name); err != nil { + return fmt.Errorf("error creating archive: %s", err.Error()) } - d.UI.Output(fmt.Sprintf("Created debug archive: %s", archiveFile)) - return 0 + return nil +} + +type debugStream interface { + Recv() (*proto.DebugFileResponse, error) + grpc.ClientStream +} + +func (d *debugEnv) writeFromStream(name string, stream debugStream) error { + // wait for open request + msg, err := stream.Recv() + if err != nil { + return err + } + + if _, ok := msg.Event.(*proto.DebugFileResponse_Open_); !ok { + return fmt.Errorf("expected open message") + } + + // create the stream + conn := &grpc_net_conn.Conn{ + Stream: stream, + Response: &proto.DebugFileResponse_Input{}, + Decode: grpc_net_conn.SimpleDecoder(func(msg gproto.Message) *[]byte { + return &msg.(*proto.DebugFileResponse_Input).Data + }), + } + + file, err := os.OpenFile(filepath.Join(d.dst, name), os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return err + } + defer file.Close() + + if _, err := io.Copy(file, conn); err != nil { + return err + } + + return nil +} + +func (d *debugEnv) writeJSON(name string, msg protoiface.MessageV1) error { + m := jsonpb.Marshaler{} + data, err := m.MarshalToString(msg) + + if err != nil { + return err + } + + if err := ioutil.WriteFile(filepath.Join(d.dst, name), []byte(data), 0600); err != nil { + return fmt.Errorf("failed to write status: %v", err) + } + + return nil } func trapSignal(cancel func()) { diff --git a/internal/cli/debug_block.go b/internal/cli/debug_block.go new file mode 100644 index 0000000000..5a282cc550 --- /dev/null +++ b/internal/cli/debug_block.go @@ -0,0 +1,126 @@ +package cli + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/internal/cli/flagset" + "github.com/ethereum/go-ethereum/internal/cli/server/proto" +) + +// DebugBlockCommand is the command to group the peers commands +type DebugBlockCommand struct { + *Meta2 + + output string +} + +func (p *DebugBlockCommand) MarkDown() string { + items := []string{ + "# Debug trace", + "The ```bor debug block ``` command will create an archive containing traces of a bor block.", + p.Flags().MarkDown(), + } + + return strings.Join(items, "\n\n") +} + +// Help implements the cli.Command interface +func (c *DebugBlockCommand) Help() string { + return `Usage: bor debug block + + This command is used get traces of a bor block` +} + +func (c *DebugBlockCommand) Flags() *flagset.Flagset { + flags := c.NewFlagSet("trace") + + flags.StringFlag(&flagset.StringFlag{ + Name: "output", + Value: &c.output, + Usage: "Output directory", + }) + + return flags +} + +// Synopsis implements the cli.Command interface +func (c *DebugBlockCommand) Synopsis() string { + return "Get trace of a bor block" +} + +// Run implements the cli.Command interface +func (c *DebugBlockCommand) Run(args []string) int { + flags := c.Flags() + + var number *int64 = nil + + // parse the block number (if available) + if len(args)%2 != 0 { + num, err := strconv.ParseInt(args[0], 10, 64) + if err == nil { + number = &num + } + + args = args[1:] + } + // parse output directory + if err := flags.Parse(args); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + borClt, err := c.BorConn() + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + + dEnv := &debugEnv{ + output: c.output, + prefix: "bor-block-trace-", + } + if err := dEnv.init(); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + c.UI.Output("Starting block tracer...") + c.UI.Output("") + + // create a debug block request + var debugRequest *proto.DebugBlockRequest = &proto.DebugBlockRequest{} + if number != nil { + debugRequest.Number = *number + } else { + debugRequest.Number = -1 + } + + // send the request + // receives a grpc stream of debug block response + stream, err := borClt.DebugBlock(context.Background(), debugRequest) + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + + if err := dEnv.writeFromStream("block.json", stream); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + if err := dEnv.finish(); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + if c.output != "" { + c.UI.Output(fmt.Sprintf("Created debug directory: %s", dEnv.dst)) + } else { + c.UI.Output(fmt.Sprintf("Created block trace archive: %s", dEnv.tarName())) + } + + return 0 +} diff --git a/internal/cli/debug_pprof.go b/internal/cli/debug_pprof.go new file mode 100644 index 0000000000..ef15e45b58 --- /dev/null +++ b/internal/cli/debug_pprof.go @@ -0,0 +1,159 @@ +package cli + +// Based on https://github.com/hashicorp/nomad/blob/main/command/operator_debug.go + +import ( + "context" + "fmt" + "strings" + + "github.com/golang/protobuf/ptypes/empty" + + "github.com/ethereum/go-ethereum/internal/cli/flagset" + "github.com/ethereum/go-ethereum/internal/cli/server/proto" +) + +type DebugPprofCommand struct { + *Meta2 + + seconds uint64 + output string +} + +func (p *DebugPprofCommand) MarkDown() string { + items := []string{ + "# Debug Pprof", + "The ```debug pprof ``` command will create an archive containing bor pprof traces.", + p.Flags().MarkDown(), + } + + return strings.Join(items, "\n\n") +} + +// Help implements the cli.Command interface +func (d *DebugPprofCommand) Help() string { + return `Usage: bor debug + + Build an archive containing Bor pprof traces + + ` + d.Flags().Help() +} + +func (d *DebugPprofCommand) Flags() *flagset.Flagset { + flags := d.NewFlagSet("debug") + + flags.Uint64Flag(&flagset.Uint64Flag{ + Name: "seconds", + Usage: "seconds to trace", + Value: &d.seconds, + Default: 2, + }) + flags.StringFlag(&flagset.StringFlag{ + Name: "output", + Value: &d.output, + Usage: "Output directory", + }) + + return flags +} + +// Synopsis implements the cli.Command interface +func (d *DebugPprofCommand) Synopsis() string { + return "Build an archive containing Bor pprof traces" +} + +// Run implements the cli.Command interface +func (d *DebugPprofCommand) Run(args []string) int { + flags := d.Flags() + if err := flags.Parse(args); err != nil { + d.UI.Error(err.Error()) + return 1 + } + + clt, err := d.BorConn() + if err != nil { + d.UI.Error(err.Error()) + return 1 + } + + dEnv := &debugEnv{ + output: d.output, + prefix: "bor-debug-", + } + if err := dEnv.init(); err != nil { + d.UI.Error(err.Error()) + return 1 + } + + d.UI.Output("Starting debugger...") + d.UI.Output("") + + pprofProfile := func(ctx context.Context, profile string, filename string) error { + req := &proto.DebugPprofRequest{ + Seconds: int64(d.seconds), + } + + switch profile { + case "cpu": + req.Type = proto.DebugPprofRequest_CPU + case "trace": + req.Type = proto.DebugPprofRequest_TRACE + default: + req.Type = proto.DebugPprofRequest_LOOKUP + req.Profile = profile + } + + stream, err := clt.DebugPprof(ctx, req) + + if err != nil { + return err + } + + if err := dEnv.writeFromStream(filename+".prof", stream); err != nil { + return err + } + + return nil + } + + ctx, cancelFn := context.WithCancel(context.Background()) + trapSignal(cancelFn) + + profiles := map[string]string{ + "heap": "heap", + "cpu": "cpu", + "trace": "trace", + } + for profile, filename := range profiles { + if err := pprofProfile(ctx, profile, filename); err != nil { + d.UI.Error(fmt.Sprintf("Error creating profile '%s': %v", profile, err)) + return 1 + } + } + + // append the status + { + statusResp, err := clt.Status(ctx, &empty.Empty{}) + if err != nil { + d.UI.Output(fmt.Sprintf("Failed to get status: %v", err)) + return 1 + } + if err := dEnv.writeJSON("status.json", statusResp); err != nil { + d.UI.Error(err.Error()) + return 1 + } + } + + if err := dEnv.finish(); err != nil { + d.UI.Error(err.Error()) + return 1 + } + + if d.output != "" { + d.UI.Output(fmt.Sprintf("Created debug directory: %s", dEnv.dst)) + } else { + d.UI.Output(fmt.Sprintf("Created debug archive: %s", dEnv.tarName())) + } + + return 0 +} diff --git a/internal/cli/debug_test.go b/internal/cli/debug_test.go new file mode 100644 index 0000000000..f77cf839ac --- /dev/null +++ b/internal/cli/debug_test.go @@ -0,0 +1,112 @@ +package cli + +import ( + "os" + "path" + "strconv" + "testing" + "time" + + "github.com/mitchellh/cli" + "github.com/stretchr/testify/assert" + + "github.com/ethereum/go-ethereum/internal/cli/server" +) + +var currentDir string = "" + +func TestCommand_DebugBlock(t *testing.T) { + t.Parallel() + + // Start a blockchain in developer mode and get trace of block + config := server.DefaultConfig() + + // enable developer mode + config.Developer.Enabled = true + config.Developer.Period = 2 // block time + + // enable archive mode for getting traces of ancient blocks + config.GcMode = "archive" + + // start the mock server + srv, err := server.CreateMockServer(config) + assert.NoError(t, err) + + defer server.CloseMockServer(srv) + + // get the grpc port + port := srv.GetGrpcAddr() + + // wait for 4 seconds to mine a 2 blocks + time.Sleep(2 * time.Duration(config.Developer.Period) * time.Second) + + // add prefix for debug trace + prefix := "bor-block-trace-" + + // output dir + output := "debug_block_test" + + // set current directory + currentDir, _ = os.Getwd() + + // trace 1st block + start := time.Now() + dst1 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json") + res := traceBlock(port, 1, output) + assert.Equal(t, 0, res) + t.Logf("Completed trace of block %d in %d ms at %s", 1, time.Since(start).Milliseconds(), dst1) + + // adding this to avoid debug directory name conflicts + time.Sleep(time.Second) + + // trace last/recent block + start = time.Now() + latestBlock := srv.GetLatestBlockNumber().Int64() + dst2 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json") + res = traceBlock(port, latestBlock, output) + assert.Equal(t, 0, res) + t.Logf("Completed trace of block %d in %d ms at %s", latestBlock, time.Since(start).Milliseconds(), dst2) + + // verify if the trace files are created + done := verify(dst1) + assert.Equal(t, true, done) + done = verify(dst2) + assert.Equal(t, true, done) + + // delete the traces + deleteTraces(output) +} + +// traceBlock calls the cli command to trace a block +func traceBlock(port string, number int64, output string) int { + ui := cli.NewMockUi() + command := &DebugBlockCommand{ + Meta2: &Meta2{ + UI: ui, + addr: "127.0.0.1:" + port, + }, + } + + // run trace (by explicitly passing the output directory and grpc address) + return command.Run([]string{strconv.FormatInt(number, 10), "--output", output, "--address", command.Meta2.addr}) +} + +// verify checks if the trace file is created at the destination +// directory or not +func verify(dst string) bool { + dst = path.Join(currentDir, dst) + if file, err := os.Stat(dst); err == nil { + // check if the file has content + if file.Size() > 0 { + return true + } + } + + return false +} + +// deleteTraces removes the traces created during the test +func deleteTraces(dst string) { + dst = path.Join(currentDir, dst) + os.RemoveAll(dst) +} diff --git a/internal/cli/flagset/flagset.go b/internal/cli/flagset/flagset.go index 4388dd03fc..b57fff9996 100644 --- a/internal/cli/flagset/flagset.go +++ b/internal/cli/flagset/flagset.go @@ -4,6 +4,7 @@ import ( "flag" "fmt" "math/big" + "sort" "strings" "time" ) @@ -18,12 +19,14 @@ func NewFlagSet(name string) *Flagset { flags: []*FlagVar{}, set: flag.NewFlagSet(name, flag.ContinueOnError), } + return f } type FlagVar struct { Name string Usage string + Group string } func (f *Flagset) addFlag(fl *FlagVar) { @@ -32,13 +35,54 @@ func (f *Flagset) addFlag(fl *FlagVar) { func (f *Flagset) Help() string { str := "Options:\n\n" + items := []string{} for _, item := range f.flags { items = append(items, fmt.Sprintf(" -%s\n %s", item.Name, item.Usage)) } + return str + strings.Join(items, "\n\n") } +// MarkDown implements cli.MarkDown interface +func (f *Flagset) MarkDown() string { + if len(f.flags) == 0 { + return "" + } + + groups := make(map[string][]*FlagVar) + + for _, item := range f.flags { + groups[item.Group] = append(groups[item.Group], item) + } + + i := 0 + keys := make([]string, len(groups)) + + for k := range groups { + keys[i] = k + i++ + } + + sort.Strings(keys) + + items := []string{} + + for _, k := range keys { + if k == "" { + items = append(items, "## Options") + } else { + items = append(items, fmt.Sprintf("### %s Options", k)) + } + + for _, item := range groups[k] { + items = append(items, fmt.Sprintf("- ```%s```: %s", item.Name, item.Usage)) + } + } + + return strings.Join(items, "\n\n") +} + func (f *Flagset) Parse(args []string) error { return f.set.Parse(args) } @@ -52,12 +96,14 @@ type BoolFlag struct { Usage string Default bool Value *bool + Group string } func (f *Flagset) BoolFlag(b *BoolFlag) { f.addFlag(&FlagVar{ Name: b.Name, Usage: b.Usage, + Group: b.Group, }) f.set.BoolVar(b.Value, b.Name, b.Default, b.Usage) } @@ -67,12 +113,14 @@ type StringFlag struct { Usage string Default string Value *string + Group string } func (f *Flagset) StringFlag(b *StringFlag) { f.addFlag(&FlagVar{ Name: b.Name, Usage: b.Usage, + Group: b.Group, }) f.set.StringVar(b.Value, b.Name, b.Default, b.Usage) } @@ -82,12 +130,14 @@ type IntFlag struct { Usage string Value *int Default int + Group string } func (f *Flagset) IntFlag(i *IntFlag) { f.addFlag(&FlagVar{ Name: i.Name, Usage: i.Usage, + Group: i.Group, }) f.set.IntVar(i.Value, i.Name, i.Default, i.Usage) } @@ -97,12 +147,14 @@ type Uint64Flag struct { Usage string Value *uint64 Default uint64 + Group string } func (f *Flagset) Uint64Flag(i *Uint64Flag) { f.addFlag(&FlagVar{ Name: i.Name, Usage: i.Usage, + Group: i.Group, }) f.set.Uint64Var(i.Value, i.Name, i.Default, i.Usage) } @@ -111,12 +163,14 @@ type BigIntFlag struct { Name string Usage string Value *big.Int + Group string } func (b *BigIntFlag) String() string { if b.Value == nil { return "" } + return b.Value.String() } @@ -129,10 +183,12 @@ func (b *BigIntFlag) Set(value string) error { } else { num, ok = num.SetString(value, 10) } + if !ok { return fmt.Errorf("failed to set big int") } b.Value = num + return nil } @@ -140,6 +196,7 @@ func (f *Flagset) BigIntFlag(b *BigIntFlag) { f.addFlag(&FlagVar{ Name: b.Name, Usage: b.Usage, + Group: b.Group, }) f.set.Var(b, b.Name, b.Usage) } @@ -148,17 +205,20 @@ type SliceStringFlag struct { Name string Usage string Value *[]string + Group string } func (i *SliceStringFlag) String() string { if i.Value == nil { return "" } + return strings.Join(*i.Value, ",") } func (i *SliceStringFlag) Set(value string) error { *i.Value = append(*i.Value, strings.Split(value, ",")...) + return nil } @@ -166,6 +226,7 @@ func (f *Flagset) SliceStringFlag(s *SliceStringFlag) { f.addFlag(&FlagVar{ Name: s.Name, Usage: s.Usage, + Group: s.Group, }) f.set.Var(s, s.Name, s.Usage) } @@ -175,12 +236,14 @@ type DurationFlag struct { Usage string Value *time.Duration Default time.Duration + Group string } func (f *Flagset) DurationFlag(d *DurationFlag) { f.addFlag(&FlagVar{ Name: d.Name, Usage: d.Usage, + Group: d.Group, }) f.set.DurationVar(d.Value, d.Name, d.Default, "") } @@ -189,16 +252,19 @@ type MapStringFlag struct { Name string Usage string Value *map[string]string + Group string } func (m *MapStringFlag) String() string { if m.Value == nil { return "" } + ls := []string{} for k, v := range *m.Value { ls = append(ls, k+"="+v) } + return strings.Join(ls, ",") } @@ -206,6 +272,7 @@ func (m *MapStringFlag) Set(value string) error { if m.Value == nil { m.Value = &map[string]string{} } + for _, t := range strings.Split(value, ",") { if t != "" { kv := strings.Split(t, "=") @@ -215,6 +282,7 @@ func (m *MapStringFlag) Set(value string) error { } } } + return nil } @@ -222,6 +290,7 @@ func (f *Flagset) MapStringFlag(m *MapStringFlag) { f.addFlag(&FlagVar{ Name: m.Name, Usage: m.Usage, + Group: m.Group, }) f.set.Var(m, m.Name, m.Usage) } @@ -231,12 +300,14 @@ type Float64Flag struct { Usage string Value *float64 Default float64 + Group string } func (f *Flagset) Float64Flag(i *Float64Flag) { f.addFlag(&FlagVar{ Name: i.Name, Usage: i.Usage, + Group: i.Group, }) f.set.Float64Var(i.Value, i.Name, i.Default, "") } diff --git a/internal/cli/markdown.go b/internal/cli/markdown.go new file mode 100644 index 0000000000..652c98e56b --- /dev/null +++ b/internal/cli/markdown.go @@ -0,0 +1,14 @@ +package cli + +import ( + "strings" +) + +type MarkDown interface { + MarkDown() string +} + +// Create a Markdown code block from a slice of string, where each string is a line of code +func CodeBlock(lines []string) string { + return "```\n" + strings.Join(lines, "\n") + "\n```" +} diff --git a/internal/cli/markdown_test.go b/internal/cli/markdown_test.go new file mode 100644 index 0000000000..30c272a220 --- /dev/null +++ b/internal/cli/markdown_test.go @@ -0,0 +1,20 @@ +package cli + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCodeBlock(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + lines := []string{ + "abc", + "bcd", + } + + expected := "```\n" + "abc\n" + "bcd\n" + "```" + assert.Equal(expected, CodeBlock(lines)) +} diff --git a/internal/cli/peers.go b/internal/cli/peers.go index b591366222..fbbca24fad 100644 --- a/internal/cli/peers.go +++ b/internal/cli/peers.go @@ -1,6 +1,8 @@ package cli import ( + "strings" + "github.com/mitchellh/cli" ) @@ -9,6 +11,20 @@ type PeersCommand struct { UI cli.Ui } +// MarkDown implements cli.MarkDown interface +func (a *PeersCommand) MarkDown() string { + items := []string{ + "# Peers", + "The ```peers``` command groups actions to interact with peers:", + "- [```peers add```](./peers_add.md): Joins the local client to another remote peer.", + "- [```peers list```](./peers_list.md): Lists the connected peers to the Bor client.", + "- [```peers remove```](./peers_remove.md): Disconnects the local client from a connected peer if exists.", + "- [```peers status```](./peers_status.md): Display the status of a peer by its id.", + } + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (c *PeersCommand) Help() string { return `Usage: bor peers diff --git a/internal/cli/peers_add.go b/internal/cli/peers_add.go index 2b2fe127e0..3df1a6b6cb 100644 --- a/internal/cli/peers_add.go +++ b/internal/cli/peers_add.go @@ -2,6 +2,7 @@ package cli import ( "context" + "strings" "github.com/ethereum/go-ethereum/internal/cli/flagset" "github.com/ethereum/go-ethereum/internal/cli/server/proto" @@ -14,6 +15,17 @@ type PeersAddCommand struct { trusted bool } +// MarkDown implements cli.MarkDown interface +func (p *PeersAddCommand) MarkDown() string { + items := []string{ + "# Peers add", + "The ```peers add ``` command joins the local client to another remote peer.", + p.Flags().MarkDown(), + } + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (p *PeersAddCommand) Help() string { return `Usage: bor peers add @@ -68,5 +80,6 @@ func (c *PeersAddCommand) Run(args []string) int { c.UI.Error(err.Error()) return 1 } + return 0 } diff --git a/internal/cli/peers_list.go b/internal/cli/peers_list.go index a42e0011a5..4a572447c1 100644 --- a/internal/cli/peers_list.go +++ b/internal/cli/peers_list.go @@ -14,6 +14,17 @@ type PeersListCommand struct { *Meta2 } +// MarkDown implements cli.MarkDown interface +func (p *PeersListCommand) MarkDown() string { + items := []string{ + "# Peers add", + "The ```peers list``` command lists the connected peers.", + p.Flags().MarkDown(), + } + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (p *PeersListCommand) Help() string { return `Usage: bor peers list @@ -50,12 +61,14 @@ func (c *PeersListCommand) Run(args []string) int { req := &proto.PeersListRequest{} resp, err := borClt.PeersList(context.Background(), req) + if err != nil { c.UI.Error(err.Error()) return 1 } c.UI.Output(formatPeers(resp.Peers)) + return 0 } @@ -66,6 +79,7 @@ func formatPeers(peers []*proto.Peer) string { rows := make([]string, len(peers)+1) rows[0] = "ID|Enode|Name|Caps|Static|Trusted" + for i, d := range peers { enode := strings.TrimPrefix(d.Enode, "enode://") @@ -77,5 +91,6 @@ func formatPeers(peers []*proto.Peer) string { d.Static, d.Trusted) } + return formatList(rows) } diff --git a/internal/cli/peers_remove.go b/internal/cli/peers_remove.go index 979f139251..f53284c40c 100644 --- a/internal/cli/peers_remove.go +++ b/internal/cli/peers_remove.go @@ -2,6 +2,7 @@ package cli import ( "context" + "strings" "github.com/ethereum/go-ethereum/internal/cli/flagset" "github.com/ethereum/go-ethereum/internal/cli/server/proto" @@ -14,6 +15,17 @@ type PeersRemoveCommand struct { trusted bool } +// MarkDown implements cli.MarkDown interface +func (p *PeersRemoveCommand) MarkDown() string { + items := []string{ + "# Peers remove", + "The ```peers remove ``` command disconnects the local client from a connected peer if exists.", + p.Flags().MarkDown(), + } + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (p *PeersRemoveCommand) Help() string { return `Usage: bor peers remove @@ -68,5 +80,6 @@ func (c *PeersRemoveCommand) Run(args []string) int { c.UI.Error(err.Error()) return 1 } + return 0 } diff --git a/internal/cli/peers_status.go b/internal/cli/peers_status.go index c1da2b2647..f5d700a273 100644 --- a/internal/cli/peers_status.go +++ b/internal/cli/peers_status.go @@ -14,6 +14,17 @@ type PeersStatusCommand struct { *Meta2 } +// MarkDown implements cli.MarkDown interface +func (p *PeersStatusCommand) MarkDown() string { + items := []string{ + "# Peers status", + "The ```peers status ``` command displays the status of a peer by its id.", + p.Flags().MarkDown(), + } + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (p *PeersStatusCommand) Help() string { return `Usage: bor peers status @@ -58,12 +69,14 @@ func (c *PeersStatusCommand) Run(args []string) int { Enode: args[0], } resp, err := borClt.PeersStatus(context.Background(), req) + if err != nil { c.UI.Error(err.Error()) return 1 } c.UI.Output(formatPeer(resp.Peer)) + return 0 } @@ -77,5 +90,6 @@ func formatPeer(peer *proto.Peer) string { fmt.Sprintf("Static|%v", peer.Static), fmt.Sprintf("Trusted|%v", peer.Trusted), }) + return base } diff --git a/internal/cli/server/chains/chain.go b/internal/cli/server/chains/chain.go index 05c12ef0b0..d6717f5893 100644 --- a/internal/cli/server/chains/chain.go +++ b/internal/cli/server/chains/chain.go @@ -1,8 +1,15 @@ package chains import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/log" ) type Chain struct { @@ -18,7 +25,61 @@ var chains = map[string]*Chain{ "mumbai": mumbaiTestnet, } -func GetChain(name string) (*Chain, bool) { - chain, ok := chains[name] - return chain, ok +func GetChain(name string) (*Chain, error) { + var ( + chain *Chain + err error + ) + + if _, fileErr := os.Stat(name); fileErr == nil { + if chain, err = ImportFromFile(name); err != nil { + return nil, fmt.Errorf("error importing chain from file: %v", err) + } + + return chain, nil + } else if errors.Is(fileErr, os.ErrNotExist) { + var ok bool + if chain, ok = chains[name]; !ok { + return nil, fmt.Errorf("chain %s not found", name) + } + + return chain, nil + } else { + return nil, fileErr + } +} + +func ImportFromFile(filename string) (*Chain, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + return importChain(data) +} + +func importChain(content []byte) (*Chain, error) { + var chain *Chain + + if err := json.Unmarshal(content, &chain); err != nil { + return nil, err + } + + if chain.Genesis == nil { + log.Info("Try reading as legacy genesis") + + var genesis core.Genesis + if err := json.Unmarshal(content, &genesis); err != nil { + return nil, err + } + + if genesis.Config != nil { + chain.Genesis = &genesis + chain.NetworkId = genesis.Config.ChainID.Uint64() + } else { + return nil, fmt.Errorf("unable to parse chain config") + } + } + + return chain, nil } diff --git a/internal/cli/server/chains/chain_test.go b/internal/cli/server/chains/chain_test.go new file mode 100644 index 0000000000..b372a3c4b9 --- /dev/null +++ b/internal/cli/server/chains/chain_test.go @@ -0,0 +1,54 @@ +package chains + +import ( + "testing" +) + +func TestChain_ImportFromFile(t *testing.T) { + t.Parallel() + + type args struct { + filename string + } + + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "ImportFromFile correct json file", + args: args{filename: "test_files/chain_test.json"}, + wantErr: false, + }, + { + name: "ImportFromFile correct legacy json file", + args: args{filename: "test_files/chain_legacy_test.json"}, + wantErr: false, + }, + { + name: "ImportFromFile wrong json file", + args: args{filename: "test_files/wrong_chain.json"}, + wantErr: true, + }, + { + name: "ImportFromFile nonexistent json file", + args: args{filename: "test_files/chain_test_nonexistent.json"}, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + _, err := ImportFromFile(tt.args.filename) + if (err != nil) != tt.wantErr { + t.Errorf("ImportFromFile() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} diff --git a/internal/cli/server/chains/test_files/chain_legacy_test.json b/internal/cli/server/chains/test_files/chain_legacy_test.json new file mode 100644 index 0000000000..5702eaca40 --- /dev/null +++ b/internal/cli/server/chains/test_files/chain_legacy_test.json @@ -0,0 +1,83 @@ +{ + "config":{ + "chainId":80001, + "homesteadBlock":0, + "daoForkSupport":true, + "eip150Block":0, + "eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":2722000, + "muirGlacierBlock":2722000, + "berlinBlock":13996000, + "londonBlock":13996000, + "bor":{ + "period":{ + "0":2 + }, + "producerDelay":6, + "sprint":64, + "backupMultiplier":{ + "0":2 + }, + "validatorContract":"0x0000000000000000000000000000000000001000", + "stateReceiverContract":"0x0000000000000000000000000000000000001001", + "overrideStateSyncRecords":null, + "blockAlloc":{ + "22244000":{ + "0000000000000000000000000000000000001010":{ + "balance":"0x0", + "code":"0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610caa565b005b3480156103eb57600080fd5b506103f4610dfc565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e05565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fc1565b005b3480156104e857600080fd5b506104f1611090565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b506105486110b6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506110dc565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b506106046110fd565b005b34801561061257600080fd5b5061061b6111cd565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506111d3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b50610758611358565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af611381565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de6113d8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e611411565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061144e565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b50610964611474565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b8101908080359060200190929190505050611501565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611521565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a65611541565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a90611548565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb61154e565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506115db565b005b348015610b2e57600080fd5b50610b376115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b60006040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b60003390506000610cba826110dc565b9050610cd18360065461161e90919063ffffffff16565b600681905550600083118015610ce657508234145b610d58576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610dd4876110dc565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610e0d611381565b610e1657600080fd5b600081118015610e535750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b610ea8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611da96023913960400191505060405180910390fd5b6000610eb3836110dc565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f19350505050158015610f00573d6000803e3d6000fd5b50610f168360065461163e90919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f68585610f98896110dc565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611027576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611d866023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061108c8261165d565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b611105611381565b61110e57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b60008060008060418551146111ee5760009350505050611352565b602085015192506040850151915060ff6041860151169050601b8160ff16101561121957601b810190505b601b8160ff16141580156112315750601c8160ff1614155b156112425760009350505050611352565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561129f573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561134e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b6000813414611460576000905061146e565b61146b338484611755565b90505b92915050565b6040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b602083106114c357805182526020820191506020810190506020830392506114a0565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061153761153286868686611b12565b611be8565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611dcc605291396040516020018082805190602001908083835b6020831061159d578051825260208201915060208101905060208303925061157a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b6115e3611381565b6115ec57600080fd5b6115f58161165d565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282111561162d57600080fd5b600082840390508091505092915050565b60008082840190508381101561165357600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561169757600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117d557600080fd5b505afa1580156117e9573d6000803e3d6000fd5b505050506040513d60208110156117ff57600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561189157600080fd5b505afa1580156118a5573d6000803e3d6000fd5b505050506040513d60208110156118bb57600080fd5b810190808051906020019092919050505090506118d9868686611c32565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156119e157600080fd5b505afa1580156119f5573d6000803e3d6000fd5b505050506040513d6020811015611a0b57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a9957600080fd5b505afa158015611aad573d6000803e3d6000fd5b505050506040513d6020811015611ac357600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b6000806040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b60208310611b645780518252602082019150602081019050602083039250611b41565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611cd4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611d1a573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820ccd6c2a9c259832bbb367986ee06cd87af23022681b0cb22311a864b701d939564736f6c63430005100032" + } + } + }, + "burntContract":{ + "22640000":"0x70bcA57F4579f58670aB2d18Ef16e02C17553C38" + }, + "jaipurBlock":22770000 + } + }, + "nonce":"0x0", + "timestamp":"0x5ce28211", + "extraData":"0x", + "gasLimit":"0x989680", + "difficulty":"0x1", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "0000000000000000000000000000000000001000":{ + "code":"0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a9190810190612b24565b610706565b60405161021e93929190613463565b60405180910390f35b610241600480360361023c9190810190612b24565b61075d565b60405161024f929190613284565b60405180910390f35b610272600480360361026d9190810190612b4d565b610939565b60405161027f91906132bb565b60405180910390f35b6102a2600480360361029d9190810190612c2c565b610a91565b005b6102be60048036036102b99190810190612b4d565b61112a565b6040516102cb91906132bb565b60405180910390f35b6102dc611281565b6040516102e99190613411565b60405180910390f35b61030c60048036036103079190810190612a81565b611286565b60405161031991906132d6565b60405180910390f35b61033c60048036036103379190810190612b24565b611307565b6040516103499190613411565b60405180910390f35b61035a611437565b6040516103679190613269565b60405180910390f35b61038a60048036036103859190810190612abd565b61144f565b60405161039791906132bb565b60405180910390f35b6103a861151a565b6040516103b591906132d6565b60405180910390f35b6103d860048036036103d39190810190612b89565b611531565b6040516103e59190613411565b60405180910390f35b61040860048036036104039190810190612b4d565b611619565b60405161041591906133f6565b60405180910390f35b610426611781565b6040516104339190613411565b60405180910390f35b61045660048036036104519190810190612a06565b611791565b60405161046391906132bb565b60405180910390f35b61048660048036036104819190810190612a2f565b6117ab565b60405161049391906132d6565b60405180910390f35b6104a4611829565b6040516104b393929190613463565b60405180910390f35b6104c461189d565b6040516104d2929190613284565b60405180910390f35b6104e3611b6e565b6040516104f09190613411565b60405180910390f35b610513600480360361050e9190810190612bf0565b611b73565b6040516105229392919061342c565b60405180910390f35b61054560048036036105409190810190612a06565b611bd7565b60405161055291906132bb565b60405180910390f35b610563611bf1565b60405161057091906132d6565b60405180910390f35b610593600480360361058e9190810190612b24565b611c08565b6040516105a09190613411565b60405180910390f35b6105b1611d39565b6040516105be91906132d6565b60405180910390f35b6105cf611d50565b6040516105de93929190613463565b60405180910390f35b61060160048036036105fc9190810190612b24565b611db1565b60405161060e9190613411565b60405180910390f35b61061f611eb1565b60405161062d929190613284565b60405180910390f35b610650600480360361064b9190810190612b24565b611ec5565b60405161065d9190613411565b60405180910390f35b61066e611ee6565b60405161067b919061349a565b60405180910390f35b61069e60048036036106999190810190612bf0565b611eeb565b6040516106ad9392919061342c565b60405180910390f35b6106be611f4f565b6040516106cb9190613411565b60405180910390f35b6106ee60048036036106e99190810190612b24565b611f61565b6040516106fd93929190613463565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611db1565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a906133d6565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b30611f8b565b5b610b456001826122ac90919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d90613356565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf906133b6565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1190613396565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90613336565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc390613376565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612800565b506000600160008a815260200190815260200160002081610d879190612800565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b60200260200101516122f9565b90506000808c81526020019081526020016000208054809190600101610e349190612800565b506040518060600160405280610e5d83600081518110610e5057fe5b60200260200101516123d6565b8152602001610e7f83600181518110610e7257fe5b60200260200101516123d6565b8152602001610ea183600281518110610e9457fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b60200260200101516122f9565b9050600160008d81526020019081526020016000208054809190600101610fff9190612800565b5060405180606001604052806110288360008151811061101b57fe5b60200260200101516123d6565b815260200161104a8360018151811061103d57fe5b60200260200101516123d6565b815260200161106c8360028151811061105f57fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a3939291906131d6565b6040516020818303038152906040526040516112bf9190613213565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff9190810190612a58565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b602002602001015160200151836122ac90919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b60405161152690613254565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff16604161246a565b9050600061158582896124f690919063ffffffff16565b905061158f612832565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb8160200151876122ac90919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b611621612832565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611db1565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c69291906131aa565b6040516020818303038152906040526040516117e29190613213565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118229190810190612a58565b9050919050565b60008060008061184a600161183c611781565b6122ac90919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060056040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b50905073c26880a0af2ea0c7e8130e6ec47af756465452e8816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073be188d6641e8b680743a4815dfa0f6208038960f8160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073c275dc8be39f50d12f66b6a63629c39da5bae5bd816002815181106119af57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f903ba9e006193c1527bfbe65fe2123704ea3f9981600381518110611a0b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073928ed6a3e94437bbd316ccad78479f1d163a6a8c81600481518110611a6757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606005604051908082528060200260200182016040528015611ad35781602001602082028038833980820191505090505b50905061271081600081518110611ae657fe5b60200260200101818152505061271081600181518110611b0257fe5b60200260200101818152505061271081600281518110611b1e57fe5b60200260200101818152505061271081600381518110611b3a57fe5b60200260200101818152505061271081600481518110611b5657fe5b60200260200101818152505081819350935050509091565b60ff81565b60016020528160005260406000208181548110611b8c57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611bea611be4611781565b83610939565b9050919050565b604051611bfd9061322a565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611cdb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611c3f565b505050509050600080905060008090505b8251811015611d2e57611d1f838281518110611d0457fe5b602002602001015160200151836122ac90919063ffffffff16565b91508080600101915050611cec565b508092505050919050565b604051611d459061323f565b604051809103902081565b600080600080611d5e611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611e7157611dce612869565b6002600060036001850381548110611de257fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611e3f57506000816040015114155b8015611e4f575080604001518411155b15611e6257806000015192505050611eac565b50808060019003915050611dbd565b5060006003805490501115611ea757600360016003805490500381548110611e9557fe5b90600052602060002001549050611eac565b600090505b919050565b606080611ebd4361075d565b915091509091565b60038181548110611ed257fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611f0457fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060404381611f5b57fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611f9661189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff81525060026000838152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600381908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008381526020019081526020016000208161203f9190612800565b50600060016000838152602001908152602001600020816120609190612800565b5060008090505b83518110156121825760008083815260200190815260200160002080548091906001016120949190612800565b5060405180606001604052808281526020018483815181106120b257fe5b602002602001015181526020018583815181106120cb57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16815250600080848152602001908152602001600020828154811061210957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612067565b5060008090505b83518110156122a6576001600083815260200190815260200160002080548091906001016121b79190612800565b5060405180606001604052808281526020018483815181106121d557fe5b602002602001015181526020018583815181106121ee57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061222d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612189565b50505050565b6000808284019050838110156122c157600080fd5b8091505092915050565b6122d361288a565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061230482612600565b61230d57600080fd5b60006123188361264e565b905060608160405190808252806020026020018201604052801561235657816020015b6123436128a4565b81526020019060019003908161233b5790505b509050600061236885602001516126bf565b8560200151019050600080600090505b848110156123c95761238983612748565b91506040518060400160405280838152602001848152508482815181106123ac57fe5b602002602001018190525081830192508080600101915050612378565b5082945050505050919050565b60008082600001511180156123f057506021826000015111155b6123f957600080fd5b600061240883602001516126bf565b9050600081846000015103905060008083866020015101905080519150602083101561243b57826020036101000a820491505b81945050505050919050565b6000601582600001511461245a57600080fd5b612463826123d6565b9050919050565b60608183018451101561247c57600080fd5b6060821560008114612499576040519150602082016040526124ea565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156124d757805183526020830192506020810190506124ba565b50868552601f19601f8301166040525050505b50809150509392505050565b600080600080604185511461251157600093505050506125fa565b602085015192506040850151915060ff6041860151169050601b8160ff16101561253c57601b810190505b601b8160ff16141580156125545750601c8160ff1614155b1561256557600093505050506125fa565b60006001878386866040516000815260200160405260405161258a94939291906132f1565b6020604051602081039080840390855afa1580156125ac573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156125f257600080fd5b809450505050505b92915050565b600080826000015114156126175760009050612649565b60008083602001519050805160001a915060c060ff168260ff16101561264257600092505050612649565b6001925050505b919050565b6000808260000151141561266557600090506126ba565b6000809050600061267984602001516126bf565b84602001510190506000846000015185602001510190505b808210156126b3576126a282612748565b820191508280600101935050612691565b8293505050505b919050565b600080825160001a9050608060ff168110156126df576000915050612743565b60b860ff16811080612704575060c060ff168110158015612703575060f860ff1681105b5b15612713576001915050612743565b60c060ff168110156127335760018060b80360ff16820301915050612743565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561276957600191506127f6565b60b860ff16811015612786576001608060ff1682030191506127f5565b60c060ff168110156127b65760b78103600185019450806020036101000a855104600182018101935050506127f4565b60f860ff168110156127d357600160c060ff1682030191506127f3565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b81548183558181111561282d5760030281600302836000526020600020918201910161282c91906128be565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b61291191905b8082111561290d5760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016128c4565b5090565b90565b60008135905061292381613693565b92915050565b600081359050612938816136aa565b92915050565b60008151905061294d816136aa565b92915050565b60008083601f84011261296557600080fd5b8235905067ffffffffffffffff81111561297e57600080fd5b60208301915083600182028301111561299657600080fd5b9250929050565b600082601f8301126129ae57600080fd5b81356129c16129bc826134e2565b6134b5565b915080825260208301602083018583830111156129dd57600080fd5b6129e883828461363d565b50505092915050565b600081359050612a00816136c1565b92915050565b600060208284031215612a1857600080fd5b6000612a2684828501612914565b91505092915050565b600060208284031215612a4157600080fd5b6000612a4f84828501612929565b91505092915050565b600060208284031215612a6a57600080fd5b6000612a788482850161293e565b91505092915050565b60008060408385031215612a9457600080fd5b6000612aa285828601612929565b9250506020612ab385828601612929565b9150509250929050565b600080600060608486031215612ad257600080fd5b6000612ae086828701612929565b9350506020612af186828701612929565b925050604084013567ffffffffffffffff811115612b0e57600080fd5b612b1a8682870161299d565b9150509250925092565b600060208284031215612b3657600080fd5b6000612b44848285016129f1565b91505092915050565b60008060408385031215612b6057600080fd5b6000612b6e858286016129f1565b9250506020612b7f85828601612914565b9150509250929050565b600080600060608486031215612b9e57600080fd5b6000612bac868287016129f1565b9350506020612bbd86828701612929565b925050604084013567ffffffffffffffff811115612bda57600080fd5b612be68682870161299d565b9150509250925092565b60008060408385031215612c0357600080fd5b6000612c11858286016129f1565b9250506020612c22858286016129f1565b9150509250929050565b600080600080600080600060a0888a031215612c4757600080fd5b6000612c558a828b016129f1565b9750506020612c668a828b016129f1565b9650506040612c778a828b016129f1565b955050606088013567ffffffffffffffff811115612c9457600080fd5b612ca08a828b01612953565b9450945050608088013567ffffffffffffffff811115612cbf57600080fd5b612ccb8a828b01612953565b925092505092959891949750929550565b6000612ce88383612d0c565b60208301905092915050565b6000612d00838361317d565b60208301905092915050565b612d15816135b2565b82525050565b612d24816135b2565b82525050565b6000612d358261352e565b612d3f8185613569565b9350612d4a8361350e565b8060005b83811015612d7b578151612d628882612cdc565b9750612d6d8361354f565b925050600181019050612d4e565b5085935050505092915050565b6000612d9382613539565b612d9d818561357a565b9350612da88361351e565b8060005b83811015612dd9578151612dc08882612cf4565b9750612dcb8361355c565b925050600181019050612dac565b5085935050505092915050565b612def816135c4565b82525050565b612e06612e01826135d0565b61367f565b82525050565b612e15816135fc565b82525050565b612e2c612e27826135fc565b613689565b82525050565b6000612e3d82613544565b612e47818561358b565b9350612e5781856020860161364c565b80840191505092915050565b6000612e706004836135a7565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612eb0602d83613596565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612f16600f83613596565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612f56601383613596565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612f96604583613596565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000613022602a83613596565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613088601283613596565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b60006130c86005836135a7565b91507f38303030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000613108600e836135a7565b91507f6865696d64616c6c2d38303030310000000000000000000000000000000000006000830152600e82019050919050565b606082016000820151613151600085018261317d565b506020820151613164602085018261317d565b5060408201516131776040850182612d0c565b50505050565b61318681613626565b82525050565b61319581613626565b82525050565b6131a481613630565b82525050565b60006131b68285612df5565b6001820191506131c68284612e1b565b6020820191508190509392505050565b60006131e28286612df5565b6001820191506131f28285612e1b565b6020820191506132028284612e1b565b602082019150819050949350505050565b600061321f8284612e32565b915081905092915050565b600061323582612e63565b9150819050919050565b600061324a826130bb565b9150819050919050565b600061325f826130fb565b9150819050919050565b600060208201905061327e6000830184612d1b565b92915050565b6000604082019050818103600083015261329e8185612d2a565b905081810360208301526132b28184612d88565b90509392505050565b60006020820190506132d06000830184612de6565b92915050565b60006020820190506132eb6000830184612e0c565b92915050565b60006080820190506133066000830187612e0c565b613313602083018661319b565b6133206040830185612e0c565b61332d6060830184612e0c565b95945050505050565b6000602082019050818103600083015261334f81612ea3565b9050919050565b6000602082019050818103600083015261336f81612f09565b9050919050565b6000602082019050818103600083015261338f81612f49565b9050919050565b600060208201905081810360008301526133af81612f89565b9050919050565b600060208201905081810360008301526133cf81613015565b9050919050565b600060208201905081810360008301526133ef8161307b565b9050919050565b600060608201905061340b600083018461313b565b92915050565b6000602082019050613426600083018461318c565b92915050565b6000606082019050613441600083018661318c565b61344e602083018561318c565b61345b6040830184612d1b565b949350505050565b6000606082019050613478600083018661318c565b613485602083018561318c565b613492604083018461318c565b949350505050565b60006020820190506134af600083018461319b565b92915050565b6000604051905081810181811067ffffffffffffffff821117156134d857600080fd5b8060405250919050565b600067ffffffffffffffff8211156134f957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006135bd82613606565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b8381101561366a57808201518184015260208101905061364f565b83811115613679576000848401525b50505050565b6000819050919050565b6000819050919050565b61369c816135b2565b81146136a757600080fd5b50565b6136b3816135fc565b81146136be57600080fd5b50565b6136ca81613626565b81146136d557600080fd5b5056fea365627a7a723158208f52ee07630ffe523cc6ad3e15f437f973dcfa36729cd697f9b0fc4a145a48f06c6578706572696d656e74616cf564736f6c634300050b0040", + "balance":"0x0" + }, + "0000000000000000000000000000000000001001":{ + "code":"0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a7231582083fbdacb76f32b4112d0f7db9a596937925824798a0026ba0232322390b5263764736f6c634300050b0032", + "balance":"0x0" + }, + "0000000000000000000000000000000000001010":{ + "code":"0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a4565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116aa565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611737565b005b348015610b2e57600080fd5b50610b37611754565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa82848861177a565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3790919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e636023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5790919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e406023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b76565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c733848461177a565b90505b92915050565b6040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6e565b611d44565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611e86605291396040516020018082805190602001908083835b602083106116f957805182526020820191506020810190506020830392506116d6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173f6114dd565b61174857600080fd5b61175181611b76565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117fa57600080fd5b505afa15801561180e573d6000803e3d6000fd5b505050506040513d602081101561182457600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b657600080fd5b505afa1580156118ca573d6000803e3d6000fd5b505050506040513d60208110156118e057600080fd5b810190808051906020019092919050505090506118fe868686611d8e565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0657600080fd5b505afa158015611a1a573d6000803e3d6000fd5b505050506040513d6020811015611a3057600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d6020811015611ae857600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4657600080fd5b600082840390508091505092915050565b600080828401905083811015611b6c57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611bb057600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b60208310611cc05780518252602082019150602081019050602083039250611c9d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611dd4573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a723158208f81700133738d766ae3d68af591ad588b0125bd91449192179f460893f79f6b64736f6c634300050b0032", + "balance":"0x204fcd4f31349d83b6e00000" + }, + "928ed6a3e94437bbd316ccad78479f1d163a6a8c":{ + "balance":"0x3635c9adc5dea00000" + }, + "be188d6641e8b680743a4815dfa0f6208038960f":{ + "balance":"0x3635c9adc5dea00000" + }, + "c26880a0af2ea0c7e8130e6ec47af756465452e8":{ + "balance":"0x3635c9adc5dea00000" + }, + "c275dc8be39f50d12f66b6a63629c39da5bae5bd":{ + "balance":"0x3635c9adc5dea00000" + }, + "f903ba9e006193c1527bfbe65fe2123704ea3f99":{ + "balance":"0x3635c9adc5dea00000" + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":null +} diff --git a/internal/cli/server/chains/test_files/chain_test.json b/internal/cli/server/chains/test_files/chain_test.json new file mode 100644 index 0000000000..5bfe155d27 --- /dev/null +++ b/internal/cli/server/chains/test_files/chain_test.json @@ -0,0 +1,92 @@ +{ + "Hash":"0x7b66506a9ebdbf30d32b43c5f15a3b1216269a1ec3a75aa3182b86176a2b1ca7", + "Genesis":{ + "config":{ + "chainId":80001, + "homesteadBlock":0, + "daoForkSupport":true, + "eip150Block":0, + "eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":2722000, + "muirGlacierBlock":2722000, + "berlinBlock":13996000, + "londonBlock":13996000, + "bor":{ + "period":{ + "0":2 + }, + "producerDelay":6, + "sprint":64, + "backupMultiplier":{ + "0":2 + }, + "validatorContract":"0x0000000000000000000000000000000000001000", + "stateReceiverContract":"0x0000000000000000000000000000000000001001", + "overrideStateSyncRecords":null, + "blockAlloc":{ + "22244000":{ + "0000000000000000000000000000000000001010":{ + "balance":"0x0", + "code":"0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610caa565b005b3480156103eb57600080fd5b506103f4610dfc565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e05565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fc1565b005b3480156104e857600080fd5b506104f1611090565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b506105486110b6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506110dc565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b506106046110fd565b005b34801561061257600080fd5b5061061b6111cd565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506111d3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b50610758611358565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af611381565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de6113d8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e611411565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061144e565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b50610964611474565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b8101908080359060200190929190505050611501565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611521565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a65611541565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a90611548565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb61154e565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506115db565b005b348015610b2e57600080fd5b50610b376115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b60006040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b60003390506000610cba826110dc565b9050610cd18360065461161e90919063ffffffff16565b600681905550600083118015610ce657508234145b610d58576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610dd4876110dc565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610e0d611381565b610e1657600080fd5b600081118015610e535750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b610ea8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611da96023913960400191505060405180910390fd5b6000610eb3836110dc565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f19350505050158015610f00573d6000803e3d6000fd5b50610f168360065461163e90919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f68585610f98896110dc565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611027576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611d866023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061108c8261165d565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b611105611381565b61110e57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b60008060008060418551146111ee5760009350505050611352565b602085015192506040850151915060ff6041860151169050601b8160ff16101561121957601b810190505b601b8160ff16141580156112315750601c8160ff1614155b156112425760009350505050611352565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561129f573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561134e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b6000813414611460576000905061146e565b61146b338484611755565b90505b92915050565b6040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b602083106114c357805182526020820191506020810190506020830392506114a0565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061153761153286868686611b12565b611be8565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611dcc605291396040516020018082805190602001908083835b6020831061159d578051825260208201915060208101905060208303925061157a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b6115e3611381565b6115ec57600080fd5b6115f58161165d565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282111561162d57600080fd5b600082840390508091505092915050565b60008082840190508381101561165357600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561169757600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117d557600080fd5b505afa1580156117e9573d6000803e3d6000fd5b505050506040513d60208110156117ff57600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561189157600080fd5b505afa1580156118a5573d6000803e3d6000fd5b505050506040513d60208110156118bb57600080fd5b810190808051906020019092919050505090506118d9868686611c32565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156119e157600080fd5b505afa1580156119f5573d6000803e3d6000fd5b505050506040513d6020811015611a0b57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a9957600080fd5b505afa158015611aad573d6000803e3d6000fd5b505050506040513d6020811015611ac357600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b6000806040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b60208310611b645780518252602082019150602081019050602083039250611b41565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611cd4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611d1a573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820ccd6c2a9c259832bbb367986ee06cd87af23022681b0cb22311a864b701d939564736f6c63430005100032" + } + } + }, + "burntContract":{ + "22640000":"0x70bcA57F4579f58670aB2d18Ef16e02C17553C38" + }, + "jaipurBlock":22770000 + } + }, + "nonce":"0x0", + "timestamp":"0x5ce28211", + "extraData":"0x", + "gasLimit":"0x989680", + "difficulty":"0x1", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "0000000000000000000000000000000000001000":{ + "code":"0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a9190810190612b24565b610706565b60405161021e93929190613463565b60405180910390f35b610241600480360361023c9190810190612b24565b61075d565b60405161024f929190613284565b60405180910390f35b610272600480360361026d9190810190612b4d565b610939565b60405161027f91906132bb565b60405180910390f35b6102a2600480360361029d9190810190612c2c565b610a91565b005b6102be60048036036102b99190810190612b4d565b61112a565b6040516102cb91906132bb565b60405180910390f35b6102dc611281565b6040516102e99190613411565b60405180910390f35b61030c60048036036103079190810190612a81565b611286565b60405161031991906132d6565b60405180910390f35b61033c60048036036103379190810190612b24565b611307565b6040516103499190613411565b60405180910390f35b61035a611437565b6040516103679190613269565b60405180910390f35b61038a60048036036103859190810190612abd565b61144f565b60405161039791906132bb565b60405180910390f35b6103a861151a565b6040516103b591906132d6565b60405180910390f35b6103d860048036036103d39190810190612b89565b611531565b6040516103e59190613411565b60405180910390f35b61040860048036036104039190810190612b4d565b611619565b60405161041591906133f6565b60405180910390f35b610426611781565b6040516104339190613411565b60405180910390f35b61045660048036036104519190810190612a06565b611791565b60405161046391906132bb565b60405180910390f35b61048660048036036104819190810190612a2f565b6117ab565b60405161049391906132d6565b60405180910390f35b6104a4611829565b6040516104b393929190613463565b60405180910390f35b6104c461189d565b6040516104d2929190613284565b60405180910390f35b6104e3611b6e565b6040516104f09190613411565b60405180910390f35b610513600480360361050e9190810190612bf0565b611b73565b6040516105229392919061342c565b60405180910390f35b61054560048036036105409190810190612a06565b611bd7565b60405161055291906132bb565b60405180910390f35b610563611bf1565b60405161057091906132d6565b60405180910390f35b610593600480360361058e9190810190612b24565b611c08565b6040516105a09190613411565b60405180910390f35b6105b1611d39565b6040516105be91906132d6565b60405180910390f35b6105cf611d50565b6040516105de93929190613463565b60405180910390f35b61060160048036036105fc9190810190612b24565b611db1565b60405161060e9190613411565b60405180910390f35b61061f611eb1565b60405161062d929190613284565b60405180910390f35b610650600480360361064b9190810190612b24565b611ec5565b60405161065d9190613411565b60405180910390f35b61066e611ee6565b60405161067b919061349a565b60405180910390f35b61069e60048036036106999190810190612bf0565b611eeb565b6040516106ad9392919061342c565b60405180910390f35b6106be611f4f565b6040516106cb9190613411565b60405180910390f35b6106ee60048036036106e99190810190612b24565b611f61565b6040516106fd93929190613463565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611db1565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a906133d6565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b30611f8b565b5b610b456001826122ac90919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d90613356565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf906133b6565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1190613396565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90613336565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc390613376565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612800565b506000600160008a815260200190815260200160002081610d879190612800565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b60200260200101516122f9565b90506000808c81526020019081526020016000208054809190600101610e349190612800565b506040518060600160405280610e5d83600081518110610e5057fe5b60200260200101516123d6565b8152602001610e7f83600181518110610e7257fe5b60200260200101516123d6565b8152602001610ea183600281518110610e9457fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b60200260200101516122f9565b9050600160008d81526020019081526020016000208054809190600101610fff9190612800565b5060405180606001604052806110288360008151811061101b57fe5b60200260200101516123d6565b815260200161104a8360018151811061103d57fe5b60200260200101516123d6565b815260200161106c8360028151811061105f57fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a3939291906131d6565b6040516020818303038152906040526040516112bf9190613213565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff9190810190612a58565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b602002602001015160200151836122ac90919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b60405161152690613254565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff16604161246a565b9050600061158582896124f690919063ffffffff16565b905061158f612832565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb8160200151876122ac90919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b611621612832565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611db1565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c69291906131aa565b6040516020818303038152906040526040516117e29190613213565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118229190810190612a58565b9050919050565b60008060008061184a600161183c611781565b6122ac90919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060056040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b50905073c26880a0af2ea0c7e8130e6ec47af756465452e8816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073be188d6641e8b680743a4815dfa0f6208038960f8160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073c275dc8be39f50d12f66b6a63629c39da5bae5bd816002815181106119af57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f903ba9e006193c1527bfbe65fe2123704ea3f9981600381518110611a0b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073928ed6a3e94437bbd316ccad78479f1d163a6a8c81600481518110611a6757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606005604051908082528060200260200182016040528015611ad35781602001602082028038833980820191505090505b50905061271081600081518110611ae657fe5b60200260200101818152505061271081600181518110611b0257fe5b60200260200101818152505061271081600281518110611b1e57fe5b60200260200101818152505061271081600381518110611b3a57fe5b60200260200101818152505061271081600481518110611b5657fe5b60200260200101818152505081819350935050509091565b60ff81565b60016020528160005260406000208181548110611b8c57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611bea611be4611781565b83610939565b9050919050565b604051611bfd9061322a565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611cdb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611c3f565b505050509050600080905060008090505b8251811015611d2e57611d1f838281518110611d0457fe5b602002602001015160200151836122ac90919063ffffffff16565b91508080600101915050611cec565b508092505050919050565b604051611d459061323f565b604051809103902081565b600080600080611d5e611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611e7157611dce612869565b6002600060036001850381548110611de257fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611e3f57506000816040015114155b8015611e4f575080604001518411155b15611e6257806000015192505050611eac565b50808060019003915050611dbd565b5060006003805490501115611ea757600360016003805490500381548110611e9557fe5b90600052602060002001549050611eac565b600090505b919050565b606080611ebd4361075d565b915091509091565b60038181548110611ed257fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611f0457fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060404381611f5b57fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611f9661189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff81525060026000838152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600381908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008381526020019081526020016000208161203f9190612800565b50600060016000838152602001908152602001600020816120609190612800565b5060008090505b83518110156121825760008083815260200190815260200160002080548091906001016120949190612800565b5060405180606001604052808281526020018483815181106120b257fe5b602002602001015181526020018583815181106120cb57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16815250600080848152602001908152602001600020828154811061210957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612067565b5060008090505b83518110156122a6576001600083815260200190815260200160002080548091906001016121b79190612800565b5060405180606001604052808281526020018483815181106121d557fe5b602002602001015181526020018583815181106121ee57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061222d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612189565b50505050565b6000808284019050838110156122c157600080fd5b8091505092915050565b6122d361288a565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061230482612600565b61230d57600080fd5b60006123188361264e565b905060608160405190808252806020026020018201604052801561235657816020015b6123436128a4565b81526020019060019003908161233b5790505b509050600061236885602001516126bf565b8560200151019050600080600090505b848110156123c95761238983612748565b91506040518060400160405280838152602001848152508482815181106123ac57fe5b602002602001018190525081830192508080600101915050612378565b5082945050505050919050565b60008082600001511180156123f057506021826000015111155b6123f957600080fd5b600061240883602001516126bf565b9050600081846000015103905060008083866020015101905080519150602083101561243b57826020036101000a820491505b81945050505050919050565b6000601582600001511461245a57600080fd5b612463826123d6565b9050919050565b60608183018451101561247c57600080fd5b6060821560008114612499576040519150602082016040526124ea565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156124d757805183526020830192506020810190506124ba565b50868552601f19601f8301166040525050505b50809150509392505050565b600080600080604185511461251157600093505050506125fa565b602085015192506040850151915060ff6041860151169050601b8160ff16101561253c57601b810190505b601b8160ff16141580156125545750601c8160ff1614155b1561256557600093505050506125fa565b60006001878386866040516000815260200160405260405161258a94939291906132f1565b6020604051602081039080840390855afa1580156125ac573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156125f257600080fd5b809450505050505b92915050565b600080826000015114156126175760009050612649565b60008083602001519050805160001a915060c060ff168260ff16101561264257600092505050612649565b6001925050505b919050565b6000808260000151141561266557600090506126ba565b6000809050600061267984602001516126bf565b84602001510190506000846000015185602001510190505b808210156126b3576126a282612748565b820191508280600101935050612691565b8293505050505b919050565b600080825160001a9050608060ff168110156126df576000915050612743565b60b860ff16811080612704575060c060ff168110158015612703575060f860ff1681105b5b15612713576001915050612743565b60c060ff168110156127335760018060b80360ff16820301915050612743565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561276957600191506127f6565b60b860ff16811015612786576001608060ff1682030191506127f5565b60c060ff168110156127b65760b78103600185019450806020036101000a855104600182018101935050506127f4565b60f860ff168110156127d357600160c060ff1682030191506127f3565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b81548183558181111561282d5760030281600302836000526020600020918201910161282c91906128be565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b61291191905b8082111561290d5760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016128c4565b5090565b90565b60008135905061292381613693565b92915050565b600081359050612938816136aa565b92915050565b60008151905061294d816136aa565b92915050565b60008083601f84011261296557600080fd5b8235905067ffffffffffffffff81111561297e57600080fd5b60208301915083600182028301111561299657600080fd5b9250929050565b600082601f8301126129ae57600080fd5b81356129c16129bc826134e2565b6134b5565b915080825260208301602083018583830111156129dd57600080fd5b6129e883828461363d565b50505092915050565b600081359050612a00816136c1565b92915050565b600060208284031215612a1857600080fd5b6000612a2684828501612914565b91505092915050565b600060208284031215612a4157600080fd5b6000612a4f84828501612929565b91505092915050565b600060208284031215612a6a57600080fd5b6000612a788482850161293e565b91505092915050565b60008060408385031215612a9457600080fd5b6000612aa285828601612929565b9250506020612ab385828601612929565b9150509250929050565b600080600060608486031215612ad257600080fd5b6000612ae086828701612929565b9350506020612af186828701612929565b925050604084013567ffffffffffffffff811115612b0e57600080fd5b612b1a8682870161299d565b9150509250925092565b600060208284031215612b3657600080fd5b6000612b44848285016129f1565b91505092915050565b60008060408385031215612b6057600080fd5b6000612b6e858286016129f1565b9250506020612b7f85828601612914565b9150509250929050565b600080600060608486031215612b9e57600080fd5b6000612bac868287016129f1565b9350506020612bbd86828701612929565b925050604084013567ffffffffffffffff811115612bda57600080fd5b612be68682870161299d565b9150509250925092565b60008060408385031215612c0357600080fd5b6000612c11858286016129f1565b9250506020612c22858286016129f1565b9150509250929050565b600080600080600080600060a0888a031215612c4757600080fd5b6000612c558a828b016129f1565b9750506020612c668a828b016129f1565b9650506040612c778a828b016129f1565b955050606088013567ffffffffffffffff811115612c9457600080fd5b612ca08a828b01612953565b9450945050608088013567ffffffffffffffff811115612cbf57600080fd5b612ccb8a828b01612953565b925092505092959891949750929550565b6000612ce88383612d0c565b60208301905092915050565b6000612d00838361317d565b60208301905092915050565b612d15816135b2565b82525050565b612d24816135b2565b82525050565b6000612d358261352e565b612d3f8185613569565b9350612d4a8361350e565b8060005b83811015612d7b578151612d628882612cdc565b9750612d6d8361354f565b925050600181019050612d4e565b5085935050505092915050565b6000612d9382613539565b612d9d818561357a565b9350612da88361351e565b8060005b83811015612dd9578151612dc08882612cf4565b9750612dcb8361355c565b925050600181019050612dac565b5085935050505092915050565b612def816135c4565b82525050565b612e06612e01826135d0565b61367f565b82525050565b612e15816135fc565b82525050565b612e2c612e27826135fc565b613689565b82525050565b6000612e3d82613544565b612e47818561358b565b9350612e5781856020860161364c565b80840191505092915050565b6000612e706004836135a7565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612eb0602d83613596565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612f16600f83613596565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612f56601383613596565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612f96604583613596565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000613022602a83613596565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613088601283613596565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b60006130c86005836135a7565b91507f38303030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000613108600e836135a7565b91507f6865696d64616c6c2d38303030310000000000000000000000000000000000006000830152600e82019050919050565b606082016000820151613151600085018261317d565b506020820151613164602085018261317d565b5060408201516131776040850182612d0c565b50505050565b61318681613626565b82525050565b61319581613626565b82525050565b6131a481613630565b82525050565b60006131b68285612df5565b6001820191506131c68284612e1b565b6020820191508190509392505050565b60006131e28286612df5565b6001820191506131f28285612e1b565b6020820191506132028284612e1b565b602082019150819050949350505050565b600061321f8284612e32565b915081905092915050565b600061323582612e63565b9150819050919050565b600061324a826130bb565b9150819050919050565b600061325f826130fb565b9150819050919050565b600060208201905061327e6000830184612d1b565b92915050565b6000604082019050818103600083015261329e8185612d2a565b905081810360208301526132b28184612d88565b90509392505050565b60006020820190506132d06000830184612de6565b92915050565b60006020820190506132eb6000830184612e0c565b92915050565b60006080820190506133066000830187612e0c565b613313602083018661319b565b6133206040830185612e0c565b61332d6060830184612e0c565b95945050505050565b6000602082019050818103600083015261334f81612ea3565b9050919050565b6000602082019050818103600083015261336f81612f09565b9050919050565b6000602082019050818103600083015261338f81612f49565b9050919050565b600060208201905081810360008301526133af81612f89565b9050919050565b600060208201905081810360008301526133cf81613015565b9050919050565b600060208201905081810360008301526133ef8161307b565b9050919050565b600060608201905061340b600083018461313b565b92915050565b6000602082019050613426600083018461318c565b92915050565b6000606082019050613441600083018661318c565b61344e602083018561318c565b61345b6040830184612d1b565b949350505050565b6000606082019050613478600083018661318c565b613485602083018561318c565b613492604083018461318c565b949350505050565b60006020820190506134af600083018461319b565b92915050565b6000604051905081810181811067ffffffffffffffff821117156134d857600080fd5b8060405250919050565b600067ffffffffffffffff8211156134f957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006135bd82613606565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b8381101561366a57808201518184015260208101905061364f565b83811115613679576000848401525b50505050565b6000819050919050565b6000819050919050565b61369c816135b2565b81146136a757600080fd5b50565b6136b3816135fc565b81146136be57600080fd5b50565b6136ca81613626565b81146136d557600080fd5b5056fea365627a7a723158208f52ee07630ffe523cc6ad3e15f437f973dcfa36729cd697f9b0fc4a145a48f06c6578706572696d656e74616cf564736f6c634300050b0040", + "balance":"0x0" + }, + "0000000000000000000000000000000000001001":{ + "code":"0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a7231582083fbdacb76f32b4112d0f7db9a596937925824798a0026ba0232322390b5263764736f6c634300050b0032", + "balance":"0x0" + }, + "0000000000000000000000000000000000001010":{ + "code":"0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a4565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116aa565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611737565b005b348015610b2e57600080fd5b50610b37611754565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa82848861177a565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3790919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e636023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5790919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e406023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b76565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c733848461177a565b90505b92915050565b6040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6e565b611d44565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611e86605291396040516020018082805190602001908083835b602083106116f957805182526020820191506020810190506020830392506116d6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173f6114dd565b61174857600080fd5b61175181611b76565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117fa57600080fd5b505afa15801561180e573d6000803e3d6000fd5b505050506040513d602081101561182457600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b657600080fd5b505afa1580156118ca573d6000803e3d6000fd5b505050506040513d60208110156118e057600080fd5b810190808051906020019092919050505090506118fe868686611d8e565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0657600080fd5b505afa158015611a1a573d6000803e3d6000fd5b505050506040513d6020811015611a3057600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d6020811015611ae857600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4657600080fd5b600082840390508091505092915050565b600080828401905083811015611b6c57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611bb057600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b60208310611cc05780518252602082019150602081019050602083039250611c9d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611dd4573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a723158208f81700133738d766ae3d68af591ad588b0125bd91449192179f460893f79f6b64736f6c634300050b0032", + "balance":"0x204fcd4f31349d83b6e00000" + }, + "928ed6a3e94437bbd316ccad78479f1d163a6a8c":{ + "balance":"0x3635c9adc5dea00000" + }, + "be188d6641e8b680743a4815dfa0f6208038960f":{ + "balance":"0x3635c9adc5dea00000" + }, + "c26880a0af2ea0c7e8130e6ec47af756465452e8":{ + "balance":"0x3635c9adc5dea00000" + }, + "c275dc8be39f50d12f66b6a63629c39da5bae5bd":{ + "balance":"0x3635c9adc5dea00000" + }, + "f903ba9e006193c1527bfbe65fe2123704ea3f99":{ + "balance":"0x3635c9adc5dea00000" + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":null + }, + "Bootnodes":[ + "enode://320553cda00dfc003f499a3ce9598029f364fbb3ed1222fdc20a94d97dcc4d8ba0cd0bfa996579dcc6d17a534741fb0a5da303a90579431259150de66b597251@54.147.31.250:30303", + "enode://f0f48a8781629f95ff02606081e6e43e4aebd503f3d07fc931fad7dd5ca1ba52bd849a6f6c3be0e375cf13c9ae04d859c4a9ae3546dc8ed4f10aa5dbb47d4998@34.226.134.117:30303" + ], + "NetworkId":80001, + "DNS":null + } diff --git a/internal/cli/server/chains/test_files/wrong_chain.json b/internal/cli/server/chains/test_files/wrong_chain.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/internal/cli/server/chains/test_files/wrong_chain.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/internal/cli/server/command.go b/internal/cli/server/command.go index 4b2374dc42..a0b8a6d87c 100644 --- a/internal/cli/server/command.go +++ b/internal/cli/server/command.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "os/signal" + "strings" "syscall" "github.com/ethereum/go-ethereum/log" @@ -25,6 +26,17 @@ type Command struct { srv *Server } +// MarkDown implements cli.MarkDown interface +func (c *Command) MarkDown() string { + items := []string{ + "# Server", + "The ```bor server``` command runs the Bor client.", + c.Flags().MarkDown(), + } + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (c *Command) Help() string { return `Usage: bor [options] diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index 06ec8c16af..ab8c8e5155 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -43,8 +43,8 @@ type Config struct { // Name, or identity of the node Name string `hcl:"name,optional"` - // Whitelist is a list of required (block number, hash) pairs to accept - Whitelist map[string]string `hcl:"whitelist,optional"` + // RequiredBlocks is a list of required (block number, hash) pairs to accept + RequiredBlocks map[string]string `hcl:"requiredblocks,optional"` // LogLevel is the level of the logs to put out LogLevel string `hcl:"log-level,optional"` @@ -52,14 +52,17 @@ type Config struct { // DataDir is the directory to store the state in DataDir string `hcl:"data-dir,optional"` + // KeyStoreDir is the directory to store keystores + KeyStoreDir string `hcl:"keystore-dir,optional"` + // SyncMode selects the sync protocol SyncMode string `hcl:"sync-mode,optional"` // GcMode selects the garbage collection mode for the trie GcMode string `hcl:"gc-mode,optional"` - // XXX - Snapshot bool `hcl:"snapshot,optional"` + // NoSnapshot disables the snapshot database mode + NoSnapshot bool `hcl:"no-snapshot,optional"` // Ethstats is the address of the ethstats server to send telemetry Ethstats string `hcl:"ethstats,optional"` @@ -368,6 +371,9 @@ type AccountsConfig struct { // UseLightweightKDF enables a faster but less secure encryption of accounts UseLightweightKDF bool `hcl:"use-lightweight-kdf,optional"` + + // DisableBorWallet disables the personal wallet endpoints + DisableBorWallet bool `hcl:"disable-bor-wallet,optional"` } type DeveloperConfig struct { @@ -380,11 +386,11 @@ type DeveloperConfig struct { func DefaultConfig() *Config { return &Config{ - Chain: "mainnet", - Name: Hostname(), - Whitelist: map[string]string{}, - LogLevel: "INFO", - DataDir: defaultDataDir(), + Chain: "mainnet", + Name: Hostname(), + RequiredBlocks: map[string]string{}, + LogLevel: "INFO", + DataDir: defaultDataDir(), P2P: &P2PConfig{ MaxPeers: 30, MaxPendPeers: 50, @@ -406,27 +412,27 @@ func DefaultConfig() *Config { URL: "http://localhost:1317", Without: false, }, - SyncMode: "full", - GcMode: "full", - Snapshot: true, + SyncMode: "full", + GcMode: "full", + NoSnapshot: false, TxPool: &TxPoolConfig{ Locals: []string{}, NoLocals: false, Journal: "", Rejournal: time.Duration(1 * time.Hour), - PriceLimit: 1, + PriceLimit: 30000000000, PriceBump: 10, AccountSlots: 16, - GlobalSlots: 4096, - AccountQueue: 64, - GlobalQueue: 1024, + GlobalSlots: 32768, + AccountQueue: 16, + GlobalQueue: 32768, LifeTime: time.Duration(3 * time.Hour), }, Sealer: &SealerConfig{ Enabled: false, Etherbase: "", GasCeil: 8000000, - GasPrice: big.NewInt(params.GWei), + GasPrice: big.NewInt(30 * params.GWei), ExtraData: "", }, Gpo: &GpoConfig{ @@ -447,7 +453,7 @@ func DefaultConfig() *Config { Port: 8545, Prefix: "", Host: "localhost", - Modules: []string{"web3", "net"}, + Modules: []string{"eth", "net", "web3", "txpool", "bor"}, }, Ws: &APIConfig{ Enabled: false, @@ -496,6 +502,7 @@ func DefaultConfig() *Config { PasswordFile: "", AllowInsecureUnlock: false, UseLightweightKDF: false, + DisableBorWallet: false, }, GRPC: &GRPCConfig{ Addr: ":3131", @@ -523,18 +530,22 @@ func (c *Config) fillBigInt() error { b := new(big.Int) var ok bool + if strings.HasPrefix(*x.str, "0x") { b, ok = b.SetString((*x.str)[2:], 16) } else { b, ok = b.SetString(*x.str, 10) } + if !ok { return fmt.Errorf("%s can't parse big int %s", x.path, *x.str) } + *x.str = "" *x.td = b } } + return nil } @@ -555,10 +566,12 @@ func (c *Config) fillTimeDurations() error { if err != nil { return fmt.Errorf("%s can't parse time duration %s", x.path, *x.str) } + *x.str = "" *x.td = d } } + return nil } @@ -570,6 +583,7 @@ func readConfigFile(path string) (*Config, error) { if err != nil { return nil, err } + return readLegacyConfig(data) } @@ -578,26 +592,28 @@ func readConfigFile(path string) (*Config, error) { Cache: &CacheConfig{}, Sealer: &SealerConfig{}, } + if err := hclsimple.DecodeFile(path, nil, config); err != nil { return nil, fmt.Errorf("failed to decode config file '%s': %v", path, err) } + if err := config.fillBigInt(); err != nil { return nil, err } + if err := config.fillTimeDurations(); err != nil { return nil, err } + return config, nil } func (c *Config) loadChain() error { - if c.Developer.Enabled { - return nil - } - chain, ok := chains.GetChain(c.Chain) - if !ok { - return fmt.Errorf("chain '%s' not found", c.Chain) + chain, err := chains.GetChain(c.Chain) + if err != nil { + return err } + c.chain = chain // preload some default values that depend on the chain file @@ -611,14 +627,17 @@ func (c *Config) loadChain() error { } else { c.Cache.Cache = 1024 } + return nil } -func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { +//nolint:gocognit +func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*ethconfig.Config, error) { dbHandles, err := makeDatabaseHandles() if err != nil { return nil, err } + n := ethconfig.Defaults // only update for non-developer mode as we don't yet @@ -662,15 +681,42 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { if !common.IsHexAddress(etherbase) { return nil, fmt.Errorf("etherbase is not an address: %s", etherbase) } + n.Miner.Etherbase = common.HexToAddress(etherbase) } } + // unlock accounts + if len(c.Accounts.Unlock) > 0 { + if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() { + return nil, fmt.Errorf("account unlock with HTTP access is forbidden") + } + + ks := accountManager.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + + passwords, err := MakePasswordListFromFile(c.Accounts.PasswordFile) + if err != nil { + return nil, err + } + + if len(passwords) < len(c.Accounts.Unlock) { + return nil, fmt.Errorf("number of passwords provided (%v) is less than number of accounts (%v) to unlock", + len(passwords), len(c.Accounts.Unlock)) + } + + for i, account := range c.Accounts.Unlock { + err = ks.Unlock(accounts.Account{Address: common.HexToAddress(account)}, passwords[i]) + if err != nil { + return nil, fmt.Errorf("could not unlock an account %q", account) + } + } + } + // update for developer mode if c.Developer.Enabled { // Get a keystore var ks *keystore.KeyStore - if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { + if keystores := accountManager.Backends(keystore.KeyStoreType); len(keystores) > 0 { ks = keystores[0].(*keystore.KeyStore) } @@ -680,6 +726,7 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { passphrase string err error ) + // etherbase has been set above, configuring the miner address from command line flags. if n.Miner.Etherbase != (common.Address{}) { developer = accounts.Account{Address: n.Miner.Etherbase} @@ -694,8 +741,13 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { if err := ks.Unlock(developer, passphrase); err != nil { return nil, fmt.Errorf("failed to unlock developer account: %v", err) } + log.Info("Using developer account", "address", developer.Address) + // Set the Etherbase + c.Sealer.Etherbase = developer.Address.Hex() + n.Miner.Etherbase = developer.Address + // get developer mode chain config c.chain = chains.GetDeveloperChain(c.Developer.Period, developer.Address) @@ -721,18 +773,20 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { n.SnapDiscoveryURLs = c.P2P.Discovery.DNS } - // whitelist + // RequiredBlocks { n.PeerRequiredBlocks = map[uint64]common.Hash{} - for k, v := range c.Whitelist { + for k, v := range c.RequiredBlocks { number, err := strconv.ParseUint(k, 0, 64) if err != nil { - return nil, fmt.Errorf("invalid whitelist block number %s: %v", k, err) + return nil, fmt.Errorf("invalid required block number %s: %v", k, err) } + var hash common.Hash if err = hash.UnmarshalText([]byte(v)); err != nil { - return nil, fmt.Errorf("invalid whitelist hash %s: %v", v, err) + return nil, fmt.Errorf("invalid required block hash %s: %v", v, err) } + n.PeerRequiredBlocks[number] = hash } } @@ -751,6 +805,7 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024) mem.Total = 2 * 1024 * 1024 * 1024 } + allowance := uint64(mem.Total / 1024 / 1024 / 3) if cache > allowance { log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) @@ -780,6 +835,7 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { } else { log.Info("Global gas cap disabled") } + n.RPCTxFeeCap = c.JsonRPC.TxFeeCap // sync mode. It can either be "fast", "full" or "snap". We disable @@ -808,7 +864,7 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { } // snapshot disable check - if c.Snapshot { + if c.NoSnapshot { if n.SyncMode == downloader.SnapSync { log.Info("Snap sync requested, enabling --snapshot") } else { @@ -819,6 +875,7 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { } n.DatabaseHandles = dbHandles + return &n, nil } @@ -840,6 +897,7 @@ func (c *Config) buildNode() (*node.Config, error) { cfg := &node.Config{ Name: clientIdentifier, DataDir: c.DataDir, + KeyStoreDir: c.KeyStoreDir, UseLightweightKDF: c.Accounts.UseLightweightKDF, InsecureUnlockAllowed: c.Accounts.AllowInsecureUnlock, Version: params.VersionWithCommit(gitCommit, gitDate), @@ -870,6 +928,10 @@ func (c *Config) buildNode() (*node.Config, error) { cfg.P2P.ListenAddr = "" cfg.P2P.NoDial = true cfg.P2P.DiscoveryV5 = false + + // enable JsonRPC HTTP API + c.JsonRPC.Http.Enabled = true + cfg.HTTPModules = []string{"admin", "debug", "eth", "miner", "net", "personal", "txpool", "web3", "bor"} } // enable jsonrpc endpoints @@ -878,6 +940,7 @@ func (c *Config) buildNode() (*node.Config, error) { cfg.HTTPHost = c.JsonRPC.Http.Host cfg.HTTPPort = int(c.JsonRPC.Http.Port) } + if c.JsonRPC.Ws.Enabled { cfg.WSHost = c.JsonRPC.Ws.Host cfg.WSPort = int(c.JsonRPC.Ws.Port) @@ -888,6 +951,7 @@ func (c *Config) buildNode() (*node.Config, error) { if err != nil { return nil, fmt.Errorf("wrong 'nat' flag: %v", err) } + cfg.P2P.NAT = natif // only check for non-developer modes @@ -898,18 +962,30 @@ func (c *Config) buildNode() (*node.Config, error) { if len(bootnodes) == 0 { bootnodes = c.chain.Bootnodes } + if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil { return nil, err } + if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil { return nil, err } + if cfg.P2P.StaticNodes, err = parseBootnodes(c.P2P.Discovery.StaticNodes); err != nil { return nil, err } + + if len(cfg.P2P.StaticNodes) == 0 { + cfg.P2P.StaticNodes = cfg.StaticNodes() + } + if cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil { return nil, err } + + if len(cfg.P2P.TrustedNodes) == 0 { + cfg.P2P.TrustedNodes = cfg.TrustedNodes() + } } if c.P2P.NoDiscover { @@ -917,15 +993,17 @@ func (c *Config) buildNode() (*node.Config, error) { cfg.P2P.MaxPeers = 0 cfg.P2P.NoDiscovery = true } + return cfg, nil } func (c *Config) Merge(cc ...*Config) error { for _, elem := range cc { - if err := mergo.Merge(c, elem, mergo.WithOverride, mergo.WithAppendSlice); err != nil { + if err := mergo.Merge(c, elem, mergo.WithOverwriteWithEmptyValue, mergo.WithAppendSlice); err != nil { return fmt.Errorf("failed to merge configurations: %v", err) } } + return nil } @@ -934,10 +1012,12 @@ func makeDatabaseHandles() (int, error) { if err != nil { return -1, err } + raised, err := fdlimit.Raise(uint64(limit)) if err != nil { return -1, err } + return int(raised / 2), nil } @@ -952,6 +1032,7 @@ func parseBootnodes(urls []string) ([]*enode.Node, error) { dst = append(dst, node) } } + return dst, nil } @@ -962,6 +1043,7 @@ func defaultDataDir() string { // we cannot guess a stable location return "" } + switch runtime.GOOS { case "darwin": return filepath.Join(home, "Library", "Bor") @@ -971,6 +1053,7 @@ func defaultDataDir() string { // Windows XP and below don't have LocalAppData. panic("environment variable LocalAppData is undefined") } + return filepath.Join(appdata, "Bor") default: return filepath.Join(home, ".bor") @@ -982,5 +1065,22 @@ func Hostname() string { if err != nil { return "bor" } + return hostname } + +func MakePasswordListFromFile(path string) ([]string, error) { + text, err := ioutil.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("Failed to read password file: %v", err) + } + + lines := strings.Split(string(text), "\n") + + // Sanitise DOS line endings. + for i := range lines { + lines[i] = strings.TrimRight(lines[i], "\r") + } + + return lines, nil +} diff --git a/internal/cli/server/config_test.go b/internal/cli/server/config_test.go index 62296d82a4..94c4496c03 100644 --- a/internal/cli/server/config_test.go +++ b/internal/cli/server/config_test.go @@ -16,15 +16,15 @@ func TestConfigDefault(t *testing.T) { _, err := config.buildNode() assert.NoError(t, err) - _, err = config.buildEth(nil) + _, err = config.buildEth(nil, nil) assert.NoError(t, err) } func TestConfigMerge(t *testing.T) { c0 := &Config{ - Chain: "0", - Snapshot: true, - Whitelist: map[string]string{ + Chain: "0", + NoSnapshot: true, + RequiredBlocks: map[string]string{ "a": "b", }, TxPool: &TxPoolConfig{ @@ -40,7 +40,7 @@ func TestConfigMerge(t *testing.T) { } c1 := &Config{ Chain: "1", - Whitelist: map[string]string{ + RequiredBlocks: map[string]string{ "b": "c", }, P2P: &P2PConfig{ @@ -52,16 +52,14 @@ func TestConfigMerge(t *testing.T) { }, }, } + expected := &Config{ - Chain: "1", - Snapshot: true, - Whitelist: map[string]string{ + Chain: "1", + NoSnapshot: false, + RequiredBlocks: map[string]string{ "a": "b", "b": "c", }, - TxPool: &TxPoolConfig{ - LifeTime: 5 * time.Second, - }, P2P: &P2PConfig{ MaxPeers: 10, Discovery: &P2PDiscovery{ @@ -72,6 +70,34 @@ func TestConfigMerge(t *testing.T) { }, }, } + + assert.NoError(t, c0.Merge(c1)) + assert.Equal(t, c0, expected) +} + +func TestDefaultDatatypeOverride(t *testing.T) { + t.Parallel() + + // This test is specific to `maxpeers` flag (for now) to check + // if default datatype value (0 in case of uint64) is overridden. + c0 := &Config{ + P2P: &P2PConfig{ + MaxPeers: 30, + }, + } + + c1 := &Config{ + P2P: &P2PConfig{ + MaxPeers: 0, + }, + } + + expected := &Config{ + P2P: &P2PConfig{ + MaxPeers: 0, + }, + } + assert.NoError(t, c0.Merge(c1)) assert.Equal(t, c0, expected) } @@ -80,9 +106,10 @@ func TestConfigLoadFile(t *testing.T) { readFile := func(path string) { config, err := readConfigFile(path) assert.NoError(t, err) + assert.Equal(t, config, &Config{ DataDir: "./data", - Whitelist: map[string]string{ + RequiredBlocks: map[string]string{ "a": "b", }, P2P: &P2PConfig{ @@ -103,6 +130,7 @@ func TestConfigLoadFile(t *testing.T) { t.Run("hcl", func(t *testing.T) { readFile("./testdata/simple.hcl") }) + // read file in json format t.Run("json", func(t *testing.T) { readFile("./testdata/simple.json") @@ -131,3 +159,14 @@ func TestConfigBootnodesDefault(t *testing.T) { assert.Len(t, cfg.P2P.BootstrapNodes, 1) }) } + +func TestMakePasswordListFromFile(t *testing.T) { + t.Parallel() + + t.Run("ReadPasswordFile", func(t *testing.T) { + t.Parallel() + + result, _ := MakePasswordListFromFile("./testdata/password.txt") + assert.Equal(t, []string{"test1", "test2"}, result) + }) +} diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index b8f6003420..21e9a38cb9 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -10,24 +10,33 @@ func (c *Command) Flags() *flagset.Flagset { f := flagset.NewFlagSet("server") f.StringFlag(&flagset.StringFlag{ - Name: "chain", - Usage: "Name of the chain to sync", - Value: &c.cliConfig.Chain, + Name: "chain", + Usage: "Name of the chain to sync", + Value: &c.cliConfig.Chain, + Default: c.cliConfig.Chain, }) f.StringFlag(&flagset.StringFlag{ - Name: "name", - Usage: "Name/Identity of the node", - Value: &c.cliConfig.Name, + Name: "name", + Usage: "Name/Identity of the node", + Value: &c.cliConfig.Name, + Default: c.cliConfig.Name, }) f.StringFlag(&flagset.StringFlag{ - Name: "log-level", - Usage: "Set log level for the server", - Value: &c.cliConfig.LogLevel, + Name: "log-level", + Usage: "Set log level for the server", + Value: &c.cliConfig.LogLevel, + Default: c.cliConfig.LogLevel, }) f.StringFlag(&flagset.StringFlag{ - Name: "datadir", - Usage: "Path of the data directory to store information", - Value: &c.cliConfig.DataDir, + Name: "datadir", + Usage: "Path of the data directory to store information", + Value: &c.cliConfig.DataDir, + Default: c.cliConfig.DataDir, + }) + f.StringFlag(&flagset.StringFlag{ + Name: "keystore", + Usage: "Path of the directory to store keystores", + Value: &c.cliConfig.KeyStoreDir, }) f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "config", @@ -35,36 +44,41 @@ func (c *Command) Flags() *flagset.Flagset { Value: &c.configFile, }) f.StringFlag(&flagset.StringFlag{ - Name: "syncmode", - Usage: `Blockchain sync mode ("fast", "full", "snap" or "light")`, - Value: &c.cliConfig.SyncMode, + Name: "syncmode", + Usage: `Blockchain sync mode ("fast", "full", or "snap")`, + Value: &c.cliConfig.SyncMode, + Default: c.cliConfig.SyncMode, }) f.StringFlag(&flagset.StringFlag{ - Name: "gcmode", - Usage: `Blockchain garbage collection mode ("full", "archive")`, - Value: &c.cliConfig.GcMode, + Name: "gcmode", + Usage: `Blockchain garbage collection mode ("full", "archive")`, + Value: &c.cliConfig.GcMode, + Default: c.cliConfig.GcMode, }) f.MapStringFlag(&flagset.MapStringFlag{ - Name: "whitelist", + Name: "requiredblocks", Usage: "Comma separated block number-to-hash mappings to enforce (=)", - Value: &c.cliConfig.Whitelist, + Value: &c.cliConfig.RequiredBlocks, }) f.BoolFlag(&flagset.BoolFlag{ - Name: "snapshot", - Usage: `Enables snapshot-database mode (default = enable)`, - Value: &c.cliConfig.Snapshot, + Name: "no-snapshot", + Usage: `Disables the snapshot-database mode (default = false)`, + Value: &c.cliConfig.NoSnapshot, + Default: c.cliConfig.NoSnapshot, }) // heimdall f.StringFlag(&flagset.StringFlag{ - Name: "bor.heimdall", - Usage: "URL of Heimdall service", - Value: &c.cliConfig.Heimdall.URL, + Name: "bor.heimdall", + Usage: "URL of Heimdall service", + Value: &c.cliConfig.Heimdall.URL, + Default: c.cliConfig.Heimdall.URL, }) f.BoolFlag(&flagset.BoolFlag{ - Name: "bor.withoutheimdall", - Usage: "Run without Heimdall service (for testing purpose)", - Value: &c.cliConfig.Heimdall.Without, + Name: "bor.withoutheimdall", + Usage: "Run without Heimdall service (for testing purpose)", + Value: &c.cliConfig.Heimdall.Without, + Default: c.cliConfig.Heimdall.Without, }) // txpool options @@ -72,102 +86,135 @@ func (c *Command) Flags() *flagset.Flagset { Name: "txpool.locals", Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)", Value: &c.cliConfig.TxPool.Locals, + Group: "Transaction Pool", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "txpool.nolocals", - Usage: "Disables price exemptions for locally submitted transactions", - Value: &c.cliConfig.TxPool.NoLocals, + Name: "txpool.nolocals", + Usage: "Disables price exemptions for locally submitted transactions", + Value: &c.cliConfig.TxPool.NoLocals, + Default: c.cliConfig.TxPool.NoLocals, + Group: "Transaction Pool", }) f.StringFlag(&flagset.StringFlag{ - Name: "txpool.journal", - Usage: "Disk journal for local transaction to survive node restarts", - Value: &c.cliConfig.TxPool.Journal, + Name: "txpool.journal", + Usage: "Disk journal for local transaction to survive node restarts", + Value: &c.cliConfig.TxPool.Journal, + Default: c.cliConfig.TxPool.Journal, + Group: "Transaction Pool", }) f.DurationFlag(&flagset.DurationFlag{ - Name: "txpool.rejournal", - Usage: "Time interval to regenerate the local transaction journal", - Value: &c.cliConfig.TxPool.Rejournal, + Name: "txpool.rejournal", + Usage: "Time interval to regenerate the local transaction journal", + Value: &c.cliConfig.TxPool.Rejournal, + Default: c.cliConfig.TxPool.Rejournal, + Group: "Transaction Pool", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "txpool.pricelimit", - Usage: "Minimum gas price limit to enforce for acceptance into the pool", - Value: &c.cliConfig.TxPool.PriceLimit, + Name: "txpool.pricelimit", + Usage: "Minimum gas price limit to enforce for acceptance into the pool", + Value: &c.cliConfig.TxPool.PriceLimit, + Default: c.cliConfig.TxPool.PriceLimit, + Group: "Transaction Pool", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "txpool.pricebump", - Usage: "Price bump percentage to replace an already existing transaction", - Value: &c.cliConfig.TxPool.PriceBump, + Name: "txpool.pricebump", + Usage: "Price bump percentage to replace an already existing transaction", + Value: &c.cliConfig.TxPool.PriceBump, + Default: c.cliConfig.TxPool.PriceBump, + Group: "Transaction Pool", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "txpool.accountslots", - Usage: "Minimum number of executable transaction slots guaranteed per account", - Value: &c.cliConfig.TxPool.AccountSlots, + Name: "txpool.accountslots", + Usage: "Minimum number of executable transaction slots guaranteed per account", + Value: &c.cliConfig.TxPool.AccountSlots, + Default: c.cliConfig.TxPool.AccountSlots, + Group: "Transaction Pool", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "txpool.globalslots", - Usage: "Maximum number of executable transaction slots for all accounts", - Value: &c.cliConfig.TxPool.GlobalSlots, + Name: "txpool.globalslots", + Usage: "Maximum number of executable transaction slots for all accounts", + Value: &c.cliConfig.TxPool.GlobalSlots, + Default: c.cliConfig.TxPool.GlobalSlots, + Group: "Transaction Pool", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "txpool.accountqueue", - Usage: "Maximum number of non-executable transaction slots permitted per account", - Value: &c.cliConfig.TxPool.AccountQueue, + Name: "txpool.accountqueue", + Usage: "Maximum number of non-executable transaction slots permitted per account", + Value: &c.cliConfig.TxPool.AccountQueue, + Default: c.cliConfig.TxPool.AccountQueue, + Group: "Transaction Pool", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "txpool.globalqueue", - Usage: "Maximum number of non-executable transaction slots for all accounts", - Value: &c.cliConfig.TxPool.GlobalQueue, + Name: "txpool.globalqueue", + Usage: "Maximum number of non-executable transaction slots for all accounts", + Value: &c.cliConfig.TxPool.GlobalQueue, + Default: c.cliConfig.TxPool.GlobalQueue, + Group: "Transaction Pool", }) f.DurationFlag(&flagset.DurationFlag{ - Name: "txpool.lifetime", - Usage: "Maximum amount of time non-executable transaction are queued", - Value: &c.cliConfig.TxPool.LifeTime, + Name: "txpool.lifetime", + Usage: "Maximum amount of time non-executable transaction are queued", + Value: &c.cliConfig.TxPool.LifeTime, + Default: c.cliConfig.TxPool.LifeTime, + Group: "Transaction Pool", }) // sealer options f.BoolFlag(&flagset.BoolFlag{ - Name: "mine", - Usage: "Enable mining", - Value: &c.cliConfig.Sealer.Enabled, + Name: "mine", + Usage: "Enable mining", + Value: &c.cliConfig.Sealer.Enabled, + Default: c.cliConfig.Sealer.Enabled, + Group: "Sealer", }) f.StringFlag(&flagset.StringFlag{ - Name: "miner.etherbase", - Usage: "Public address for block mining rewards (default = first account)", - Value: &c.cliConfig.Sealer.Etherbase, + Name: "miner.etherbase", + Usage: "Public address for block mining rewards (default = first account)", + Value: &c.cliConfig.Sealer.Etherbase, + Default: c.cliConfig.Sealer.Etherbase, + Group: "Sealer", }) f.StringFlag(&flagset.StringFlag{ - Name: "miner.extradata", - Usage: "Block extra data set by the miner (default = client version)", - Value: &c.cliConfig.Sealer.ExtraData, + Name: "miner.extradata", + Usage: "Block extra data set by the miner (default = client version)", + Value: &c.cliConfig.Sealer.ExtraData, + Default: c.cliConfig.Sealer.ExtraData, + Group: "Sealer", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "miner.gaslimit", - Usage: "Target gas ceiling for mined blocks", - Value: &c.cliConfig.Sealer.GasCeil, + Name: "miner.gaslimit", + Usage: "Target gas ceiling for mined blocks", + Value: &c.cliConfig.Sealer.GasCeil, + Default: c.cliConfig.Sealer.GasCeil, + Group: "Sealer", }) f.BigIntFlag(&flagset.BigIntFlag{ Name: "miner.gasprice", Usage: "Minimum gas price for mining a transaction", Value: c.cliConfig.Sealer.GasPrice, + Group: "Sealer", }) // ethstats f.StringFlag(&flagset.StringFlag{ - Name: "ethstats", - Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", - Value: &c.cliConfig.Ethstats, + Name: "ethstats", + Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", + Value: &c.cliConfig.Ethstats, + Default: c.cliConfig.Ethstats, }) // gas price oracle f.Uint64Flag(&flagset.Uint64Flag{ - Name: "gpo.blocks", - Usage: "Number of recent blocks to check for gas prices", - Value: &c.cliConfig.Gpo.Blocks, + Name: "gpo.blocks", + Usage: "Number of recent blocks to check for gas prices", + Value: &c.cliConfig.Gpo.Blocks, + Default: c.cliConfig.Gpo.Blocks, }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "gpo.percentile", - Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", - Value: &c.cliConfig.Gpo.Percentile, + Name: "gpo.percentile", + Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", + Value: &c.cliConfig.Gpo.Percentile, + Default: c.cliConfig.Gpo.Percentile, }) f.BigIntFlag(&flagset.BigIntFlag{ Name: "gpo.maxprice", @@ -182,262 +229,354 @@ func (c *Command) Flags() *flagset.Flagset { // cache options f.Uint64Flag(&flagset.Uint64Flag{ - Name: "cache", - Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node)", - Value: &c.cliConfig.Cache.Cache, + Name: "cache", + Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node)", + Value: &c.cliConfig.Cache.Cache, + Default: c.cliConfig.Cache.Cache, + Group: "Cache", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "cache.database", - Usage: "Percentage of cache memory allowance to use for database io", - Value: &c.cliConfig.Cache.PercDatabase, + Name: "cache.database", + Usage: "Percentage of cache memory allowance to use for database io", + Value: &c.cliConfig.Cache.PercDatabase, + Default: c.cliConfig.Cache.PercDatabase, + Group: "Cache", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "cache.trie", - Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)", - Value: &c.cliConfig.Cache.PercTrie, + Name: "cache.trie", + Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)", + Value: &c.cliConfig.Cache.PercTrie, + Default: c.cliConfig.Cache.PercTrie, + Group: "Cache", }) f.StringFlag(&flagset.StringFlag{ - Name: "cache.trie.journal", - Usage: "Disk journal directory for trie cache to survive node restarts", - Value: &c.cliConfig.Cache.Journal, + Name: "cache.trie.journal", + Usage: "Disk journal directory for trie cache to survive node restarts", + Value: &c.cliConfig.Cache.Journal, + Default: c.cliConfig.Cache.Journal, + Group: "Cache", }) f.DurationFlag(&flagset.DurationFlag{ - Name: "cache.trie.rejournal", - Usage: "Time interval to regenerate the trie cache journal", - Value: &c.cliConfig.Cache.Rejournal, + Name: "cache.trie.rejournal", + Usage: "Time interval to regenerate the trie cache journal", + Value: &c.cliConfig.Cache.Rejournal, + Default: c.cliConfig.Cache.Rejournal, + Group: "Cache", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "cache.gc", - Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)", - Value: &c.cliConfig.Cache.PercGc, + Name: "cache.gc", + Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)", + Value: &c.cliConfig.Cache.PercGc, + Default: c.cliConfig.Cache.PercGc, + Group: "Cache", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "cache.snapshot", - Usage: "Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode)", - Value: &c.cliConfig.Cache.PercSnapshot, + Name: "cache.snapshot", + Usage: "Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode)", + Value: &c.cliConfig.Cache.PercSnapshot, + Default: c.cliConfig.Cache.PercSnapshot, + Group: "Cache", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "cache.noprefetch", - Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)", - Value: &c.cliConfig.Cache.NoPrefetch, + Name: "cache.noprefetch", + Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)", + Value: &c.cliConfig.Cache.NoPrefetch, + Default: c.cliConfig.Cache.NoPrefetch, + Group: "Cache", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "cache.preimages", - Usage: "Enable recording the SHA3/keccak preimages of trie keys", - Value: &c.cliConfig.Cache.Preimages, + Name: "cache.preimages", + Usage: "Enable recording the SHA3/keccak preimages of trie keys", + Value: &c.cliConfig.Cache.Preimages, + Default: c.cliConfig.Cache.Preimages, + Group: "Cache", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "txlookuplimit", - Usage: "Number of recent blocks to maintain transactions index for (default = about 56 days, 0 = entire chain)", - Value: &c.cliConfig.Cache.TxLookupLimit, + Name: "txlookuplimit", + Usage: "Number of recent blocks to maintain transactions index for (default = about 56 days, 0 = entire chain)", + Value: &c.cliConfig.Cache.TxLookupLimit, + Default: c.cliConfig.Cache.TxLookupLimit, + Group: "Cache", }) // rpc options f.Uint64Flag(&flagset.Uint64Flag{ - Name: "rpc.gascap", - Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)", - Value: &c.cliConfig.JsonRPC.GasCap, + Name: "rpc.gascap", + Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)", + Value: &c.cliConfig.JsonRPC.GasCap, + Default: c.cliConfig.JsonRPC.GasCap, + Group: "JsonRPC", }) f.Float64Flag(&flagset.Float64Flag{ - Name: "rpc.txfeecap", - Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)", - Value: &c.cliConfig.JsonRPC.TxFeeCap, + Name: "rpc.txfeecap", + Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)", + Value: &c.cliConfig.JsonRPC.TxFeeCap, + Default: c.cliConfig.JsonRPC.TxFeeCap, + Group: "JsonRPC", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "ipcdisable", - Usage: "Disable the IPC-RPC server", - Value: &c.cliConfig.JsonRPC.IPCDisable, + Name: "ipcdisable", + Usage: "Disable the IPC-RPC server", + Value: &c.cliConfig.JsonRPC.IPCDisable, + Default: c.cliConfig.JsonRPC.IPCDisable, + Group: "JsonRPC", }) f.StringFlag(&flagset.StringFlag{ - Name: "ipcpath", - Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", - Value: &c.cliConfig.JsonRPC.IPCPath, + Name: "ipcpath", + Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", + Value: &c.cliConfig.JsonRPC.IPCPath, + Default: c.cliConfig.JsonRPC.IPCPath, + Group: "JsonRPC", }) f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "jsonrpc.corsdomain", Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", Value: &c.cliConfig.JsonRPC.Cors, + Group: "JsonRPC", }) f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "jsonrpc.vhosts", Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", Value: &c.cliConfig.JsonRPC.VHost, + Group: "JsonRPC", }) // http options f.BoolFlag(&flagset.BoolFlag{ - Name: "http", - Usage: "Enable the HTTP-RPC server", - Value: &c.cliConfig.JsonRPC.Http.Enabled, + Name: "http", + Usage: "Enable the HTTP-RPC server", + Value: &c.cliConfig.JsonRPC.Http.Enabled, + Default: c.cliConfig.JsonRPC.Http.Enabled, + Group: "JsonRPC", }) f.StringFlag(&flagset.StringFlag{ - Name: "http.addr", - Usage: "HTTP-RPC server listening interface", - Value: &c.cliConfig.JsonRPC.Http.Host, + Name: "http.addr", + Usage: "HTTP-RPC server listening interface", + Value: &c.cliConfig.JsonRPC.Http.Host, + Default: c.cliConfig.JsonRPC.Http.Host, + Group: "JsonRPC", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "http.port", - Usage: "HTTP-RPC server listening port", - Value: &c.cliConfig.JsonRPC.Http.Port, + Name: "http.port", + Usage: "HTTP-RPC server listening port", + Value: &c.cliConfig.JsonRPC.Http.Port, + Default: c.cliConfig.JsonRPC.Http.Port, + Group: "JsonRPC", }) f.StringFlag(&flagset.StringFlag{ - Name: "http.rpcprefix", - Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", - Value: &c.cliConfig.JsonRPC.Http.Prefix, + Name: "http.rpcprefix", + Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", + Value: &c.cliConfig.JsonRPC.Http.Prefix, + Default: c.cliConfig.JsonRPC.Http.Prefix, + Group: "JsonRPC", }) f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "http.modules", Usage: "API's offered over the HTTP-RPC interface", Value: &c.cliConfig.JsonRPC.Http.Modules, + Group: "JsonRPC", }) // ws options f.BoolFlag(&flagset.BoolFlag{ - Name: "ws", - Usage: "Enable the WS-RPC server", - Value: &c.cliConfig.JsonRPC.Ws.Enabled, + Name: "ws", + Usage: "Enable the WS-RPC server", + Value: &c.cliConfig.JsonRPC.Ws.Enabled, + Default: c.cliConfig.JsonRPC.Ws.Enabled, + Group: "JsonRPC", }) f.StringFlag(&flagset.StringFlag{ - Name: "ws.addr", - Usage: "WS-RPC server listening interface", - Value: &c.cliConfig.JsonRPC.Ws.Host, + Name: "ws.addr", + Usage: "WS-RPC server listening interface", + Value: &c.cliConfig.JsonRPC.Ws.Host, + Default: c.cliConfig.JsonRPC.Ws.Host, + Group: "JsonRPC", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "ws.port", - Usage: "WS-RPC server listening port", - Value: &c.cliConfig.JsonRPC.Ws.Port, + Name: "ws.port", + Usage: "WS-RPC server listening port", + Value: &c.cliConfig.JsonRPC.Ws.Port, + Default: c.cliConfig.JsonRPC.Ws.Port, + Group: "JsonRPC", }) f.StringFlag(&flagset.StringFlag{ - Name: "ws.rpcprefix", - Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", - Value: &c.cliConfig.JsonRPC.Ws.Prefix, + Name: "ws.rpcprefix", + Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", + Value: &c.cliConfig.JsonRPC.Ws.Prefix, + Default: c.cliConfig.JsonRPC.Ws.Prefix, + Group: "JsonRPC", }) f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "ws.modules", Usage: "API's offered over the WS-RPC interface", Value: &c.cliConfig.JsonRPC.Ws.Modules, + Group: "JsonRPC", }) // graphql options f.BoolFlag(&flagset.BoolFlag{ - Name: "graphql", - Usage: "Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.", - Value: &c.cliConfig.JsonRPC.Graphql.Enabled, + Name: "graphql", + Usage: "Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.", + Value: &c.cliConfig.JsonRPC.Graphql.Enabled, + Default: c.cliConfig.JsonRPC.Graphql.Enabled, + Group: "JsonRPC", }) // p2p options f.StringFlag(&flagset.StringFlag{ - Name: "bind", - Usage: "Network binding address", - Value: &c.cliConfig.P2P.Bind, + Name: "bind", + Usage: "Network binding address", + Value: &c.cliConfig.P2P.Bind, + Default: c.cliConfig.P2P.Bind, + Group: "P2P", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "port", - Usage: "Network listening port", - Value: &c.cliConfig.P2P.Port, + Name: "port", + Usage: "Network listening port", + Value: &c.cliConfig.P2P.Port, + Default: c.cliConfig.P2P.Port, + Group: "P2P", }) f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "bootnodes", Usage: "Comma separated enode URLs for P2P discovery bootstrap", Value: &c.cliConfig.P2P.Discovery.Bootnodes, + Group: "P2P", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "maxpeers", - Usage: "Maximum number of network peers (network disabled if set to 0)", - Value: &c.cliConfig.P2P.MaxPeers, + Name: "maxpeers", + Usage: "Maximum number of network peers (network disabled if set to 0)", + Value: &c.cliConfig.P2P.MaxPeers, + Default: c.cliConfig.P2P.MaxPeers, + Group: "P2P", }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "maxpendpeers", - Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", - Value: &c.cliConfig.P2P.MaxPendPeers, + Name: "maxpendpeers", + Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", + Value: &c.cliConfig.P2P.MaxPendPeers, + Default: c.cliConfig.P2P.MaxPendPeers, + Group: "P2P", }) f.StringFlag(&flagset.StringFlag{ - Name: "nat", - Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:)", - Value: &c.cliConfig.P2P.NAT, + Name: "nat", + Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:)", + Value: &c.cliConfig.P2P.NAT, + Default: c.cliConfig.P2P.NAT, + Group: "P2P", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "nodiscover", - Usage: "Disables the peer discovery mechanism (manual peer addition)", - Value: &c.cliConfig.P2P.NoDiscover, + Name: "nodiscover", + Usage: "Disables the peer discovery mechanism (manual peer addition)", + Value: &c.cliConfig.P2P.NoDiscover, + Default: c.cliConfig.P2P.NoDiscover, + Group: "P2P", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "v5disc", - Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", - Value: &c.cliConfig.P2P.Discovery.V5Enabled, + Name: "v5disc", + Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", + Value: &c.cliConfig.P2P.Discovery.V5Enabled, + Default: c.cliConfig.P2P.Discovery.V5Enabled, + Group: "P2P", }) // metrics f.BoolFlag(&flagset.BoolFlag{ - Name: "metrics", - Usage: "Enable metrics collection and reporting", - Value: &c.cliConfig.Telemetry.Enabled, + Name: "metrics", + Usage: "Enable metrics collection and reporting", + Value: &c.cliConfig.Telemetry.Enabled, + Default: c.cliConfig.Telemetry.Enabled, + Group: "Telemetry", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "metrics.expensive", - Usage: "Enable expensive metrics collection and reporting", - Value: &c.cliConfig.Telemetry.Expensive, + Name: "metrics.expensive", + Usage: "Enable expensive metrics collection and reporting", + Value: &c.cliConfig.Telemetry.Expensive, + Default: c.cliConfig.Telemetry.Expensive, + Group: "Telemetry", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "metrics.influxdb", - Usage: "Enable metrics export/push to an external InfluxDB database (v1)", - Value: &c.cliConfig.Telemetry.InfluxDB.V1Enabled, + Name: "metrics.influxdb", + Usage: "Enable metrics export/push to an external InfluxDB database (v1)", + Value: &c.cliConfig.Telemetry.InfluxDB.V1Enabled, + Default: c.cliConfig.Telemetry.InfluxDB.V1Enabled, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.influxdb.endpoint", - Usage: "InfluxDB API endpoint to report metrics to", - Value: &c.cliConfig.Telemetry.InfluxDB.Endpoint, + Name: "metrics.influxdb.endpoint", + Usage: "InfluxDB API endpoint to report metrics to", + Value: &c.cliConfig.Telemetry.InfluxDB.Endpoint, + Default: c.cliConfig.Telemetry.InfluxDB.Endpoint, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.influxdb.database", - Usage: "InfluxDB database name to push reported metrics to", - Value: &c.cliConfig.Telemetry.InfluxDB.Database, + Name: "metrics.influxdb.database", + Usage: "InfluxDB database name to push reported metrics to", + Value: &c.cliConfig.Telemetry.InfluxDB.Database, + Default: c.cliConfig.Telemetry.InfluxDB.Database, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.influxdb.username", - Usage: "Username to authorize access to the database", - Value: &c.cliConfig.Telemetry.InfluxDB.Username, + Name: "metrics.influxdb.username", + Usage: "Username to authorize access to the database", + Value: &c.cliConfig.Telemetry.InfluxDB.Username, + Default: c.cliConfig.Telemetry.InfluxDB.Username, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.influxdb.password", - Usage: "Password to authorize access to the database", - Value: &c.cliConfig.Telemetry.InfluxDB.Password, + Name: "metrics.influxdb.password", + Usage: "Password to authorize access to the database", + Value: &c.cliConfig.Telemetry.InfluxDB.Password, + Default: c.cliConfig.Telemetry.InfluxDB.Password, + Group: "Telemetry", }) f.MapStringFlag(&flagset.MapStringFlag{ Name: "metrics.influxdb.tags", Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", Value: &c.cliConfig.Telemetry.InfluxDB.Tags, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.prometheus-addr", - Usage: "Address for Prometheus Server", - Value: &c.cliConfig.Telemetry.PrometheusAddr, + Name: "metrics.prometheus-addr", + Usage: "Address for Prometheus Server", + Value: &c.cliConfig.Telemetry.PrometheusAddr, + Default: c.cliConfig.Telemetry.PrometheusAddr, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.opencollector-endpoint", - Usage: "OpenCollector Endpoint (host:port)", - Value: &c.cliConfig.Telemetry.OpenCollectorEndpoint, + Name: "metrics.opencollector-endpoint", + Usage: "OpenCollector Endpoint (host:port)", + Value: &c.cliConfig.Telemetry.OpenCollectorEndpoint, + Default: c.cliConfig.Telemetry.OpenCollectorEndpoint, + Group: "Telemetry", }) // influx db v2 f.BoolFlag(&flagset.BoolFlag{ - Name: "metrics.influxdbv2", - Usage: "Enable metrics export/push to an external InfluxDB v2 database", - Value: &c.cliConfig.Telemetry.InfluxDB.V2Enabled, + Name: "metrics.influxdbv2", + Usage: "Enable metrics export/push to an external InfluxDB v2 database", + Value: &c.cliConfig.Telemetry.InfluxDB.V2Enabled, + Default: c.cliConfig.Telemetry.InfluxDB.V2Enabled, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.influxdb.token", - Usage: "Token to authorize access to the database (v2 only)", - Value: &c.cliConfig.Telemetry.InfluxDB.Token, + Name: "metrics.influxdb.token", + Usage: "Token to authorize access to the database (v2 only)", + Value: &c.cliConfig.Telemetry.InfluxDB.Token, + Default: c.cliConfig.Telemetry.InfluxDB.Token, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.influxdb.bucket", - Usage: "InfluxDB bucket name to push reported metrics to (v2 only)", - Value: &c.cliConfig.Telemetry.InfluxDB.Bucket, + Name: "metrics.influxdb.bucket", + Usage: "InfluxDB bucket name to push reported metrics to (v2 only)", + Value: &c.cliConfig.Telemetry.InfluxDB.Bucket, + Default: c.cliConfig.Telemetry.InfluxDB.Bucket, + Group: "Telemetry", }) f.StringFlag(&flagset.StringFlag{ - Name: "metrics.influxdb.organization", - Usage: "InfluxDB organization name (v2 only)", - Value: &c.cliConfig.Telemetry.InfluxDB.Organization, + Name: "metrics.influxdb.organization", + Usage: "InfluxDB organization name (v2 only)", + Value: &c.cliConfig.Telemetry.InfluxDB.Organization, + Default: c.cliConfig.Telemetry.InfluxDB.Organization, + Group: "Telemetry", }) // account @@ -445,40 +584,56 @@ func (c *Command) Flags() *flagset.Flagset { Name: "unlock", Usage: "Comma separated list of accounts to unlock", Value: &c.cliConfig.Accounts.Unlock, + Group: "Account Management", }) f.StringFlag(&flagset.StringFlag{ - Name: "password", - Usage: "Password file to use for non-interactive password input", - Value: &c.cliConfig.Accounts.PasswordFile, + Name: "password", + Usage: "Password file to use for non-interactive password input", + Value: &c.cliConfig.Accounts.PasswordFile, + Default: c.cliConfig.Accounts.PasswordFile, + Group: "Account Management", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "allow-insecure-unlock", - Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http", - Value: &c.cliConfig.Accounts.AllowInsecureUnlock, + Name: "allow-insecure-unlock", + Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http", + Value: &c.cliConfig.Accounts.AllowInsecureUnlock, + Default: c.cliConfig.Accounts.AllowInsecureUnlock, + Group: "Account Management", }) f.BoolFlag(&flagset.BoolFlag{ - Name: "lightkdf", - Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", - Value: &c.cliConfig.Accounts.UseLightweightKDF, + Name: "lightkdf", + Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", + Value: &c.cliConfig.Accounts.UseLightweightKDF, + Default: c.cliConfig.Accounts.UseLightweightKDF, + Group: "Account Management", }) + f.BoolFlag((&flagset.BoolFlag{ + Name: "disable-bor-wallet", + Usage: "Disable the personal wallet endpoints", + Value: &c.cliConfig.Accounts.DisableBorWallet, + Default: c.cliConfig.Accounts.DisableBorWallet, + })) // grpc f.StringFlag(&flagset.StringFlag{ - Name: "grpc.addr", - Usage: "Address and port to bind the GRPC server", - Value: &c.cliConfig.GRPC.Addr, + Name: "grpc.addr", + Usage: "Address and port to bind the GRPC server", + Value: &c.cliConfig.GRPC.Addr, + Default: c.cliConfig.GRPC.Addr, }) // developer f.BoolFlag(&flagset.BoolFlag{ - Name: "dev", - Usage: "Enable developer mode with ephemeral proof-of-authority network and a pre-funded developer account, mining enabled", - Value: &c.cliConfig.Developer.Enabled, + Name: "dev", + Usage: "Enable developer mode with ephemeral proof-of-authority network and a pre-funded developer account, mining enabled", + Value: &c.cliConfig.Developer.Enabled, + Default: c.cliConfig.Developer.Enabled, }) f.Uint64Flag(&flagset.Uint64Flag{ - Name: "dev.period", - Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", - Value: &c.cliConfig.Developer.Period, + Name: "dev.period", + Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", + Value: &c.cliConfig.Developer.Period, + Default: c.cliConfig.Developer.Period, }) return f } diff --git a/internal/cli/server/helper.go b/internal/cli/server/helper.go new file mode 100644 index 0000000000..3a232d3185 --- /dev/null +++ b/internal/cli/server/helper.go @@ -0,0 +1,83 @@ +package server + +import ( + "fmt" + "io/ioutil" + "math/rand" + "net" + "os" + "sync/atomic" + "time" +) + +var maxPortCheck int32 = 100 + +// findAvailablePort returns the next available port starting from `from` +func findAvailablePort(from int32, count int32) (int32, error) { + if count == maxPortCheck { + return 0, fmt.Errorf("no available port found") + } + + port := atomic.AddInt32(&from, 1) + addr := fmt.Sprintf("localhost:%d", port) + + count++ + + lis, err := net.Listen("tcp", addr) + if err == nil { + lis.Close() + return port, nil + } else { + return findAvailablePort(from, count) + } +} + +func CreateMockServer(config *Config) (*Server, error) { + if config == nil { + config = DefaultConfig() + } + + // find available port for grpc server + rand.Seed(time.Now().UnixNano()) + + var ( + from int32 = 60000 // the min port to start checking from + to int32 = 61000 // the max port to start checking from + ) + + //nolint: gosec + port, err := findAvailablePort(rand.Int31n(to-from+1)+from, 0) + if err != nil { + return nil, err + } + + // grpc port + config.GRPC.Addr = fmt.Sprintf(":%d", port) + + // datadir + datadir, _ := ioutil.TempDir("/tmp", "bor-cli-test") + config.DataDir = datadir + + // find available port for http server + from = 8545 + to = 9545 + + //nolint: gosec + port, err = findAvailablePort(rand.Int31n(to-from+1)+from, 0) + if err != nil { + return nil, err + } + + config.JsonRPC.Http.Port = uint64(port) + + // start the server + return NewServer(config) +} + +func CloseMockServer(server *Server) { + // remove the contents of temp data dir + os.RemoveAll(server.config.DataDir) + + // close the server + server.Stop() +} diff --git a/internal/cli/server/proto/server.pb.go b/internal/cli/server/proto/server.pb.go index a709c538ae..5512d83b72 100644 --- a/internal/cli/server/proto/server.pb.go +++ b/internal/cli/server/proto/server.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.17.3 -// source: command/server/proto/server.proto +// protoc-gen-go v1.27.1 +// protoc v3.19.3 +// source: internal/cli/server/proto/server.proto package proto import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" @@ -22,57 +21,138 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -type PprofRequest_Type int32 +type DebugPprofRequest_Type int32 const ( - PprofRequest_LOOKUP PprofRequest_Type = 0 - PprofRequest_CPU PprofRequest_Type = 1 - PprofRequest_TRACE PprofRequest_Type = 2 + DebugPprofRequest_LOOKUP DebugPprofRequest_Type = 0 + DebugPprofRequest_CPU DebugPprofRequest_Type = 1 + DebugPprofRequest_TRACE DebugPprofRequest_Type = 2 ) -// Enum value maps for PprofRequest_Type. +// Enum value maps for DebugPprofRequest_Type. var ( - PprofRequest_Type_name = map[int32]string{ + DebugPprofRequest_Type_name = map[int32]string{ 0: "LOOKUP", 1: "CPU", 2: "TRACE", } - PprofRequest_Type_value = map[string]int32{ + DebugPprofRequest_Type_value = map[string]int32{ "LOOKUP": 0, "CPU": 1, "TRACE": 2, } ) -func (x PprofRequest_Type) Enum() *PprofRequest_Type { - p := new(PprofRequest_Type) +func (x DebugPprofRequest_Type) Enum() *DebugPprofRequest_Type { + p := new(DebugPprofRequest_Type) *p = x return p } -func (x PprofRequest_Type) String() string { +func (x DebugPprofRequest_Type) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (PprofRequest_Type) Descriptor() protoreflect.EnumDescriptor { - return file_command_server_proto_server_proto_enumTypes[0].Descriptor() +func (DebugPprofRequest_Type) Descriptor() protoreflect.EnumDescriptor { + return file_internal_cli_server_proto_server_proto_enumTypes[0].Descriptor() } -func (PprofRequest_Type) Type() protoreflect.EnumType { - return &file_command_server_proto_server_proto_enumTypes[0] +func (DebugPprofRequest_Type) Type() protoreflect.EnumType { + return &file_internal_cli_server_proto_server_proto_enumTypes[0] } -func (x PprofRequest_Type) Number() protoreflect.EnumNumber { +func (x DebugPprofRequest_Type) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use PprofRequest_Type.Descriptor instead. -func (PprofRequest_Type) EnumDescriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{16, 0} +// Deprecated: Use DebugPprofRequest_Type.Descriptor instead. +func (DebugPprofRequest_Type) EnumDescriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{18, 0} +} + +type TraceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Number int64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"` +} + +func (x *TraceRequest) Reset() { + *x = TraceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TraceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TraceRequest) ProtoMessage() {} + +func (x *TraceRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TraceRequest.ProtoReflect.Descriptor instead. +func (*TraceRequest) Descriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{0} +} + +func (x *TraceRequest) GetNumber() int64 { + if x != nil { + return x.Number + } + return 0 +} + +type TraceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *TraceResponse) Reset() { + *x = TraceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TraceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TraceResponse) ProtoMessage() {} + +func (x *TraceResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TraceResponse.ProtoReflect.Descriptor instead. +func (*TraceResponse) Descriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{1} } type ChainWatchRequest struct { @@ -84,7 +164,7 @@ type ChainWatchRequest struct { func (x *ChainWatchRequest) Reset() { *x = ChainWatchRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[0] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -97,7 +177,7 @@ func (x *ChainWatchRequest) String() string { func (*ChainWatchRequest) ProtoMessage() {} func (x *ChainWatchRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[0] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -110,7 +190,7 @@ func (x *ChainWatchRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainWatchRequest.ProtoReflect.Descriptor instead. func (*ChainWatchRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{0} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{2} } type ChainWatchResponse struct { @@ -126,7 +206,7 @@ type ChainWatchResponse struct { func (x *ChainWatchResponse) Reset() { *x = ChainWatchResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[1] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -139,7 +219,7 @@ func (x *ChainWatchResponse) String() string { func (*ChainWatchResponse) ProtoMessage() {} func (x *ChainWatchResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[1] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -152,7 +232,7 @@ func (x *ChainWatchResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainWatchResponse.ProtoReflect.Descriptor instead. func (*ChainWatchResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{1} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{3} } func (x *ChainWatchResponse) GetOldchain() []*BlockStub { @@ -188,7 +268,7 @@ type BlockStub struct { func (x *BlockStub) Reset() { *x = BlockStub{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[2] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -201,7 +281,7 @@ func (x *BlockStub) String() string { func (*BlockStub) ProtoMessage() {} func (x *BlockStub) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[2] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -214,7 +294,7 @@ func (x *BlockStub) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockStub.ProtoReflect.Descriptor instead. func (*BlockStub) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{2} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{4} } func (x *BlockStub) GetHash() string { @@ -243,7 +323,7 @@ type PeersAddRequest struct { func (x *PeersAddRequest) Reset() { *x = PeersAddRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[3] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -256,7 +336,7 @@ func (x *PeersAddRequest) String() string { func (*PeersAddRequest) ProtoMessage() {} func (x *PeersAddRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[3] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -269,7 +349,7 @@ func (x *PeersAddRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersAddRequest.ProtoReflect.Descriptor instead. func (*PeersAddRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{3} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{5} } func (x *PeersAddRequest) GetEnode() string { @@ -295,7 +375,7 @@ type PeersAddResponse struct { func (x *PeersAddResponse) Reset() { *x = PeersAddResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[4] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -308,7 +388,7 @@ func (x *PeersAddResponse) String() string { func (*PeersAddResponse) ProtoMessage() {} func (x *PeersAddResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[4] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -321,7 +401,7 @@ func (x *PeersAddResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersAddResponse.ProtoReflect.Descriptor instead. func (*PeersAddResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{4} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{6} } type PeersRemoveRequest struct { @@ -336,7 +416,7 @@ type PeersRemoveRequest struct { func (x *PeersRemoveRequest) Reset() { *x = PeersRemoveRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[5] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -349,7 +429,7 @@ func (x *PeersRemoveRequest) String() string { func (*PeersRemoveRequest) ProtoMessage() {} func (x *PeersRemoveRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[5] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -362,7 +442,7 @@ func (x *PeersRemoveRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersRemoveRequest.ProtoReflect.Descriptor instead. func (*PeersRemoveRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{5} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{7} } func (x *PeersRemoveRequest) GetEnode() string { @@ -388,7 +468,7 @@ type PeersRemoveResponse struct { func (x *PeersRemoveResponse) Reset() { *x = PeersRemoveResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[6] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -401,7 +481,7 @@ func (x *PeersRemoveResponse) String() string { func (*PeersRemoveResponse) ProtoMessage() {} func (x *PeersRemoveResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[6] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -414,7 +494,7 @@ func (x *PeersRemoveResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersRemoveResponse.ProtoReflect.Descriptor instead. func (*PeersRemoveResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{6} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{8} } type PeersListRequest struct { @@ -426,7 +506,7 @@ type PeersListRequest struct { func (x *PeersListRequest) Reset() { *x = PeersListRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[7] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -439,7 +519,7 @@ func (x *PeersListRequest) String() string { func (*PeersListRequest) ProtoMessage() {} func (x *PeersListRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[7] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -452,7 +532,7 @@ func (x *PeersListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersListRequest.ProtoReflect.Descriptor instead. func (*PeersListRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{7} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{9} } type PeersListResponse struct { @@ -466,7 +546,7 @@ type PeersListResponse struct { func (x *PeersListResponse) Reset() { *x = PeersListResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[8] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -479,7 +559,7 @@ func (x *PeersListResponse) String() string { func (*PeersListResponse) ProtoMessage() {} func (x *PeersListResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[8] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -492,7 +572,7 @@ func (x *PeersListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersListResponse.ProtoReflect.Descriptor instead. func (*PeersListResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{8} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{10} } func (x *PeersListResponse) GetPeers() []*Peer { @@ -513,7 +593,7 @@ type PeersStatusRequest struct { func (x *PeersStatusRequest) Reset() { *x = PeersStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[9] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -526,7 +606,7 @@ func (x *PeersStatusRequest) String() string { func (*PeersStatusRequest) ProtoMessage() {} func (x *PeersStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[9] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -539,7 +619,7 @@ func (x *PeersStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersStatusRequest.ProtoReflect.Descriptor instead. func (*PeersStatusRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{9} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{11} } func (x *PeersStatusRequest) GetEnode() string { @@ -560,7 +640,7 @@ type PeersStatusResponse struct { func (x *PeersStatusResponse) Reset() { *x = PeersStatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[10] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -573,7 +653,7 @@ func (x *PeersStatusResponse) String() string { func (*PeersStatusResponse) ProtoMessage() {} func (x *PeersStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[10] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -586,7 +666,7 @@ func (x *PeersStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersStatusResponse.ProtoReflect.Descriptor instead. func (*PeersStatusResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{10} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{12} } func (x *PeersStatusResponse) GetPeer() *Peer { @@ -613,7 +693,7 @@ type Peer struct { func (x *Peer) Reset() { *x = Peer{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[11] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -626,7 +706,7 @@ func (x *Peer) String() string { func (*Peer) ProtoMessage() {} func (x *Peer) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[11] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -639,7 +719,7 @@ func (x *Peer) ProtoReflect() protoreflect.Message { // Deprecated: Use Peer.ProtoReflect.Descriptor instead. func (*Peer) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{11} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{13} } func (x *Peer) GetId() string { @@ -702,7 +782,7 @@ type ChainSetHeadRequest struct { func (x *ChainSetHeadRequest) Reset() { *x = ChainSetHeadRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[12] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -715,7 +795,7 @@ func (x *ChainSetHeadRequest) String() string { func (*ChainSetHeadRequest) ProtoMessage() {} func (x *ChainSetHeadRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[12] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -728,7 +808,7 @@ func (x *ChainSetHeadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainSetHeadRequest.ProtoReflect.Descriptor instead. func (*ChainSetHeadRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{12} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{14} } func (x *ChainSetHeadRequest) GetNumber() uint64 { @@ -747,7 +827,7 @@ type ChainSetHeadResponse struct { func (x *ChainSetHeadResponse) Reset() { *x = ChainSetHeadResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[13] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -760,7 +840,7 @@ func (x *ChainSetHeadResponse) String() string { func (*ChainSetHeadResponse) ProtoMessage() {} func (x *ChainSetHeadResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[13] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -773,7 +853,7 @@ func (x *ChainSetHeadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainSetHeadResponse.ProtoReflect.Descriptor instead. func (*ChainSetHeadResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{13} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{15} } type StatusResponse struct { @@ -792,7 +872,7 @@ type StatusResponse struct { func (x *StatusResponse) Reset() { *x = StatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[14] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -805,7 +885,7 @@ func (x *StatusResponse) String() string { func (*StatusResponse) ProtoMessage() {} func (x *StatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[14] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -818,7 +898,7 @@ func (x *StatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead. func (*StatusResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{14} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{16} } func (x *StatusResponse) GetCurrentBlock() *Header { @@ -875,7 +955,7 @@ type Header struct { func (x *Header) Reset() { *x = Header{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[15] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -888,7 +968,7 @@ func (x *Header) String() string { func (*Header) ProtoMessage() {} func (x *Header) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[15] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -901,7 +981,7 @@ func (x *Header) ProtoReflect() protoreflect.Message { // Deprecated: Use Header.ProtoReflect.Descriptor instead. func (*Header) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{15} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{17} } func (x *Header) GetHash() string { @@ -918,33 +998,33 @@ func (x *Header) GetNumber() uint64 { return 0 } -type PprofRequest struct { +type DebugPprofRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type PprofRequest_Type `protobuf:"varint,1,opt,name=type,proto3,enum=proto.PprofRequest_Type" json:"type,omitempty"` - Profile string `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"` - Seconds int64 `protobuf:"varint,3,opt,name=seconds,proto3" json:"seconds,omitempty"` + Type DebugPprofRequest_Type `protobuf:"varint,1,opt,name=type,proto3,enum=proto.DebugPprofRequest_Type" json:"type,omitempty"` + Profile string `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"` + Seconds int64 `protobuf:"varint,3,opt,name=seconds,proto3" json:"seconds,omitempty"` } -func (x *PprofRequest) Reset() { - *x = PprofRequest{} +func (x *DebugPprofRequest) Reset() { + *x = DebugPprofRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[16] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *PprofRequest) String() string { +func (x *DebugPprofRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PprofRequest) ProtoMessage() {} +func (*DebugPprofRequest) ProtoMessage() {} -func (x *PprofRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[16] +func (x *DebugPprofRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -955,61 +1035,57 @@ func (x *PprofRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PprofRequest.ProtoReflect.Descriptor instead. -func (*PprofRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{16} +// Deprecated: Use DebugPprofRequest.ProtoReflect.Descriptor instead. +func (*DebugPprofRequest) Descriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{18} } -func (x *PprofRequest) GetType() PprofRequest_Type { +func (x *DebugPprofRequest) GetType() DebugPprofRequest_Type { if x != nil { return x.Type } - return PprofRequest_LOOKUP + return DebugPprofRequest_LOOKUP } -func (x *PprofRequest) GetProfile() string { +func (x *DebugPprofRequest) GetProfile() string { if x != nil { return x.Profile } return "" } -func (x *PprofRequest) GetSeconds() int64 { +func (x *DebugPprofRequest) GetSeconds() int64 { if x != nil { return x.Seconds } return 0 } -type PprofResponse struct { +type DebugBlockRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Types that are assignable to Event: - // *PprofResponse_Open_ - // *PprofResponse_Input_ - // *PprofResponse_Eof - Event isPprofResponse_Event `protobuf_oneof:"event"` + Number int64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"` } -func (x *PprofResponse) Reset() { - *x = PprofResponse{} +func (x *DebugBlockRequest) Reset() { + *x = DebugBlockRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[17] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *PprofResponse) String() string { +func (x *DebugBlockRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PprofResponse) ProtoMessage() {} +func (*DebugBlockRequest) ProtoMessage() {} -func (x *PprofResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[17] +func (x *DebugBlockRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1020,60 +1096,111 @@ func (x *PprofResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PprofResponse.ProtoReflect.Descriptor instead. -func (*PprofResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{17} +// Deprecated: Use DebugBlockRequest.ProtoReflect.Descriptor instead. +func (*DebugBlockRequest) Descriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{19} } -func (m *PprofResponse) GetEvent() isPprofResponse_Event { +func (x *DebugBlockRequest) GetNumber() int64 { + if x != nil { + return x.Number + } + return 0 +} + +type DebugFileResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Event: + // *DebugFileResponse_Open_ + // *DebugFileResponse_Input_ + // *DebugFileResponse_Eof + Event isDebugFileResponse_Event `protobuf_oneof:"event"` +} + +func (x *DebugFileResponse) Reset() { + *x = DebugFileResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DebugFileResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DebugFileResponse) ProtoMessage() {} + +func (x *DebugFileResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DebugFileResponse.ProtoReflect.Descriptor instead. +func (*DebugFileResponse) Descriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{20} +} + +func (m *DebugFileResponse) GetEvent() isDebugFileResponse_Event { if m != nil { return m.Event } return nil } -func (x *PprofResponse) GetOpen() *PprofResponse_Open { - if x, ok := x.GetEvent().(*PprofResponse_Open_); ok { +func (x *DebugFileResponse) GetOpen() *DebugFileResponse_Open { + if x, ok := x.GetEvent().(*DebugFileResponse_Open_); ok { return x.Open } return nil } -func (x *PprofResponse) GetInput() *PprofResponse_Input { - if x, ok := x.GetEvent().(*PprofResponse_Input_); ok { +func (x *DebugFileResponse) GetInput() *DebugFileResponse_Input { + if x, ok := x.GetEvent().(*DebugFileResponse_Input_); ok { return x.Input } return nil } -func (x *PprofResponse) GetEof() *emptypb.Empty { - if x, ok := x.GetEvent().(*PprofResponse_Eof); ok { +func (x *DebugFileResponse) GetEof() *emptypb.Empty { + if x, ok := x.GetEvent().(*DebugFileResponse_Eof); ok { return x.Eof } return nil } -type isPprofResponse_Event interface { - isPprofResponse_Event() +type isDebugFileResponse_Event interface { + isDebugFileResponse_Event() } -type PprofResponse_Open_ struct { - Open *PprofResponse_Open `protobuf:"bytes,1,opt,name=open,proto3,oneof"` +type DebugFileResponse_Open_ struct { + Open *DebugFileResponse_Open `protobuf:"bytes,1,opt,name=open,proto3,oneof"` } -type PprofResponse_Input_ struct { - Input *PprofResponse_Input `protobuf:"bytes,2,opt,name=input,proto3,oneof"` +type DebugFileResponse_Input_ struct { + Input *DebugFileResponse_Input `protobuf:"bytes,2,opt,name=input,proto3,oneof"` } -type PprofResponse_Eof struct { +type DebugFileResponse_Eof struct { Eof *emptypb.Empty `protobuf:"bytes,3,opt,name=eof,proto3,oneof"` } -func (*PprofResponse_Open_) isPprofResponse_Event() {} +func (*DebugFileResponse_Open_) isDebugFileResponse_Event() {} -func (*PprofResponse_Input_) isPprofResponse_Event() {} +func (*DebugFileResponse_Input_) isDebugFileResponse_Event() {} -func (*PprofResponse_Eof) isPprofResponse_Event() {} +func (*DebugFileResponse_Eof) isDebugFileResponse_Event() {} type StatusResponse_Fork struct { state protoimpl.MessageState @@ -1088,7 +1215,7 @@ type StatusResponse_Fork struct { func (x *StatusResponse_Fork) Reset() { *x = StatusResponse_Fork{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[18] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1101,7 +1228,7 @@ func (x *StatusResponse_Fork) String() string { func (*StatusResponse_Fork) ProtoMessage() {} func (x *StatusResponse_Fork) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[18] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1114,7 +1241,7 @@ func (x *StatusResponse_Fork) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusResponse_Fork.ProtoReflect.Descriptor instead. func (*StatusResponse_Fork) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{14, 0} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{16, 0} } func (x *StatusResponse_Fork) GetName() string { @@ -1151,7 +1278,7 @@ type StatusResponse_Syncing struct { func (x *StatusResponse_Syncing) Reset() { *x = StatusResponse_Syncing{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[19] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1164,7 +1291,7 @@ func (x *StatusResponse_Syncing) String() string { func (*StatusResponse_Syncing) ProtoMessage() {} func (x *StatusResponse_Syncing) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[19] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1177,7 +1304,7 @@ func (x *StatusResponse_Syncing) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusResponse_Syncing.ProtoReflect.Descriptor instead. func (*StatusResponse_Syncing) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{14, 1} + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{16, 1} } func (x *StatusResponse_Syncing) GetStartingBlock() int64 { @@ -1201,32 +1328,31 @@ func (x *StatusResponse_Syncing) GetCurrentBlock() int64 { return 0 } -type PprofResponse_Open struct { +type DebugFileResponse_Open struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Headers map[string]string `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` } -func (x *PprofResponse_Open) Reset() { - *x = PprofResponse_Open{} +func (x *DebugFileResponse_Open) Reset() { + *x = DebugFileResponse_Open{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[20] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *PprofResponse_Open) String() string { +func (x *DebugFileResponse_Open) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PprofResponse_Open) ProtoMessage() {} +func (*DebugFileResponse_Open) ProtoMessage() {} -func (x *PprofResponse_Open) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[20] +func (x *DebugFileResponse_Open) ProtoReflect() protoreflect.Message { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1237,26 +1363,19 @@ func (x *PprofResponse_Open) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PprofResponse_Open.ProtoReflect.Descriptor instead. -func (*PprofResponse_Open) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{17, 0} +// Deprecated: Use DebugFileResponse_Open.ProtoReflect.Descriptor instead. +func (*DebugFileResponse_Open) Descriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{20, 0} } -func (x *PprofResponse_Open) GetHeaders() map[string]string { +func (x *DebugFileResponse_Open) GetHeaders() map[string]string { if x != nil { return x.Headers } return nil } -func (x *PprofResponse_Open) GetSize() int64 { - if x != nil { - return x.Size - } - return 0 -} - -type PprofResponse_Input struct { +type DebugFileResponse_Input struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1264,23 +1383,23 @@ type PprofResponse_Input struct { Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` } -func (x *PprofResponse_Input) Reset() { - *x = PprofResponse_Input{} +func (x *DebugFileResponse_Input) Reset() { + *x = DebugFileResponse_Input{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[21] + mi := &file_internal_cli_server_proto_server_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *PprofResponse_Input) String() string { +func (x *DebugFileResponse_Input) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PprofResponse_Input) ProtoMessage() {} +func (*DebugFileResponse_Input) ProtoMessage() {} -func (x *PprofResponse_Input) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[21] +func (x *DebugFileResponse_Input) ProtoReflect() protoreflect.Message { + mi := &file_internal_cli_server_proto_server_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1291,263 +1410,305 @@ func (x *PprofResponse_Input) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PprofResponse_Input.ProtoReflect.Descriptor instead. -func (*PprofResponse_Input) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{17, 1} +// Deprecated: Use DebugFileResponse_Input.ProtoReflect.Descriptor instead. +func (*DebugFileResponse_Input) Descriptor() ([]byte, []int) { + return file_internal_cli_server_proto_server_proto_rawDescGZIP(), []int{20, 1} } -func (x *PprofResponse_Input) GetData() []byte { +func (x *DebugFileResponse_Input) GetData() []byte { if x != nil { return x.Data } return nil } -var File_command_server_proto_server_proto protoreflect.FileDescriptor +var File_internal_cli_server_proto_server_proto protoreflect.FileDescriptor -var file_command_server_proto_server_proto_rawDesc = []byte{ - 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x13, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x84, 0x01, 0x0a, - 0x12, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x6c, 0x64, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x62, 0x52, 0x08, 0x6f, 0x6c, 0x64, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x12, 0x2c, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, +var file_internal_cli_server_proto_server_proto_rawDesc = []byte{ + 0x0a, 0x26, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x26, 0x0a, 0x0c, + 0x54, 0x72, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x22, 0x0f, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, + 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x84, 0x01, 0x0a, 0x12, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x6c, 0x64, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x53, 0x74, 0x75, 0x62, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x37, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x62, - 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x41, 0x0a, 0x0f, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, - 0x12, 0x0a, 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x44, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, - 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x50, 0x65, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x12, 0x0a, 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x36, 0x0a, 0x11, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x65, 0x65, - 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x2a, 0x0a, 0x12, + 0x6b, 0x53, 0x74, 0x75, 0x62, 0x52, 0x08, 0x6f, 0x6c, 0x64, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, + 0x2c, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, + 0x74, 0x75, 0x62, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x37, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x62, 0x12, 0x12, + 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, + 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x41, 0x0a, 0x0f, 0x50, 0x65, + 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, + 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, 0x12, 0x0a, + 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x44, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, + 0x0a, 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x36, 0x0a, 0x11, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, + 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x2a, 0x0a, 0x12, 0x50, 0x65, + 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x36, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, + 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x22, 0x98, + 0x01, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x65, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x63, 0x61, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, + 0x61, 0x70, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x22, 0x2d, 0x0a, 0x13, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0xe2, 0x03, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x33, 0x0a, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0d, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x6e, + 0x75, 0x6d, 0x50, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6e, + 0x75, 0x6d, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x4d, + 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, + 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x30, 0x0a, 0x05, + 0x66, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x6b, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x6b, 0x73, 0x1a, 0x4c, + 0x0a, 0x04, 0x46, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x1a, 0x77, 0x0a, 0x07, + 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x22, 0x0a, + 0x0c, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x34, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xa2, 0x01, 0x0a, 0x11, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x31, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x50, 0x70, 0x72, + 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, + 0x43, 0x50, 0x55, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x02, + 0x22, 0x2b, 0x0a, 0x11, 0x44, 0x65, 0x62, 0x75, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xdd, 0x02, + 0x0a, 0x11, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4f, 0x70, 0x65, 0x6e, + 0x48, 0x00, 0x52, 0x04, 0x6f, 0x70, 0x65, 0x6e, 0x12, 0x36, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x48, 0x00, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x12, 0x2a, 0x0a, 0x03, 0x65, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x03, 0x65, 0x6f, 0x66, 0x1a, 0x88, 0x01, 0x0a, + 0x04, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, + 0x65, 0x62, 0x75, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x1b, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x32, 0xdd, 0x04, + 0x0a, 0x03, 0x42, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, + 0x64, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, + 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, + 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, + 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x36, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, - 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x1f, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, - 0x22, 0x98, 0x01, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, - 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, - 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, - 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x61, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x04, 0x63, 0x61, 0x70, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, - 0x73, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, - 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x22, 0x2d, 0x0a, 0x13, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0xe2, 0x03, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x33, 0x0a, 0x0d, 0x63, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0d, - 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, - 0x08, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x08, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x6e, - 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x6e, - 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x79, - 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x30, - 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x6b, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x6b, 0x73, - 0x1a, 0x4c, 0x0a, 0x04, 0x46, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x1a, 0x77, - 0x0a, 0x07, 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, - 0x22, 0x0a, 0x0c, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x34, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x98, 0x01, - 0x0a, 0x0c, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, - 0x22, 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x4f, 0x4f, 0x4b, - 0x55, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x10, 0x01, 0x12, 0x09, 0x0a, - 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x02, 0x22, 0xe1, 0x02, 0x0a, 0x0d, 0x50, 0x70, 0x72, - 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x6f, 0x70, - 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4f, - 0x70, 0x65, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x6f, 0x70, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x48, 0x00, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, - 0x2a, 0x0a, 0x03, 0x65, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x03, 0x65, 0x6f, 0x66, 0x1a, 0x98, 0x01, 0x0a, 0x04, - 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x40, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, - 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4f, 0x70, 0x65, 0x6e, - 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x1b, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x32, 0x8b, 0x04, 0x0a, - 0x03, 0x42, 0x6f, 0x72, 0x12, 0x34, 0x0a, 0x05, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x12, 0x13, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x08, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, - 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, - 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, - 0x09, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, - 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, - 0x0b, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, - 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, - 0x74, 0x63, 0x68, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x17, 0x5a, 0x15, 0x2f, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, + 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x43, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x18, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, 0x74, 0x63, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x50, 0x70, + 0x72, 0x6f, 0x66, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0a, 0x44, 0x65, 0x62, + 0x75, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x1c, 0x5a, + 0x1a, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( - file_command_server_proto_server_proto_rawDescOnce sync.Once - file_command_server_proto_server_proto_rawDescData = file_command_server_proto_server_proto_rawDesc + file_internal_cli_server_proto_server_proto_rawDescOnce sync.Once + file_internal_cli_server_proto_server_proto_rawDescData = file_internal_cli_server_proto_server_proto_rawDesc ) -func file_command_server_proto_server_proto_rawDescGZIP() []byte { - file_command_server_proto_server_proto_rawDescOnce.Do(func() { - file_command_server_proto_server_proto_rawDescData = protoimpl.X.CompressGZIP(file_command_server_proto_server_proto_rawDescData) +func file_internal_cli_server_proto_server_proto_rawDescGZIP() []byte { + file_internal_cli_server_proto_server_proto_rawDescOnce.Do(func() { + file_internal_cli_server_proto_server_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_cli_server_proto_server_proto_rawDescData) }) - return file_command_server_proto_server_proto_rawDescData + return file_internal_cli_server_proto_server_proto_rawDescData } -var file_command_server_proto_server_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_command_server_proto_server_proto_msgTypes = make([]protoimpl.MessageInfo, 23) -var file_command_server_proto_server_proto_goTypes = []interface{}{ - (PprofRequest_Type)(0), // 0: proto.PprofRequest.Type - (*ChainWatchRequest)(nil), // 1: proto.ChainWatchRequest - (*ChainWatchResponse)(nil), // 2: proto.ChainWatchResponse - (*BlockStub)(nil), // 3: proto.BlockStub - (*PeersAddRequest)(nil), // 4: proto.PeersAddRequest - (*PeersAddResponse)(nil), // 5: proto.PeersAddResponse - (*PeersRemoveRequest)(nil), // 6: proto.PeersRemoveRequest - (*PeersRemoveResponse)(nil), // 7: proto.PeersRemoveResponse - (*PeersListRequest)(nil), // 8: proto.PeersListRequest - (*PeersListResponse)(nil), // 9: proto.PeersListResponse - (*PeersStatusRequest)(nil), // 10: proto.PeersStatusRequest - (*PeersStatusResponse)(nil), // 11: proto.PeersStatusResponse - (*Peer)(nil), // 12: proto.Peer - (*ChainSetHeadRequest)(nil), // 13: proto.ChainSetHeadRequest - (*ChainSetHeadResponse)(nil), // 14: proto.ChainSetHeadResponse - (*StatusResponse)(nil), // 15: proto.StatusResponse - (*Header)(nil), // 16: proto.Header - (*PprofRequest)(nil), // 17: proto.PprofRequest - (*PprofResponse)(nil), // 18: proto.PprofResponse - (*StatusResponse_Fork)(nil), // 19: proto.StatusResponse.Fork - (*StatusResponse_Syncing)(nil), // 20: proto.StatusResponse.Syncing - (*PprofResponse_Open)(nil), // 21: proto.PprofResponse.Open - (*PprofResponse_Input)(nil), // 22: proto.PprofResponse.Input - nil, // 23: proto.PprofResponse.Open.HeadersEntry - (*emptypb.Empty)(nil), // 24: google.protobuf.Empty +var file_internal_cli_server_proto_server_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_internal_cli_server_proto_server_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_internal_cli_server_proto_server_proto_goTypes = []interface{}{ + (DebugPprofRequest_Type)(0), // 0: proto.DebugPprofRequest.Type + (*TraceRequest)(nil), // 1: proto.TraceRequest + (*TraceResponse)(nil), // 2: proto.TraceResponse + (*ChainWatchRequest)(nil), // 3: proto.ChainWatchRequest + (*ChainWatchResponse)(nil), // 4: proto.ChainWatchResponse + (*BlockStub)(nil), // 5: proto.BlockStub + (*PeersAddRequest)(nil), // 6: proto.PeersAddRequest + (*PeersAddResponse)(nil), // 7: proto.PeersAddResponse + (*PeersRemoveRequest)(nil), // 8: proto.PeersRemoveRequest + (*PeersRemoveResponse)(nil), // 9: proto.PeersRemoveResponse + (*PeersListRequest)(nil), // 10: proto.PeersListRequest + (*PeersListResponse)(nil), // 11: proto.PeersListResponse + (*PeersStatusRequest)(nil), // 12: proto.PeersStatusRequest + (*PeersStatusResponse)(nil), // 13: proto.PeersStatusResponse + (*Peer)(nil), // 14: proto.Peer + (*ChainSetHeadRequest)(nil), // 15: proto.ChainSetHeadRequest + (*ChainSetHeadResponse)(nil), // 16: proto.ChainSetHeadResponse + (*StatusResponse)(nil), // 17: proto.StatusResponse + (*Header)(nil), // 18: proto.Header + (*DebugPprofRequest)(nil), // 19: proto.DebugPprofRequest + (*DebugBlockRequest)(nil), // 20: proto.DebugBlockRequest + (*DebugFileResponse)(nil), // 21: proto.DebugFileResponse + (*StatusResponse_Fork)(nil), // 22: proto.StatusResponse.Fork + (*StatusResponse_Syncing)(nil), // 23: proto.StatusResponse.Syncing + (*DebugFileResponse_Open)(nil), // 24: proto.DebugFileResponse.Open + (*DebugFileResponse_Input)(nil), // 25: proto.DebugFileResponse.Input + nil, // 26: proto.DebugFileResponse.Open.HeadersEntry + (*emptypb.Empty)(nil), // 27: google.protobuf.Empty } -var file_command_server_proto_server_proto_depIdxs = []int32{ - 3, // 0: proto.ChainWatchResponse.oldchain:type_name -> proto.BlockStub - 3, // 1: proto.ChainWatchResponse.newchain:type_name -> proto.BlockStub - 12, // 2: proto.PeersListResponse.peers:type_name -> proto.Peer - 12, // 3: proto.PeersStatusResponse.peer:type_name -> proto.Peer - 16, // 4: proto.StatusResponse.currentBlock:type_name -> proto.Header - 16, // 5: proto.StatusResponse.currentHeader:type_name -> proto.Header - 20, // 6: proto.StatusResponse.syncing:type_name -> proto.StatusResponse.Syncing - 19, // 7: proto.StatusResponse.forks:type_name -> proto.StatusResponse.Fork - 0, // 8: proto.PprofRequest.type:type_name -> proto.PprofRequest.Type - 21, // 9: proto.PprofResponse.open:type_name -> proto.PprofResponse.Open - 22, // 10: proto.PprofResponse.input:type_name -> proto.PprofResponse.Input - 24, // 11: proto.PprofResponse.eof:type_name -> google.protobuf.Empty - 23, // 12: proto.PprofResponse.Open.headers:type_name -> proto.PprofResponse.Open.HeadersEntry - 17, // 13: proto.Bor.Pprof:input_type -> proto.PprofRequest - 4, // 14: proto.Bor.PeersAdd:input_type -> proto.PeersAddRequest - 6, // 15: proto.Bor.PeersRemove:input_type -> proto.PeersRemoveRequest - 8, // 16: proto.Bor.PeersList:input_type -> proto.PeersListRequest - 10, // 17: proto.Bor.PeersStatus:input_type -> proto.PeersStatusRequest - 13, // 18: proto.Bor.ChainSetHead:input_type -> proto.ChainSetHeadRequest - 24, // 19: proto.Bor.Status:input_type -> google.protobuf.Empty - 1, // 20: proto.Bor.ChainWatch:input_type -> proto.ChainWatchRequest - 18, // 21: proto.Bor.Pprof:output_type -> proto.PprofResponse - 5, // 22: proto.Bor.PeersAdd:output_type -> proto.PeersAddResponse - 7, // 23: proto.Bor.PeersRemove:output_type -> proto.PeersRemoveResponse - 9, // 24: proto.Bor.PeersList:output_type -> proto.PeersListResponse - 11, // 25: proto.Bor.PeersStatus:output_type -> proto.PeersStatusResponse - 14, // 26: proto.Bor.ChainSetHead:output_type -> proto.ChainSetHeadResponse - 15, // 27: proto.Bor.Status:output_type -> proto.StatusResponse - 2, // 28: proto.Bor.ChainWatch:output_type -> proto.ChainWatchResponse - 21, // [21:29] is the sub-list for method output_type - 13, // [13:21] is the sub-list for method input_type +var file_internal_cli_server_proto_server_proto_depIdxs = []int32{ + 5, // 0: proto.ChainWatchResponse.oldchain:type_name -> proto.BlockStub + 5, // 1: proto.ChainWatchResponse.newchain:type_name -> proto.BlockStub + 14, // 2: proto.PeersListResponse.peers:type_name -> proto.Peer + 14, // 3: proto.PeersStatusResponse.peer:type_name -> proto.Peer + 18, // 4: proto.StatusResponse.currentBlock:type_name -> proto.Header + 18, // 5: proto.StatusResponse.currentHeader:type_name -> proto.Header + 23, // 6: proto.StatusResponse.syncing:type_name -> proto.StatusResponse.Syncing + 22, // 7: proto.StatusResponse.forks:type_name -> proto.StatusResponse.Fork + 0, // 8: proto.DebugPprofRequest.type:type_name -> proto.DebugPprofRequest.Type + 24, // 9: proto.DebugFileResponse.open:type_name -> proto.DebugFileResponse.Open + 25, // 10: proto.DebugFileResponse.input:type_name -> proto.DebugFileResponse.Input + 27, // 11: proto.DebugFileResponse.eof:type_name -> google.protobuf.Empty + 26, // 12: proto.DebugFileResponse.Open.headers:type_name -> proto.DebugFileResponse.Open.HeadersEntry + 6, // 13: proto.Bor.PeersAdd:input_type -> proto.PeersAddRequest + 8, // 14: proto.Bor.PeersRemove:input_type -> proto.PeersRemoveRequest + 10, // 15: proto.Bor.PeersList:input_type -> proto.PeersListRequest + 12, // 16: proto.Bor.PeersStatus:input_type -> proto.PeersStatusRequest + 15, // 17: proto.Bor.ChainSetHead:input_type -> proto.ChainSetHeadRequest + 27, // 18: proto.Bor.Status:input_type -> google.protobuf.Empty + 3, // 19: proto.Bor.ChainWatch:input_type -> proto.ChainWatchRequest + 19, // 20: proto.Bor.DebugPprof:input_type -> proto.DebugPprofRequest + 20, // 21: proto.Bor.DebugBlock:input_type -> proto.DebugBlockRequest + 7, // 22: proto.Bor.PeersAdd:output_type -> proto.PeersAddResponse + 9, // 23: proto.Bor.PeersRemove:output_type -> proto.PeersRemoveResponse + 11, // 24: proto.Bor.PeersList:output_type -> proto.PeersListResponse + 13, // 25: proto.Bor.PeersStatus:output_type -> proto.PeersStatusResponse + 16, // 26: proto.Bor.ChainSetHead:output_type -> proto.ChainSetHeadResponse + 17, // 27: proto.Bor.Status:output_type -> proto.StatusResponse + 4, // 28: proto.Bor.ChainWatch:output_type -> proto.ChainWatchResponse + 21, // 29: proto.Bor.DebugPprof:output_type -> proto.DebugFileResponse + 21, // 30: proto.Bor.DebugBlock:output_type -> proto.DebugFileResponse + 22, // [22:31] is the sub-list for method output_type + 13, // [13:22] is the sub-list for method input_type 13, // [13:13] is the sub-list for extension type_name 13, // [13:13] is the sub-list for extension extendee 0, // [0:13] is the sub-list for field type_name } -func init() { file_command_server_proto_server_proto_init() } -func file_command_server_proto_server_proto_init() { - if File_command_server_proto_server_proto != nil { +func init() { file_internal_cli_server_proto_server_proto_init() } +func file_internal_cli_server_proto_server_proto_init() { + if File_internal_cli_server_proto_server_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_command_server_proto_server_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TraceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_cli_server_proto_server_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TraceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_cli_server_proto_server_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChainWatchRequest); i { case 0: return &v.state @@ -1559,7 +1720,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChainWatchResponse); i { case 0: return &v.state @@ -1571,7 +1732,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlockStub); i { case 0: return &v.state @@ -1583,7 +1744,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersAddRequest); i { case 0: return &v.state @@ -1595,7 +1756,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersAddResponse); i { case 0: return &v.state @@ -1607,7 +1768,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersRemoveRequest); i { case 0: return &v.state @@ -1619,7 +1780,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersRemoveResponse); i { case 0: return &v.state @@ -1631,7 +1792,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersListRequest); i { case 0: return &v.state @@ -1643,7 +1804,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersListResponse); i { case 0: return &v.state @@ -1655,7 +1816,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersStatusRequest); i { case 0: return &v.state @@ -1667,7 +1828,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PeersStatusResponse); i { case 0: return &v.state @@ -1679,7 +1840,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Peer); i { case 0: return &v.state @@ -1691,7 +1852,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChainSetHeadRequest); i { case 0: return &v.state @@ -1703,7 +1864,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChainSetHeadResponse); i { case 0: return &v.state @@ -1715,7 +1876,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusResponse); i { case 0: return &v.state @@ -1727,7 +1888,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Header); i { case 0: return &v.state @@ -1739,8 +1900,8 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PprofRequest); i { + file_internal_cli_server_proto_server_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DebugPprofRequest); i { case 0: return &v.state case 1: @@ -1751,8 +1912,8 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PprofResponse); i { + file_internal_cli_server_proto_server_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DebugBlockRequest); i { case 0: return &v.state case 1: @@ -1763,7 +1924,19 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DebugFileResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_cli_server_proto_server_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusResponse_Fork); i { case 0: return &v.state @@ -1775,7 +1948,7 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_internal_cli_server_proto_server_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusResponse_Syncing); i { case 0: return &v.state @@ -1787,8 +1960,8 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PprofResponse_Open); i { + file_internal_cli_server_proto_server_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DebugFileResponse_Open); i { case 0: return &v.state case 1: @@ -1799,8 +1972,8 @@ func file_command_server_proto_server_proto_init() { return nil } } - file_command_server_proto_server_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PprofResponse_Input); i { + file_internal_cli_server_proto_server_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DebugFileResponse_Input); i { case 0: return &v.state case 1: @@ -1812,28 +1985,28 @@ func file_command_server_proto_server_proto_init() { } } } - file_command_server_proto_server_proto_msgTypes[17].OneofWrappers = []interface{}{ - (*PprofResponse_Open_)(nil), - (*PprofResponse_Input_)(nil), - (*PprofResponse_Eof)(nil), + file_internal_cli_server_proto_server_proto_msgTypes[20].OneofWrappers = []interface{}{ + (*DebugFileResponse_Open_)(nil), + (*DebugFileResponse_Input_)(nil), + (*DebugFileResponse_Eof)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_command_server_proto_server_proto_rawDesc, + RawDescriptor: file_internal_cli_server_proto_server_proto_rawDesc, NumEnums: 1, - NumMessages: 23, + NumMessages: 26, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_command_server_proto_server_proto_goTypes, - DependencyIndexes: file_command_server_proto_server_proto_depIdxs, - EnumInfos: file_command_server_proto_server_proto_enumTypes, - MessageInfos: file_command_server_proto_server_proto_msgTypes, + GoTypes: file_internal_cli_server_proto_server_proto_goTypes, + DependencyIndexes: file_internal_cli_server_proto_server_proto_depIdxs, + EnumInfos: file_internal_cli_server_proto_server_proto_enumTypes, + MessageInfos: file_internal_cli_server_proto_server_proto_msgTypes, }.Build() - File_command_server_proto_server_proto = out.File - file_command_server_proto_server_proto_rawDesc = nil - file_command_server_proto_server_proto_goTypes = nil - file_command_server_proto_server_proto_depIdxs = nil + File_internal_cli_server_proto_server_proto = out.File + file_internal_cli_server_proto_server_proto_rawDesc = nil + file_internal_cli_server_proto_server_proto_goTypes = nil + file_internal_cli_server_proto_server_proto_depIdxs = nil } diff --git a/internal/cli/server/proto/server.proto b/internal/cli/server/proto/server.proto index 2dc84bff78..1520ab6536 100644 --- a/internal/cli/server/proto/server.proto +++ b/internal/cli/server/proto/server.proto @@ -4,11 +4,9 @@ package proto; import "google/protobuf/empty.proto"; -option go_package = "/command/server/proto"; +option go_package = "/internal/cli/server/proto"; service Bor { - rpc Pprof(PprofRequest) returns (stream PprofResponse); - rpc PeersAdd(PeersAddRequest) returns (PeersAddResponse); rpc PeersRemove(PeersRemoveRequest) returns (PeersRemoveResponse); @@ -20,8 +18,20 @@ service Bor { rpc ChainSetHead(ChainSetHeadRequest) returns (ChainSetHeadResponse); rpc Status(google.protobuf.Empty) returns (StatusResponse); - + rpc ChainWatch(ChainWatchRequest) returns (stream ChainWatchResponse); + + rpc DebugPprof(DebugPprofRequest) returns (stream DebugFileResponse); + + rpc DebugBlock(DebugBlockRequest) returns (stream DebugFileResponse); +} + +message TraceRequest { + int64 number = 1; +} + +message TraceResponse { + } message ChainWatchRequest { @@ -113,7 +123,7 @@ message Header { uint64 number = 2; } -message PprofRequest { +message DebugPprofRequest { Type type = 1; string profile = 2; @@ -127,7 +137,11 @@ message PprofRequest { } } -message PprofResponse { +message DebugBlockRequest { + int64 number = 1; +} + +message DebugFileResponse { oneof event { Open open = 1; Input input = 2; @@ -136,7 +150,6 @@ message PprofResponse { message Open { map headers = 1; - int64 size = 2; } message Input { diff --git a/internal/cli/server/proto/server_grpc.pb.go b/internal/cli/server/proto/server_grpc.pb.go index 9ed2593e47..63f1fa6187 100644 --- a/internal/cli/server/proto/server_grpc.pb.go +++ b/internal/cli/server/proto/server_grpc.pb.go @@ -1,8 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v3.17.3 -// source: command/server/proto/server.proto +// - protoc v3.19.3 +// source: internal/cli/server/proto/server.proto package proto @@ -23,7 +23,6 @@ const _ = grpc.SupportPackageIsVersion7 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type BorClient interface { - Pprof(ctx context.Context, in *PprofRequest, opts ...grpc.CallOption) (Bor_PprofClient, error) PeersAdd(ctx context.Context, in *PeersAddRequest, opts ...grpc.CallOption) (*PeersAddResponse, error) PeersRemove(ctx context.Context, in *PeersRemoveRequest, opts ...grpc.CallOption) (*PeersRemoveResponse, error) PeersList(ctx context.Context, in *PeersListRequest, opts ...grpc.CallOption) (*PeersListResponse, error) @@ -31,6 +30,8 @@ type BorClient interface { ChainSetHead(ctx context.Context, in *ChainSetHeadRequest, opts ...grpc.CallOption) (*ChainSetHeadResponse, error) Status(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*StatusResponse, error) ChainWatch(ctx context.Context, in *ChainWatchRequest, opts ...grpc.CallOption) (Bor_ChainWatchClient, error) + DebugPprof(ctx context.Context, in *DebugPprofRequest, opts ...grpc.CallOption) (Bor_DebugPprofClient, error) + DebugBlock(ctx context.Context, in *DebugBlockRequest, opts ...grpc.CallOption) (Bor_DebugBlockClient, error) } type borClient struct { @@ -41,38 +42,6 @@ func NewBorClient(cc grpc.ClientConnInterface) BorClient { return &borClient{cc} } -func (c *borClient) Pprof(ctx context.Context, in *PprofRequest, opts ...grpc.CallOption) (Bor_PprofClient, error) { - stream, err := c.cc.NewStream(ctx, &Bor_ServiceDesc.Streams[0], "/proto.Bor/Pprof", opts...) - if err != nil { - return nil, err - } - x := &borPprofClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type Bor_PprofClient interface { - Recv() (*PprofResponse, error) - grpc.ClientStream -} - -type borPprofClient struct { - grpc.ClientStream -} - -func (x *borPprofClient) Recv() (*PprofResponse, error) { - m := new(PprofResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - func (c *borClient) PeersAdd(ctx context.Context, in *PeersAddRequest, opts ...grpc.CallOption) (*PeersAddResponse, error) { out := new(PeersAddResponse) err := c.cc.Invoke(ctx, "/proto.Bor/PeersAdd", in, out, opts...) @@ -128,7 +97,7 @@ func (c *borClient) Status(ctx context.Context, in *emptypb.Empty, opts ...grpc. } func (c *borClient) ChainWatch(ctx context.Context, in *ChainWatchRequest, opts ...grpc.CallOption) (Bor_ChainWatchClient, error) { - stream, err := c.cc.NewStream(ctx, &Bor_ServiceDesc.Streams[1], "/proto.Bor/ChainWatch", opts...) + stream, err := c.cc.NewStream(ctx, &Bor_ServiceDesc.Streams[0], "/proto.Bor/ChainWatch", opts...) if err != nil { return nil, err } @@ -159,11 +128,74 @@ func (x *borChainWatchClient) Recv() (*ChainWatchResponse, error) { return m, nil } +func (c *borClient) DebugPprof(ctx context.Context, in *DebugPprofRequest, opts ...grpc.CallOption) (Bor_DebugPprofClient, error) { + stream, err := c.cc.NewStream(ctx, &Bor_ServiceDesc.Streams[1], "/proto.Bor/DebugPprof", opts...) + if err != nil { + return nil, err + } + x := &borDebugPprofClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Bor_DebugPprofClient interface { + Recv() (*DebugFileResponse, error) + grpc.ClientStream +} + +type borDebugPprofClient struct { + grpc.ClientStream +} + +func (x *borDebugPprofClient) Recv() (*DebugFileResponse, error) { + m := new(DebugFileResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *borClient) DebugBlock(ctx context.Context, in *DebugBlockRequest, opts ...grpc.CallOption) (Bor_DebugBlockClient, error) { + stream, err := c.cc.NewStream(ctx, &Bor_ServiceDesc.Streams[2], "/proto.Bor/DebugBlock", opts...) + if err != nil { + return nil, err + } + x := &borDebugBlockClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Bor_DebugBlockClient interface { + Recv() (*DebugFileResponse, error) + grpc.ClientStream +} + +type borDebugBlockClient struct { + grpc.ClientStream +} + +func (x *borDebugBlockClient) Recv() (*DebugFileResponse, error) { + m := new(DebugFileResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // BorServer is the server API for Bor service. // All implementations must embed UnimplementedBorServer // for forward compatibility type BorServer interface { - Pprof(*PprofRequest, Bor_PprofServer) error PeersAdd(context.Context, *PeersAddRequest) (*PeersAddResponse, error) PeersRemove(context.Context, *PeersRemoveRequest) (*PeersRemoveResponse, error) PeersList(context.Context, *PeersListRequest) (*PeersListResponse, error) @@ -171,6 +203,8 @@ type BorServer interface { ChainSetHead(context.Context, *ChainSetHeadRequest) (*ChainSetHeadResponse, error) Status(context.Context, *emptypb.Empty) (*StatusResponse, error) ChainWatch(*ChainWatchRequest, Bor_ChainWatchServer) error + DebugPprof(*DebugPprofRequest, Bor_DebugPprofServer) error + DebugBlock(*DebugBlockRequest, Bor_DebugBlockServer) error mustEmbedUnimplementedBorServer() } @@ -178,9 +212,6 @@ type BorServer interface { type UnimplementedBorServer struct { } -func (UnimplementedBorServer) Pprof(*PprofRequest, Bor_PprofServer) error { - return status.Errorf(codes.Unimplemented, "method Pprof not implemented") -} func (UnimplementedBorServer) PeersAdd(context.Context, *PeersAddRequest) (*PeersAddResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PeersAdd not implemented") } @@ -202,6 +233,12 @@ func (UnimplementedBorServer) Status(context.Context, *emptypb.Empty) (*StatusRe func (UnimplementedBorServer) ChainWatch(*ChainWatchRequest, Bor_ChainWatchServer) error { return status.Errorf(codes.Unimplemented, "method ChainWatch not implemented") } +func (UnimplementedBorServer) DebugPprof(*DebugPprofRequest, Bor_DebugPprofServer) error { + return status.Errorf(codes.Unimplemented, "method DebugPprof not implemented") +} +func (UnimplementedBorServer) DebugBlock(*DebugBlockRequest, Bor_DebugBlockServer) error { + return status.Errorf(codes.Unimplemented, "method DebugBlock not implemented") +} func (UnimplementedBorServer) mustEmbedUnimplementedBorServer() {} // UnsafeBorServer may be embedded to opt out of forward compatibility for this service. @@ -215,27 +252,6 @@ func RegisterBorServer(s grpc.ServiceRegistrar, srv BorServer) { s.RegisterService(&Bor_ServiceDesc, srv) } -func _Bor_Pprof_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(PprofRequest) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(BorServer).Pprof(m, &borPprofServer{stream}) -} - -type Bor_PprofServer interface { - Send(*PprofResponse) error - grpc.ServerStream -} - -type borPprofServer struct { - grpc.ServerStream -} - -func (x *borPprofServer) Send(m *PprofResponse) error { - return x.ServerStream.SendMsg(m) -} - func _Bor_PeersAdd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(PeersAddRequest) if err := dec(in); err != nil { @@ -365,6 +381,48 @@ func (x *borChainWatchServer) Send(m *ChainWatchResponse) error { return x.ServerStream.SendMsg(m) } +func _Bor_DebugPprof_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(DebugPprofRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(BorServer).DebugPprof(m, &borDebugPprofServer{stream}) +} + +type Bor_DebugPprofServer interface { + Send(*DebugFileResponse) error + grpc.ServerStream +} + +type borDebugPprofServer struct { + grpc.ServerStream +} + +func (x *borDebugPprofServer) Send(m *DebugFileResponse) error { + return x.ServerStream.SendMsg(m) +} + +func _Bor_DebugBlock_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(DebugBlockRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(BorServer).DebugBlock(m, &borDebugBlockServer{stream}) +} + +type Bor_DebugBlockServer interface { + Send(*DebugFileResponse) error + grpc.ServerStream +} + +type borDebugBlockServer struct { + grpc.ServerStream +} + +func (x *borDebugBlockServer) Send(m *DebugFileResponse) error { + return x.ServerStream.SendMsg(m) +} + // Bor_ServiceDesc is the grpc.ServiceDesc for Bor service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -398,16 +456,21 @@ var Bor_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{ - { - StreamName: "Pprof", - Handler: _Bor_Pprof_Handler, - ServerStreams: true, - }, { StreamName: "ChainWatch", Handler: _Bor_ChainWatch_Handler, ServerStreams: true, }, + { + StreamName: "DebugPprof", + Handler: _Bor_DebugPprof_Handler, + ServerStreams: true, + }, + { + StreamName: "DebugBlock", + Handler: _Bor_DebugBlock_Handler, + ServerStreams: true, + }, }, - Metadata: "command/server/proto/server.proto", + Metadata: "internal/cli/server/proto/server.proto", } diff --git a/internal/cli/server/server.go b/internal/cli/server/server.go index e882429e86..7d5ec2c8f3 100644 --- a/internal/cli/server/server.go +++ b/internal/cli/server/server.go @@ -4,13 +4,28 @@ import ( "context" "fmt" "io" + "math/big" "net" "net/http" "os" "strings" "time" + "github.com/mattn/go-colorable" + "github.com/mattn/go-isatty" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + "google.golang.org/grpc" + + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/bor" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethstats" @@ -21,15 +36,6 @@ import ( "github.com/ethereum/go-ethereum/metrics/influxdb" "github.com/ethereum/go-ethereum/metrics/prometheus" "github.com/ethereum/go-ethereum/node" - "github.com/mattn/go-colorable" - "github.com/mattn/go-isatty" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" - "go.opentelemetry.io/otel/propagation" - "go.opentelemetry.io/otel/sdk/resource" - sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.4.0" - "google.golang.org/grpc" ) type Server struct { @@ -39,6 +45,9 @@ type Server struct { grpcServer *grpc.Server tracer *sdktrace.TracerProvider config *Config + + // tracerAPI to trace block executions + tracerAPI *tracers.API } func NewServer(config *Config) (*Server, error) { @@ -63,54 +72,131 @@ func NewServer(config *Config) (*Server, error) { if err != nil { return nil, err } + stack, err := node.New(nodeCfg) if err != nil { return nil, err } - srv.node = stack // setup account manager (only keystore) - { - keydir := stack.KeyStoreDir() - n, p := keystore.StandardScryptN, keystore.StandardScryptP - if config.Accounts.UseLightweightKDF { - n, p = keystore.LightScryptN, keystore.LightScryptP - } + // create a new account manager, only for the scope of this function + accountManager := accounts.NewManager(&accounts.Config{}) + + // register backend to account manager with keystore for signing + keydir := stack.KeyStoreDir() + + n, p := keystore.StandardScryptN, keystore.StandardScryptP + if config.Accounts.UseLightweightKDF { + n, p = keystore.LightScryptN, keystore.LightScryptP + } + + // proceed to authorize the local account manager in any case + accountManager.AddBackend(keystore.NewKeyStore(keydir, n, p)) + + // flag to set if we're authorizing consensus here + authorized := false + + // check if personal wallet endpoints are disabled or not + // nolint:nestif + if !config.Accounts.DisableBorWallet { + // add keystore globally to the node's account manager if personal wallet is enabled stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p)) + + // register the ethereum backend + ethCfg, err := config.buildEth(stack, stack.AccountManager()) + if err != nil { + return nil, err + } + + backend, err := eth.New(stack, ethCfg) + if err != nil { + return nil, err + } + + srv.backend = backend + } else { + // register the ethereum backend (with temporary created account manager) + ethCfg, err := config.buildEth(stack, accountManager) + if err != nil { + return nil, err + } + + backend, err := eth.New(stack, ethCfg) + if err != nil { + return nil, err + } + + srv.backend = backend + + // authorize only if mining or in developer mode + if config.Sealer.Enabled || config.Developer.Enabled { + // get the etherbase + eb, err := srv.backend.Etherbase() + if err != nil { + log.Error("Cannot start mining without etherbase", "err", err) + + return nil, fmt.Errorf("etherbase missing: %v", err) + } + + // Authorize the clique consensus (if chosen) to sign using wallet signer + var cli *clique.Clique + if c, ok := srv.backend.Engine().(*clique.Clique); ok { + cli = c + } else if cl, ok := srv.backend.Engine().(*beacon.Beacon); ok { + if c, ok := cl.InnerEngine().(*clique.Clique); ok { + cli = c + } + } + if cli != nil { + wallet, err := accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", err) + + return nil, fmt.Errorf("signer missing: %v", err) + } + + cli.Authorize(eb, wallet.SignData) + authorized = true + } + + // Authorize the bor consensus (if chosen) to sign using wallet signer + if bor, ok := srv.backend.Engine().(*bor.Bor); ok { + wallet, err := accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", err) + return nil, fmt.Errorf("signer missing: %v", err) + } + + bor.Authorize(eb, wallet.SignData) + authorized = true + } + } } - // register the ethereum backend - ethCfg, err := config.buildEth(stack) - if err != nil { - return nil, err - } - - backend, err := eth.New(stack, ethCfg) - if err != nil { - return nil, err - } - srv.backend = backend + // set the auth status in backend + srv.backend.SetAuthorized(authorized) // debug tracing is enabled by default - stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) + stack.RegisterAPIs(tracers.APIs(srv.backend.APIBackend)) + srv.tracerAPI = tracers.NewAPI(srv.backend.APIBackend) // graphql is started from another place if config.JsonRPC.Graphql.Enabled { - if err := graphql.New(stack, backend.APIBackend, config.JsonRPC.Cors, config.JsonRPC.VHost); err != nil { + if err := graphql.New(stack, srv.backend.APIBackend, config.JsonRPC.Cors, config.JsonRPC.VHost); err != nil { return nil, fmt.Errorf("failed to register the GraphQL service: %v", err) } } // register ethash service if config.Ethstats != "" { - if err := ethstats.New(stack, backend.APIBackend, backend.Engine(), config.Ethstats); err != nil { + if err := ethstats.New(stack, srv.backend.APIBackend, srv.backend.Engine(), config.Ethstats); err != nil { return nil, err } } // sealing (if enabled) or in dev mode if config.Sealer.Enabled || config.Developer.Enabled { - if err := backend.StartMining(1); err != nil { + if err := srv.backend.StartMining(1); err != nil { return nil, err } } @@ -119,15 +205,20 @@ func NewServer(config *Config) (*Server, error) { return nil, err } + // Set the node instance + srv.node = stack + // start the node if err := srv.node.Start(); err != nil { return nil, err } + return srv, nil } func (s *Server) Stop() { s.node.Close() + s.grpcServer.Stop() // shutdown the tracer if s.tracer != nil { @@ -160,10 +251,12 @@ func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error if v1Enabled { log.Info("Enabling metrics export to InfluxDB (v1)") + go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, cfg.Database, cfg.Username, cfg.Password, "geth.", tags) } if v2Enabled { log.Info("Enabling metrics export to InfluxDB (v2)") + go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, cfg.Token, cfg.Bucket, cfg.Organization, "geth.", tags) } } @@ -175,9 +268,7 @@ func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error prometheusMux := http.NewServeMux() - prometheusMux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { - prometheus.Handler(metrics.DefaultRegistry) - }) + prometheusMux.Handle("/debug/metrics/prometheus", prometheus.Handler(metrics.DefaultRegistry)) promServer := &http.Server{ Addr: config.PrometheusAddr, @@ -252,6 +343,7 @@ func (s *Server) setupGRPCServer(addr string) error { }() log.Info("GRPC Server started", "addr", addr) + return nil } @@ -262,16 +354,20 @@ func (s *Server) withLoggingUnaryInterceptor() grpc.ServerOption { func (s *Server) loggingServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { start := time.Now() h, err := handler(ctx, req) + log.Trace("Request", "method", info.FullMethod, "duration", time.Since(start), "error", err) + return h, err } func setupLogger(logLevel string) { output := io.Writer(os.Stderr) + usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" if usecolor { output = colorable.NewColorableStderr() } + ostream := log.StreamHandler(output, log.TerminalFormat(usecolor)) glogger := log.NewGlogHandler(ostream) @@ -282,5 +378,14 @@ func setupLogger(logLevel string) { } else { glogger.Verbosity(log.LvlInfo) } + log.Root().SetHandler(glogger) } + +func (s *Server) GetLatestBlockNumber() *big.Int { + return s.backend.BlockChain().CurrentBlock().Number() +} + +func (s *Server) GetGrpcAddr() string { + return s.config.GRPC.Addr[1:] +} diff --git a/internal/cli/server/server_test.go b/internal/cli/server/server_test.go index 070739c687..c88c656b10 100644 --- a/internal/cli/server/server_test.go +++ b/internal/cli/server/server_test.go @@ -1,13 +1,37 @@ package server import ( + "fmt" + "net" + "sync/atomic" "testing" "time" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/assert" ) +var initialPort uint64 = 61000 + +// nextPort gives the next available port starting from 60000 +func nextPort() uint64 { + log.Info("Checking for new port", "current", initialPort) + port := atomic.AddUint64(&initialPort, 1) + addr := fmt.Sprintf("localhost:%d", port) + + lis, err := net.Listen("tcp", addr) + if err == nil { + lis.Close() + + return port + } else { + return nextPort() + } +} + func TestServer_DeveloperMode(t *testing.T) { + t.Parallel() // get the default config config := DefaultConfig() @@ -16,17 +40,17 @@ func TestServer_DeveloperMode(t *testing.T) { config.Developer.Enabled = true config.Developer.Period = 2 // block time - // start the server - server, err1 := NewServer(config) - if err1 != nil { - t.Fatalf("failed to start server: %v", err1) - } + // start the mock server + server, err := CreateMockServer(config) + assert.NoError(t, err) + + defer CloseMockServer(server) // record the initial block number blockNumber := server.backend.BlockChain().CurrentBlock().Header().Number.Int64() var i int64 = 0 - for i = 0; i < 10; i++ { + for i = 0; i < 3; i++ { // We expect the node to mine blocks every `config.Developer.Period` time period time.Sleep(time.Duration(config.Developer.Period) * time.Second) currBlock := server.backend.BlockChain().CurrentBlock().Header().Number.Int64() @@ -35,7 +59,4 @@ func TestServer_DeveloperMode(t *testing.T) { break } } - - // stop the server - server.Stop() } diff --git a/internal/cli/server/service.go b/internal/cli/server/service.go index e8e3928581..de240d5461 100644 --- a/internal/cli/server/service.go +++ b/internal/cli/server/service.go @@ -2,46 +2,34 @@ package server import ( "context" + "encoding/json" "fmt" "math/big" "reflect" "strings" + gproto "github.com/golang/protobuf/proto" //nolint:staticcheck,typecheck + "github.com/golang/protobuf/ptypes/empty" + grpc_net_conn "github.com/mitchellh/go-grpc-net-conn" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/cli/server/pprof" "github.com/ethereum/go-ethereum/internal/cli/server/proto" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" - gproto "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/empty" - grpc_net_conn "github.com/mitchellh/go-grpc-net-conn" ) -func (s *Server) Pprof(req *proto.PprofRequest, stream proto.Bor_PprofServer) error { - var payload []byte - var headers map[string]string - var err error - - ctx := context.Background() - switch req.Type { - case proto.PprofRequest_CPU: - payload, headers, err = pprof.CPUProfile(ctx, int(req.Seconds)) - case proto.PprofRequest_TRACE: - payload, headers, err = pprof.Trace(ctx, int(req.Seconds)) - case proto.PprofRequest_LOOKUP: - payload, headers, err = pprof.Profile(req.Profile, 0, 0) - } - if err != nil { - return err - } +const chunkSize = 1024 * 1024 * 1024 +func sendStreamDebugFile(stream proto.Bor_DebugPprofServer, headers map[string]string, data []byte) error { // open the stream and send the headers - err = stream.Send(&proto.PprofResponse{ - Event: &proto.PprofResponse_Open_{ - Open: &proto.PprofResponse_Open{ + err := stream.Send(&proto.DebugFileResponse{ + Event: &proto.DebugFileResponse_Open_{ + Open: &proto.DebugFileResponse_Open{ Headers: headers, - Size: int64(len(payload)), }, }, }) @@ -50,24 +38,57 @@ func (s *Server) Pprof(req *proto.PprofRequest, stream proto.Bor_PprofServer) er } // Wrap our conn around the response. + encoder := grpc_net_conn.SimpleEncoder(func(msg gproto.Message) *[]byte { + return &msg.(*proto.DebugFileResponse_Input).Data + }) conn := &grpc_net_conn.Conn{ Stream: stream, - Request: &proto.PprofResponse_Input{}, - Encode: grpc_net_conn.SimpleEncoder(func(msg gproto.Message) *[]byte { - return &msg.(*proto.PprofResponse_Input).Data - }), + Request: &proto.DebugFileResponse_Input{}, + Encode: grpc_net_conn.ChunkedEncoder(encoder, chunkSize), } - if _, err := conn.Write(payload); err != nil { + + if _, err := conn.Write(data); err != nil { return err } // send the eof - err = stream.Send(&proto.PprofResponse{ - Event: &proto.PprofResponse_Eof{}, + err = stream.Send(&proto.DebugFileResponse{ + Event: &proto.DebugFileResponse_Eof{}, }) if err != nil { return err } + + return nil +} + +func (s *Server) DebugPprof(req *proto.DebugPprofRequest, stream proto.Bor_DebugPprofServer) error { + var ( + payload []byte + headers map[string]string + err error + ) + + ctx := context.Background() + + switch req.Type { + case proto.DebugPprofRequest_CPU: + payload, headers, err = pprof.CPUProfile(ctx, int(req.Seconds)) + case proto.DebugPprofRequest_TRACE: + payload, headers, err = pprof.Trace(ctx, int(req.Seconds)) + case proto.DebugPprofRequest_LOOKUP: + payload, headers, err = pprof.Profile(req.Profile, 0, 0) + } + + if err != nil { + return err + } + + // send the file on a grpc stream + if err := sendStreamDebugFile(stream, headers, payload); err != nil { + return err + } + return nil } @@ -169,6 +190,34 @@ func headerToProtoHeader(h *types.Header) *proto.Header { } } +func (s *Server) DebugBlock(req *proto.DebugBlockRequest, stream proto.Bor_DebugBlockServer) error { + traceReq := &tracers.TraceBlockRequest{ + Number: req.Number, + Config: &tracers.TraceConfig{ + Config: &logger.Config{ + EnableMemory: true, + }, + }, + } + + res, err := s.tracerAPI.TraceBorBlock(traceReq) + if err != nil { + return err + } + + // this is memory heavy + data, err := json.Marshal(res) + if err != nil { + return err + } + + if err := sendStreamDebugFile(stream, map[string]string{}, data); err != nil { + return err + } + + return nil +} + var bigIntT = reflect.TypeOf(new(big.Int)).Kind() // gatherForks gathers all the fork numbers via reflection diff --git a/internal/cli/server/testdata/password.txt b/internal/cli/server/testdata/password.txt new file mode 100644 index 0000000000..1827ffa521 --- /dev/null +++ b/internal/cli/server/testdata/password.txt @@ -0,0 +1,2 @@ +test1 +test2 \ No newline at end of file diff --git a/internal/cli/server/testdata/simple.hcl b/internal/cli/server/testdata/simple.hcl index e276960e6d..5afc091859 100644 --- a/internal/cli/server/testdata/simple.hcl +++ b/internal/cli/server/testdata/simple.hcl @@ -1,6 +1,6 @@ data-dir = "./data" -whitelist = { +requiredblocks = { a = "b" } diff --git a/internal/cli/server/testdata/simple.json b/internal/cli/server/testdata/simple.json index 277f05d105..6270ee6d13 100644 --- a/internal/cli/server/testdata/simple.json +++ b/internal/cli/server/testdata/simple.json @@ -1,6 +1,6 @@ { "data-dir": "./data", - "whitelist": { + "requiredblocks": { "a": "b" }, "p2p": { diff --git a/internal/cli/status.go b/internal/cli/status.go index ef0a42172b..2a8b7d7470 100644 --- a/internal/cli/status.go +++ b/internal/cli/status.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/internal/cli/server/proto" + "github.com/golang/protobuf/ptypes/empty" ) @@ -14,6 +15,16 @@ type StatusCommand struct { *Meta2 } +// MarkDown implements cli.MarkDown interface +func (p *StatusCommand) MarkDown() string { + items := []string{ + "# Status", + "The ```status``` command outputs the status of the client.", + } + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (p *StatusCommand) Help() string { return `Usage: bor status @@ -47,6 +58,7 @@ func (c *StatusCommand) Run(args []string) int { } c.UI.Output(printStatus(status)) + return 0 } @@ -60,6 +72,7 @@ func printStatus(status *proto.StatusResponse) string { forks := make([]string, len(status.Forks)+1) forks[0] = "Name|Block|Enabled" + for i, d := range status.Forks { forks[i+1] = fmt.Sprintf("%s|%d|%v", d.Name, d.Block, !d.Disabled) } @@ -83,5 +96,6 @@ func printStatus(status *proto.StatusResponse) string { "\nForks", formatList(forks), } + return strings.Join(full, "\n") } diff --git a/internal/cli/version.go b/internal/cli/version.go index 7433f208b2..cd155f43a7 100644 --- a/internal/cli/version.go +++ b/internal/cli/version.go @@ -1,7 +1,10 @@ package cli import ( + "strings" + "github.com/ethereum/go-ethereum/params" + "github.com/mitchellh/cli" ) @@ -10,6 +13,25 @@ type VersionCommand struct { UI cli.Ui } +// MarkDown implements cli.MarkDown interface +func (d *VersionCommand) MarkDown() string { + examples := []string{ + "## Usage", + CodeBlock([]string{ + "$ bor version", + "0.2.9-stable", + }), + } + + items := []string{ + "# Version", + "The ```bor version``` command outputs the version of the binary.", + } + items = append(items, examples...) + + return strings.Join(items, "\n\n") +} + // Help implements the cli.Command interface func (c *VersionCommand) Help() string { return `Usage: bor version diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 2c3520a885..aa2596fe81 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -59,6 +59,7 @@ func (args *TransactionArgs) from() common.Address { if args.From == nil { return common.Address{} } + return *args.From } @@ -67,9 +68,11 @@ func (args *TransactionArgs) data() []byte { if args.Input != nil { return *args.Input } + if args.Data != nil { return *args.Data } + return nil } @@ -78,8 +81,10 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } + // After london, default to 1559 unless gasPrice is set head := b.CurrentHeader() + // If user specifies both maxPriorityfee and maxFee, then we do not // need to consult the chain for defaults. It's definitely a London tx. if args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil { @@ -90,6 +95,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { if err != nil { return err } + args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) } if args.MaxFeePerGas == nil { @@ -97,8 +103,10 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { (*big.Int)(args.MaxPriorityFeePerGas), new(big.Int).Mul(head.BaseFee, big.NewInt(2)), ) + args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap) } + if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) } @@ -106,17 +114,20 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") } + if args.GasPrice == nil { price, err := b.SuggestGasTipCap(ctx) if err != nil { return err } + if b.ChainConfig().IsLondon(head.Number) { // The legacy tx gas price suggestion should not add 2x base fee // because all fees are consumed, so it would result in a spiral // upwards. price.Add(price, head.BaseFee) } + args.GasPrice = (*hexutil.Big)(price) } } @@ -126,22 +137,28 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) } } + if args.Value == nil { args.Value = new(hexutil.Big) } + if args.Nonce == nil { nonce, err := b.GetPoolNonce(ctx, args.from()) if err != nil { return err } + args.Nonce = (*hexutil.Uint64)(&nonce) } + if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) } + if args.To == nil && len(args.data()) == 0 { return errors.New(`contract creation without any data provided`) } + // Estimate the gas usage if necessary. if args.Gas == nil { // These fields are immutable during the estimation, safe to @@ -157,18 +174,23 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { Data: (*hexutil.Bytes)(&data), AccessList: args.AccessList, } + pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) + estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap()) if err != nil { return err } + args.Gas = &estimated log.Trace("Estimate gas usage automatically", "gas", args.Gas) } + if args.ChainID == nil { id := (*hexutil.Big)(b.ChainConfig().ChainID) args.ChainID = id } + return nil } @@ -180,6 +202,7 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } + // Set sender address or use zero address if none specified. addr := args.from() @@ -191,24 +214,29 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t if gas == 0 { gas = uint64(math.MaxUint64 / 2) } + if args.Gas != nil && *args.Gas != systemCallGas { gas = uint64(*args.Gas) } + if globalGasCap != 0 && globalGasCap < gas { log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) gas = globalGasCap } + var ( gasPrice *big.Int gasFeeCap *big.Int gasTipCap *big.Int ) + if baseFee == nil { // If there's no basefee, then it must be a non-1559 execution gasPrice = new(big.Int) if args.GasPrice != nil { gasPrice = args.GasPrice.ToInt() } + gasFeeCap, gasTipCap = gasPrice, gasPrice } else { // A basefee is provided, necessitating 1559-type execution @@ -219,30 +247,40 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t } else { // User specified 1559 gas feilds (or none), use those gasFeeCap = new(big.Int) + if args.MaxFeePerGas != nil { gasFeeCap = args.MaxFeePerGas.ToInt() } + gasTipCap = new(big.Int) + if args.MaxPriorityFeePerGas != nil { gasTipCap = args.MaxPriorityFeePerGas.ToInt() } + // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes gasPrice = new(big.Int) + if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap) } } } + value := new(big.Int) if args.Value != nil { value = args.Value.ToInt() } + data := args.data() + var accessList types.AccessList if args.AccessList != nil { accessList = *args.AccessList } + msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true) + return msg, nil } @@ -250,6 +288,7 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t // This assumes that setDefaults has been called. func (args *TransactionArgs) toTransaction() *types.Transaction { var data types.TxData + switch { case args.MaxFeePerGas != nil: al := types.AccessList{} @@ -288,6 +327,7 @@ func (args *TransactionArgs) toTransaction() *types.Transaction { Data: args.data(), } } + return types.NewTx(data) } diff --git a/internal/web3ext/bor_ext.go b/internal/web3ext/bor_ext.go index b7fe9b4886..fe8b01da19 100644 --- a/internal/web3ext/bor_ext.go +++ b/internal/web3ext/bor_ext.go @@ -17,6 +17,18 @@ web3._extend({ params: 1, inputFormatter: [null] }), + new web3._extend.Method({ + name: 'getSnapshotProposer', + call: 'bor_getSnapshotProposer', + params: 1, + inputFormatter: [null] + }), + new web3._extend.Method({ + name: 'getSnapshotProposerSequence', + call: 'bor_getSnapshotProposerSequence', + params: 1, + inputFormatter: [null] + }), new web3._extend.Method({ name: 'getSnapshotAtHash', call: 'bor_getSnapshotAtHash', diff --git a/metrics/sample_test.go b/metrics/sample_test.go index c9168d3e82..d675862e84 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -244,6 +244,7 @@ func TestUniformSampleIncludesTail(t *testing.T) { } func TestUniformSampleSnapshot(t *testing.T) { + rand.Seed(1) s := NewUniformSample(100) for i := 1; i <= 10000; i++ { s.Update(int64(i)) @@ -339,6 +340,9 @@ func TestUniformSampleConcurrentUpdateCount(t *testing.T) { if testing.Short() { t.Skip("skipping in short mode") } + + rand.Seed(1) + s := NewUniformSample(100) for i := 0; i < 100; i++ { s.Update(int64(i)) diff --git a/miner/fake_miner.go b/miner/fake_miner.go new file mode 100644 index 0000000000..cbe0d9f54c --- /dev/null +++ b/miner/fake_miner.go @@ -0,0 +1,233 @@ +package miner + +import ( + "errors" + "math/big" + "testing" + "time" + + "github.com/golang/mock/gomock" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "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/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "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/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/tests/bor/mocks" + "github.com/ethereum/go-ethereum/trie" +) + +type DefaultBorMiner struct { + Miner *Miner + Mux *event.TypeMux //nolint:staticcheck + Cleanup func(skipMiner bool) + + Ctrl *gomock.Controller + EthAPIMock api.Caller + HeimdallClientMock bor.IHeimdallClient + ContractMock bor.GenesisContract +} + +func NewBorDefaultMiner(t *testing.T) *DefaultBorMiner { + t.Helper() + + ctrl := gomock.NewController(t) + + ethAPI := api.NewMockCaller(ctrl) + ethAPI.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() + + heimdallClient := mocks.NewMockIHeimdallClient(ctrl) + heimdallClient.EXPECT().Close().Times(1) + + genesisContracts := bor.NewMockGenesisContract(ctrl) + + miner, mux, cleanup := createBorMiner(t, ethAPI, spanner, heimdallClient, genesisContracts) + + return &DefaultBorMiner{ + Miner: miner, + Mux: mux, + Cleanup: cleanup, + Ctrl: ctrl, + EthAPIMock: ethAPI, + HeimdallClientMock: heimdallClient, + ContractMock: genesisContracts, + } +} + +//nolint:staticcheck +func createBorMiner(t *testing.T, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) (*Miner, *event.TypeMux, func(skipMiner bool)) { + t.Helper() + + // Create Ethash config + chainDB, _, chainConfig := NewDBForFakes(t) + + engine := NewFakeBor(t, chainDB, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock) + + // Create Ethereum backend + bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("can't create new chain %v", err) + } + + statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil) + blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} + + pool := core.NewTxPool(testTxPoolConfig, chainConfig, blockchain) + backend := NewMockBackend(bc, pool) + + // Create event Mux + mux := new(event.TypeMux) + + config := Config{ + Etherbase: common.HexToAddress("123456789"), + } + + // Create Miner + miner := New(backend, &config, chainConfig, mux, engine, nil) + + cleanup := func(skipMiner bool) { + bc.Stop() + engine.Close() + pool.Stop() + + if !skipMiner { + miner.Close() + } + } + + return miner, mux, cleanup +} + +func NewDBForFakes(t *testing.T) (ethdb.Database, *core.Genesis, *params.ChainConfig) { + t.Helper() + + memdb := memorydb.New() + chainDB := rawdb.NewDatabase(memdb) + genesis := core.DeveloperGenesisBlock(2, 11_500_000, common.HexToAddress("12345")) + + chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis) + if err != nil { + t.Fatalf("can't create new chain config: %v", err) + } + + chainConfig.Bor.Period = map[string]uint64{ + "0": 1, + } + + return chainDB, genesis, chainConfig +} + +func NewFakeBor(t *testing.T, chainDB ethdb.Database, chainConfig *params.ChainConfig, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) consensus.Engine { + t.Helper() + + if chainConfig.Bor == nil { + chainConfig.Bor = params.BorUnittestChainConfig.Bor + } + + return bor.New(chainConfig, chainDB, ethAPIMock, spanner, heimdallClientMock, contractMock) +} + +type mockBackend struct { + bc *core.BlockChain + txPool *core.TxPool +} + +func NewMockBackend(bc *core.BlockChain, txPool *core.TxPool) *mockBackend { + return &mockBackend{ + bc: bc, + txPool: txPool, + } +} + +func (m *mockBackend) BlockChain() *core.BlockChain { + return m.bc +} + +func (m *mockBackend) TxPool() *core.TxPool { + return m.txPool +} + +func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { + return nil, errors.New("not supported") +} + +type testBlockChain struct { + statedb *state.StateDB + gasLimit uint64 + chainHeadFeed *event.Feed +} + +func (bc *testBlockChain) CurrentBlock() *types.Block { + return types.NewBlock(&types.Header{ + GasLimit: bc.gasLimit, + }, nil, nil, nil, trie.NewStackTrie(nil)) +} + +func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { + return bc.CurrentBlock() +} + +func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { + return bc.statedb, nil +} + +func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + return bc.chainHeadFeed.Subscribe(ch) +} + +var ( + // Test chain configurations + testTxPoolConfig core.TxPoolConfig + ethashChainConfig *params.ChainConfig + cliqueChainConfig *params.ChainConfig + + // Test accounts + testBankKey, _ = crypto.GenerateKey() + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + testBankFunds = big.NewInt(1000000000000000000) + + testUserKey, _ = crypto.GenerateKey() + testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) + + // Test transactions + pendingTxs []*types.Transaction + newTxs []*types.Transaction + + testConfig = &Config{ + Recommit: time.Second, + GasCeil: params.GenesisGasLimit, + } +) + +func init() { + testTxPoolConfig = core.DefaultTxPoolConfig + testTxPoolConfig.Journal = "" + ethashChainConfig = new(params.ChainConfig) + *ethashChainConfig = *params.TestChainConfig + cliqueChainConfig = new(params.ChainConfig) + *cliqueChainConfig = *params.TestChainConfig + cliqueChainConfig.Clique = ¶ms.CliqueConfig{ + Period: 10, + Epoch: 30000, + } +} diff --git a/miner/miner_test.go b/miner/miner_test.go index 03c79cbbd5..76f61fd0d4 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -18,80 +18,32 @@ package miner import ( - "errors" "testing" "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/clique" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" - "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/eth/downloader" - "github.com/ethereum/go-ethereum/ethdb/memorydb" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/trie" ) -type mockBackend struct { - bc *core.BlockChain - txPool *core.TxPool -} - -func NewMockBackend(bc *core.BlockChain, txPool *core.TxPool) *mockBackend { - return &mockBackend{ - bc: bc, - txPool: txPool, - } -} - -func (m *mockBackend) BlockChain() *core.BlockChain { - return m.bc -} - -func (m *mockBackend) TxPool() *core.TxPool { - return m.txPool -} - -func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { - return nil, errors.New("not supported") -} - -type testBlockChain struct { - statedb *state.StateDB - gasLimit uint64 - chainHeadFeed *event.Feed -} - -func (bc *testBlockChain) CurrentBlock() *types.Block { - return types.NewBlock(&types.Header{ - GasLimit: bc.gasLimit, - }, nil, nil, nil, trie.NewStackTrie(nil)) -} - -func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { - return bc.CurrentBlock() -} - -func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { - return bc.statedb, nil -} - -func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { - return bc.chainHeadFeed.Subscribe(ch) -} - func TestMiner(t *testing.T) { - miner, mux, cleanup := createMiner(t) - defer cleanup(false) + t.Parallel() + + minerBor := NewBorDefaultMiner(t) + defer func() { + minerBor.Cleanup(false) + minerBor.Ctrl.Finish() + }() + + miner := minerBor.Miner + mux := minerBor.Mux + miner.Start(common.HexToAddress("0x12345")) waitForMiningState(t, miner, true) + // Start the downloader mux.Post(downloader.StartEvent{}) waitForMiningState(t, miner, false) + // Stop the downloader and wait for the update loop to run mux.Post(downloader.DoneEvent{}) waitForMiningState(t, miner, true) @@ -113,10 +65,20 @@ func TestMiner(t *testing.T) { // An initial FailedEvent should allow mining to stop on a subsequent // downloader StartEvent. func TestMinerDownloaderFirstFails(t *testing.T) { - miner, mux, cleanup := createMiner(t) - defer cleanup(false) + t.Parallel() + + minerBor := NewBorDefaultMiner(t) + defer func() { + minerBor.Cleanup(false) + minerBor.Ctrl.Finish() + }() + + miner := minerBor.Miner + mux := minerBor.Mux + miner.Start(common.HexToAddress("0x12345")) waitForMiningState(t, miner, true) + // Start the downloader mux.Post(downloader.StartEvent{}) waitForMiningState(t, miner, false) @@ -145,10 +107,20 @@ func TestMinerDownloaderFirstFails(t *testing.T) { } func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { - miner, mux, cleanup := createMiner(t) - defer cleanup(false) + t.Parallel() + + minerBor := NewBorDefaultMiner(t) + defer func() { + minerBor.Cleanup(false) + minerBor.Ctrl.Finish() + }() + + miner := minerBor.Miner + mux := minerBor.Mux + miner.Start(common.HexToAddress("0x12345")) waitForMiningState(t, miner, true) + // Start the downloader mux.Post(downloader.StartEvent{}) waitForMiningState(t, miner, false) @@ -168,58 +140,104 @@ func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { } func TestStartWhileDownload(t *testing.T) { - miner, mux, cleanup := createMiner(t) - defer cleanup(false) + t.Parallel() + + minerBor := NewBorDefaultMiner(t) + defer func() { + minerBor.Cleanup(false) + minerBor.Ctrl.Finish() + }() + + miner := minerBor.Miner + mux := minerBor.Mux + waitForMiningState(t, miner, false) miner.Start(common.HexToAddress("0x12345")) waitForMiningState(t, miner, true) + // Stop the downloader and wait for the update loop to run mux.Post(downloader.StartEvent{}) waitForMiningState(t, miner, false) + // Starting the miner after the downloader should not work miner.Start(common.HexToAddress("0x12345")) waitForMiningState(t, miner, false) } func TestStartStopMiner(t *testing.T) { - miner, _, cleanup := createMiner(t) - defer cleanup(false) + t.Parallel() + + minerBor := NewBorDefaultMiner(t) + defer func() { + minerBor.Cleanup(false) + minerBor.Ctrl.Finish() + }() + + miner := minerBor.Miner + waitForMiningState(t, miner, false) miner.Start(common.HexToAddress("0x12345")) - waitForMiningState(t, miner, true) - miner.Stop() - waitForMiningState(t, miner, false) + waitForMiningState(t, miner, true) + + miner.Stop() + + waitForMiningState(t, miner, false) } func TestCloseMiner(t *testing.T) { - miner, _, cleanup := createMiner(t) - defer cleanup(true) + t.Parallel() + + minerBor := NewBorDefaultMiner(t) + defer func() { + minerBor.Cleanup(true) + minerBor.Ctrl.Finish() + }() + + miner := minerBor.Miner + waitForMiningState(t, miner, false) + miner.Start(common.HexToAddress("0x12345")) + waitForMiningState(t, miner, true) + // Terminate the miner and wait for the update loop to run miner.Close() + waitForMiningState(t, miner, false) } // TestMinerSetEtherbase checks that etherbase becomes set even if mining isn't // possible at the moment func TestMinerSetEtherbase(t *testing.T) { - miner, mux, cleanup := createMiner(t) - defer cleanup(false) + t.Parallel() + + minerBor := NewBorDefaultMiner(t) + defer func() { + minerBor.Cleanup(false) + minerBor.Ctrl.Finish() + }() + + miner := minerBor.Miner + mux := minerBor.Mux + // Start with a 'bad' mining address miner.Start(common.HexToAddress("0xdead")) waitForMiningState(t, miner, true) + // Start the downloader mux.Post(downloader.StartEvent{}) waitForMiningState(t, miner, false) + // Now user tries to configure proper mining address miner.Start(common.HexToAddress("0x1337")) + // Stop the downloader and wait for the update loop to run mux.Post(downloader.DoneEvent{}) waitForMiningState(t, miner, true) + // The miner should now be using the good address if got, exp := miner.coinbase, common.HexToAddress("0x1337"); got != exp { t.Fatalf("Wrong coinbase, got %x expected %x", got, exp) @@ -239,46 +257,6 @@ func waitForMiningState(t *testing.T, m *Miner, mining bool) { return } } + t.Fatalf("Mining() == %t, want %t", state, mining) } - -func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { - // Create Ethash config - config := Config{ - Etherbase: common.HexToAddress("123456789"), - } - // Create chainConfig - memdb := memorydb.New() - chainDB := rawdb.NewDatabase(memdb) - genesis := core.DeveloperGenesisBlock(15, 11_500_000, common.HexToAddress("12345")) - chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis) - if err != nil { - t.Fatalf("can't create new chain config: %v", err) - } - // Create consensus engine - engine := clique.New(chainConfig.Clique, chainDB) - // Create Ethereum backend - consensus.NewMerger(rawdb.NewMemoryDatabase()) - bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("can't create new chain %v", err) - } - statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil) - blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} - - pool := core.NewTxPool(testTxPoolConfig, chainConfig, blockchain) - backend := NewMockBackend(bc, pool) - // Create event Mux - mux := new(event.TypeMux) - // Create Miner - miner := New(backend, &config, chainConfig, mux, engine, nil) - cleanup := func(skipMiner bool) { - bc.Stop() - engine.Close() - pool.Stop() - if !skipMiner { - miner.Close() - } - } - return miner, mux, cleanup -} diff --git a/miner/unconfirmed_test.go b/miner/unconfirmed_test.go index dc83cb9265..70d3325506 100644 --- a/miner/unconfirmed_test.go +++ b/miner/unconfirmed_test.go @@ -44,6 +44,7 @@ func TestUnconfirmedInsertBounds(t *testing.T) { for i := 0; i < int(depth); i++ { pool.Insert(depth, [32]byte{byte(depth), byte(i)}) } + // Validate that no blocks below the depth allowance are left in pool.blocks.Do(func(block interface{}) { if block := block.(*unconfirmedBlock); block.index+uint64(limit) <= depth { @@ -64,23 +65,29 @@ func TestUnconfirmedShifts(t *testing.T) { for depth := start; depth < start+uint64(limit); depth++ { pool.Insert(depth, [32]byte{byte(depth)}) } + // Try to shift below the limit and ensure no blocks are dropped pool.Shift(start + uint64(limit) - 1) if n := pool.blocks.Len(); n != int(limit) { t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit) } + // Try to shift half the blocks out and verify remainder pool.Shift(start + uint64(limit) - 1 + uint64(limit/2)) if n := pool.blocks.Len(); n != int(limit)/2 { t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit/2) } + // Try to shift all the remaining blocks out and verify emptyness pool.Shift(start + 2*uint64(limit)) + if n := pool.blocks.Len(); n != 0 { t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0) } + // Try to shift out from the empty set and make sure it doesn't break pool.Shift(start + 3*uint64(limit)) + if n := pool.blocks.Len(); n != 0 { t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0) } diff --git a/miner/worker.go b/miner/worker.go index 1da8a529d7..9fcb2140ca 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -25,6 +25,7 @@ import ( "time" mapset "github.com/deckarep/golang-set" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -393,23 +394,27 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t // prevF = float64(prev.Nanoseconds()) // next float64 // ) + // // if inc { // next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) // max := float64(maxRecommitInterval.Nanoseconds()) + // // if next > max { // next = max // } // } else { // next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) // min := float64(minRecommit.Nanoseconds()) + // // if next < min { // next = min // } // } + // // log.Info("Recalc Commit", "Prev", prev, "Next", next) //returning the Same prev value to keep the recommit interval constant - return time.Duration(int64(prev)) + return prev } // newWorkLoop is a standalone goroutine to submit new sealing work upon received events. diff --git a/miner/worker_test.go b/miner/worker_test.go index 20dc3238da..6dae391c88 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -24,9 +24,14 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "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/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -38,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/tests/bor/mocks" ) const ( @@ -49,43 +55,9 @@ const ( testGas = 144109 ) -var ( - // Test chain configurations - testTxPoolConfig core.TxPoolConfig - ethashChainConfig *params.ChainConfig - cliqueChainConfig *params.ChainConfig - - // Test accounts - testBankKey, _ = crypto.GenerateKey() - testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) - testBankFunds = big.NewInt(1000000000000000000) - - testUserKey, _ = crypto.GenerateKey() - testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) - - // Test transactions - pendingTxs []*types.Transaction - newTxs []*types.Transaction - - testConfig = &Config{ - Recommit: time.Second, - GasCeil: params.GenesisGasLimit, - } -) - func init() { - testTxPoolConfig = core.DefaultTxPoolConfig - testTxPoolConfig.Journal = "" - ethashChainConfig = new(params.ChainConfig) - *ethashChainConfig = *params.TestChainConfig - cliqueChainConfig = new(params.ChainConfig) - *cliqueChainConfig = *params.TestChainConfig - cliqueChainConfig.Clique = ¶ms.CliqueConfig{ - Period: 10, - Epoch: 30000, - } - signer := types.LatestSigner(params.TestChainConfig) + tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ ChainID: params.TestChainConfig.ChainID, Nonce: 0, @@ -94,6 +66,7 @@ func init() { Gas: params.TxGas, GasPrice: big.NewInt(params.InitialBaseFee), }) + pendingTxs = append(pendingTxs, tx1) tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ @@ -103,6 +76,7 @@ func init() { Gas: params.TxGas, GasPrice: big.NewInt(params.InitialBaseFee), }) + newTxs = append(newTxs, tx2) rand.Seed(time.Now().UnixNano()) @@ -125,6 +99,12 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine } switch e := engine.(type) { + case *bor.Bor: + gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) + copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) + e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { + return crypto.Sign(crypto.Keccak256(data), testBankKey) + }) case *clique.Clique: gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) @@ -135,6 +115,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine default: t.Fatalf("unexpected consensus engine type: %T", engine) } + genesis := gspec.MustCommit(db) chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil) @@ -149,10 +130,12 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine t.Fatalf("failed to insert origin chain: %v", err) } } + parent := genesis if n > 0 { parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) } + blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { gen.SetCoinbase(testUserAddress) }) @@ -174,28 +157,36 @@ func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base func (b *testWorkerBackend) newRandomUncle() *types.Block { var parent *types.Block + cur := b.chain.CurrentBlock() + if cur.NumberU64() == 0 { parent = b.chain.Genesis() } else { parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash()) } + blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) { var addr = make([]byte, common.AddressLength) + rand.Read(addr) gen.SetCoinbase(common.BytesToAddress(addr)) }) + return blocks[0] } func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { var tx *types.Transaction + gasPrice := big.NewInt(10 * params.InitialBaseFee) + if creation { tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey) } else { tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey) } + return tx } @@ -204,39 +195,85 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens backend.txPool.AddLocals(pendingTxs) w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false) w.setEtherbase(testBankAddress) + return w, backend } func TestGenerateBlockAndImportEthash(t *testing.T) { - testGenerateBlockAndImport(t, false) + t.Parallel() + + testGenerateBlockAndImport(t, false, false) } func TestGenerateBlockAndImportClique(t *testing.T) { - testGenerateBlockAndImport(t, true) + t.Parallel() + + testGenerateBlockAndImport(t, true, false) } -func testGenerateBlockAndImport(t *testing.T, isClique bool) { +func TestGenerateBlockAndImportBor(t *testing.T) { + t.Parallel() + + testGenerateBlockAndImport(t, false, true) +} + +//nolint:thelper +func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) { var ( engine consensus.Engine chainConfig *params.ChainConfig db = rawdb.NewMemoryDatabase() ) - if isClique { - chainConfig = params.AllCliqueProtocolChanges - chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} - engine = clique.New(chainConfig.Clique, db) + + if isBor { + chainConfig = params.BorUnittestChainConfig + + 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: testBankAddress, + VotingPower: 100, + ProposerPriority: 0, + }, + }, nil).AnyTimes() + + heimdallClientMock := mocks.NewMockIHeimdallClient(ctrl) + heimdallClientMock.EXPECT().Close().Times(1) + + contractMock := bor.NewMockGenesisContract(ctrl) + + db, _, _ = NewDBForFakes(t) + + engine = NewFakeBor(t, db, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock) } else { - chainConfig = params.AllEthashProtocolChanges - engine = ethash.NewFaker() + if isClique { + chainConfig = params.AllCliqueProtocolChanges + chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} + engine = clique.New(chainConfig.Clique, db) + } else { + chainConfig = params.AllEthashProtocolChanges + engine = ethash.NewFaker() + } } + defer engine.Close() + chainConfig.LondonBlock = big.NewInt(0) + w, b := newTestWorker(t, chainConfig, engine, db, 0) defer w.close() // This test chain imports the mined blocks. db2 := rawdb.NewMemoryDatabase() b.genesis.MustCommit(db2) + chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) defer chain.Stop() @@ -287,20 +324,25 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens taskIndex int taskCh = make(chan struct{}, 2) ) + checkEqual := func(t *testing.T, task *task, index int) { // The first empty work without any txs included receiptLen, balance := 0, big.NewInt(0) + if index == 1 { // The second full work with 1 tx included receiptLen, balance = 1, big.NewInt(1000) } + if len(task.receipts) != receiptLen { t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) } + if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) } } + w.newTaskHook = func(task *task) { if task.block.NumberU64() == 1 { checkEqual(t, task, taskIndex) @@ -308,11 +350,14 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens taskCh <- struct{}{} } } + w.skipSealHook = func(task *task) bool { return true } w.fullTaskHook = func() { time.Sleep(100 * time.Millisecond) } + w.start() // Start mining! + for i := 0; i < 2; i += 1 { select { case <-taskCh: @@ -344,16 +389,20 @@ func TestStreamUncleBlock(t *testing.T) { t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex()) } } + taskCh <- struct{}{} taskIndex += 1 } } + w.skipSealHook = func(task *task) bool { return true } + w.fullTaskHook = func() { time.Sleep(100 * time.Millisecond) } + w.start() for i := 0; i < 2; i += 1 { @@ -396,20 +445,25 @@ func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, en // one has 1 pending tx, the third one has 2 txs if taskIndex == 2 { receiptLen, balance := 2, big.NewInt(2000) + if len(task.receipts) != receiptLen { t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) } + if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) } } + taskCh <- struct{}{} taskIndex += 1 } } + w.skipSealHook = func(task *task) bool { return true } + w.fullTaskHook = func() { time.Sleep(100 * time.Millisecond) } @@ -423,6 +477,7 @@ func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, en t.Error("new task timeout") } } + b.txPool.AddLocals(newTxs) time.Sleep(time.Second) @@ -464,6 +519,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co index = 0 start uint32 ) + w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { // Short circuit if interval checking hasn't started. if atomic.LoadUint32(&start) == 0 { @@ -494,16 +550,19 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co if recommitInterval != wantRecommitInterval { t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) } + result = append(result, float64(recommitInterval.Nanoseconds())) index += 1 progress <- struct{}{} } + w.start() time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt atomic.StoreUint32(&start, 1) w.setRecommitInterval(3 * time.Second) + select { case <-progress: case <-time.NewTimer(time.Second).C: @@ -511,6 +570,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co } w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} + select { case <-progress: case <-time.NewTimer(time.Second).C: @@ -518,6 +578,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co } w.resubmitAdjustCh <- &intervalAdjust{inc: false} + select { case <-progress: case <-time.NewTimer(time.Second).C: @@ -525,6 +586,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co } w.setRecommitInterval(500 * time.Millisecond) + select { case <-progress: case <-time.NewTimer(time.Second).C: @@ -559,9 +621,11 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co w.skipSealHook = func(task *task) bool { return true } + w.fullTaskHook = func() { time.Sleep(100 * time.Millisecond) } + timestamp := uint64(time.Now().Unix()) assertBlock := func(block *types.Block, number uint64, coinbase common.Address, random common.Hash) { if block.Time() != timestamp { @@ -569,14 +633,17 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co // is even smaller than parent block's. It's OK. t.Logf("Invalid timestamp, want %d, get %d", timestamp, block.Time()) } + if len(block.Uncles()) != 0 { t.Error("Unexpected uncle block") } + _, isClique := engine.(*clique.Clique) if !isClique { if len(block.Extra()) != 0 { t.Error("Unexpected extra field") } + if block.Coinbase() != coinbase { t.Errorf("Unexpected coinbase got %x want %x", block.Coinbase(), coinbase) } @@ -585,18 +652,22 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co t.Error("Unexpected coinbase") } } + if !isClique { if block.MixDigest() != random { t.Error("Unexpected mix digest") } } + if block.Nonce() != 0 { t.Error("Unexpected block nonce") } + if block.NumberU64() != number { t.Errorf("Mismatched block number, want %d got %d", number, block.NumberU64()) } } + var cases = []struct { parent common.Hash coinbase common.Address @@ -644,6 +715,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co // This API should work even when the automatic sealing is not enabled for _, c := range cases { block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random) + if c.expectErr { if err == nil { t.Error("Expect error but get nil") @@ -652,12 +724,14 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co if err != nil { t.Errorf("Unexpected error %v", err) } + assertBlock(block, c.expectNumber, c.coinbase, c.random) } } // This API should work even when the automatic sealing is enabled w.start() + for _, c := range cases { block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random) if c.expectErr { @@ -668,6 +742,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co if err != nil { t.Errorf("Unexpected error %v", err) } + assertBlock(block, c.expectNumber, c.coinbase, c.random) } } diff --git a/params/config.go b/params/config.go index 47e22f986c..980250a1ec 100644 --- a/params/config.go +++ b/params/config.go @@ -23,8 +23,9 @@ import ( "sort" "strconv" - "github.com/ethereum/go-ethereum/common" "golang.org/x/crypto/sha3" + + "github.com/ethereum/go-ethereum/common" ) // Genesis hashes to enforce below configs on. @@ -289,6 +290,38 @@ var ( }, }, } + BorUnittestChainConfig = &ChainConfig{ + ChainID: big.NewInt(80001), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Hash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + Bor: &BorConfig{ + Period: map[string]uint64{ + "0": 1, + }, + ProducerDelay: 3, + Sprint: 32, + BackupMultiplier: map[string]uint64{ + "0": 2, + }, + ValidatorContract: "0x0000000000000000000000000000000000001000", + StateReceiverContract: "0x0000000000000000000000000000000000001001", + BurntContract: map[string]string{ + "0": "0x00000000000000000000000000000000000000000", + }, + }, + } // MumbaiChainConfig contains the chain parameters to run a node on the Mumbai test network. MumbaiChainConfig = &ChainConfig{ @@ -550,7 +583,9 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin for k := range field { keys = append(keys, k) } + sort.Strings(keys) + for i := 0; i < len(keys)-1; i++ { valUint, _ := strconv.ParseUint(keys[i], 10, 64) valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64) @@ -558,6 +593,7 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin return field[keys[i]] } } + return field[keys[len(keys)-1]] } diff --git a/scripts/tools-protobuf.sh b/scripts/tools-protobuf.sh index fe03cab3cb..04144134f4 100755 --- a/scripts/tools-protobuf.sh +++ b/scripts/tools-protobuf.sh @@ -1,15 +1,24 @@ #!/bin/bash # Install protobuf -PROTOC_ZIP=protoc-3.12.0-linux-x86_64.zip -curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.12.0/$PROTOC_ZIP +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + os="linux" +elif [[ "$OSTYPE" == "darwin"* ]]; then + os="osx" +else + echo "Unsupported platform" + exit 1 +fi + +PROTOC_ZIP=protoc-3.19.3-$os-x86_64.zip +curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.19.3/$PROTOC_ZIP sudo unzip -o $PROTOC_ZIP -d /usr/local bin/protoc sudo unzip -o $PROTOC_ZIP -d /usr/local 'include/*' rm -f $PROTOC_ZIP # Change permissions to use the binary -sudo chmod 755 -R /usr/local/bin/protoc -sudo chmod 755 -R /usr/local/include +sudo chmod -R 755 /usr/local/bin/protoc +sudo chmod -R 755 /usr/local/include # Install golang extensions (DO NOT CHANGE THE VERSIONS) go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.25.0 diff --git a/tests/block_test.go b/tests/block_test.go index 74c7ed8197..591bff6e07 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -14,6 +14,9 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +//go:build integration +// +build integration + package tests import ( diff --git a/tests/block_test_util.go b/tests/block_test_util.go index bcf861e09b..d28f3a1237 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -15,6 +15,7 @@ // along with the go-ethereum library. If not, see . // Package tests implements execution of Ethereum JSON tests. + package tests import ( diff --git a/tests/bor/bor_test.go b/tests/bor/bor_test.go index a179616290..36d515c557 100644 --- a/tests/bor/bor_test.go +++ b/tests/bor/bor_test.go @@ -1,8 +1,10 @@ +//go:build integration +// +build integration + package bor import ( "encoding/hex" - "encoding/json" "io" "math/big" "testing" @@ -14,6 +16,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/bor" + "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/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -25,19 +30,13 @@ import ( "github.com/ethereum/go-ethereum/tests/bor/mocks" ) -var ( - spanPath = "bor/span/1" - clerkPath = "clerk/event-record/list" - clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50" -) - func TestInsertingSpanSizeBlocks(t *testing.T) { init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) chain := init.ethereum.BlockChain() engine := init.ethereum.Engine() _bor := engine.(*bor.Bor) - defer engine.Close() + defer _bor.Close() h, heimdallSpan, ctrl := getMockedHeimdallClient(t) defer ctrl.Finish() @@ -45,7 +44,7 @@ func TestInsertingSpanSizeBlocks(t *testing.T) { _, span := loadSpanFromFile(t) h.EXPECT().Close().AnyTimes() - h.EXPECT().FetchLatestCheckpoint().Return(&bor.Checkpoint{ + h.EXPECT().FetchLatestCheckpoint().Return(&checkpoint.Checkpoint{ Proposer: span.SelectedProducers[0].Address, StartBlock: big.NewInt(0), EndBlock: big.NewInt(int64(spanSize)), @@ -81,7 +80,7 @@ func TestFetchStateSyncEvents(t *testing.T) { engine := init.ethereum.Engine() _bor := engine.(*bor.Bor) - defer engine.Close() + defer _bor.Close() // A. Insert blocks for 0th sprint db := init.ethereum.ChainDb() @@ -101,6 +100,7 @@ func TestFetchStateSyncEvents(t *testing.T) { h := mocks.NewMockIHeimdallClient(ctrl) h.EXPECT().Close().AnyTimes() + h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes() // B.2 Mock State Sync events fromID := uint64(1) @@ -112,9 +112,7 @@ func TestFetchStateSyncEvents(t *testing.T) { sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to eventRecords := generateFakeStateSyncEvents(sample, eventCount) - // Mock - h.EXPECT().FetchWithRetry(spanPath, "").Return(res, nil).AnyTimes() - h.EXPECT().FetchStateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() + h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() _bor.SetHeimdallClient(h) block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) @@ -137,7 +135,7 @@ func TestFetchStateSyncEvents_2(t *testing.T) { h := mocks.NewMockIHeimdallClient(ctrl) h.EXPECT().Close().AnyTimes() - h.EXPECT().FetchWithRetry(spanPath, "").Return(res, nil).AnyTimes() + h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes() // Mock State Sync events // at # sprintSize, events are fetched for [fromID, (block-sprint).Time) @@ -147,7 +145,7 @@ func TestFetchStateSyncEvents_2(t *testing.T) { // First query will be from [id=1, (block-sprint).Time] // Insert 5 events in this time range - eventRecords := []*bor.EventRecordWithTime{ + eventRecords := []*clerk.EventRecordWithTime{ buildStateEvent(sample, 1, 3), // id = 1, time = 1 buildStateEvent(sample, 2, 1), // id = 2, time = 3 buildStateEvent(sample, 3, 2), // id = 3, time = 2 @@ -156,7 +154,7 @@ func TestFetchStateSyncEvents_2(t *testing.T) { buildStateEvent(sample, 6, 4), // id = 6, time = 4 } - h.EXPECT().FetchStateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() + h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() _bor.SetHeimdallClient(h) // Insert blocks for 0th sprint @@ -175,12 +173,12 @@ func TestFetchStateSyncEvents_2(t *testing.T) { // fromID = uint64(5) to = int64(chain.GetHeaderByNumber(sprintSize).Time) - eventRecords = []*bor.EventRecordWithTime{ + + eventRecords = []*clerk.EventRecordWithTime{ buildStateEvent(sample, 5, 7), buildStateEvent(sample, 6, 4), } - - h.EXPECT().FetchStateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() + h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() for i := sprintSize + 1; i <= spanSize; i++ { block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) @@ -278,58 +276,50 @@ func TestSignerNotFound(t *testing.T) { bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()}) } -func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *bor.HeimdallSpan, *gomock.Controller) { +func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *span.HeimdallSpan, *gomock.Controller) { ctrl := gomock.NewController(t) h := mocks.NewMockIHeimdallClient(ctrl) - res, heimdallSpan := loadSpanFromFile(t) + _, heimdallSpan := loadSpanFromFile(t) - h.EXPECT().FetchWithRetry(spanPath, "").Return(res, nil).AnyTimes() - h.EXPECT().FetchStateSyncEvents(gomock.Any(), gomock.Any()).Return(getEventRecords(t), nil).AnyTimes() + h.EXPECT().Span(uint64(1)).Return(heimdallSpan, nil).AnyTimes() + + h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any()). + Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes() return h, heimdallSpan, ctrl } -func generateFakeStateSyncEvents(sample *bor.EventRecordWithTime, count int) []*bor.EventRecordWithTime { - events := make([]*bor.EventRecordWithTime, count) +func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime { + events := make([]*clerk.EventRecordWithTime, count) event := *sample event.ID = 1 - events[0] = &bor.EventRecordWithTime{} + events[0] = &clerk.EventRecordWithTime{} *events[0] = event for i := 1; i < count; i++ { event.ID = uint64(i) event.Time = event.Time.Add(1 * time.Second) - events[i] = &bor.EventRecordWithTime{} + events[i] = &clerk.EventRecordWithTime{} *events[i] = event } return events } -func buildStateEvent(sample *bor.EventRecordWithTime, id uint64, timeStamp int64) *bor.EventRecordWithTime { +func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime { event := *sample event.ID = id event.Time = time.Unix(timeStamp, 0) return &event } -func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime { - res := stateSyncEventsPayload(t) - var _eventRecords []*bor.EventRecordWithTime - if err := json.Unmarshal(res.Result, &_eventRecords); err != nil { - t.Fatalf("%s", err) - } - _eventRecords[0].Time = time.Unix(1, 0) - return _eventRecords[0] +func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime { + eventRecords := stateSyncEventsPayload(t) + eventRecords.Result[0].Time = time.Unix(1, 0) + return eventRecords.Result[0] } -func getEventRecords(t *testing.T) []*bor.EventRecordWithTime { - res := stateSyncEventsPayload(t) - var _eventRecords []*bor.EventRecordWithTime - if err := json.Unmarshal(res.Result, &_eventRecords); err != nil { - t.Fatalf("%s", err) - } - - return _eventRecords +func getEventRecords(t *testing.T) []*clerk.EventRecordWithTime { + return stateSyncEventsPayload(t).Result } // TestEIP1559Transition tests the following: diff --git a/tests/bor/helper.go b/tests/bor/helper.go index a1b6a19742..a8a3ae4ea6 100644 --- a/tests/bor/helper.go +++ b/tests/bor/helper.go @@ -11,6 +11,9 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/bor" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" + "github.com/ethereum/go-ethereum/consensus/bor/valset" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -46,17 +49,23 @@ type initializeData struct { } func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { + t.Helper() + genesisData, err := ioutil.ReadFile("./testdata/genesis.json") if err != nil { t.Fatalf("%s", err) } + gen := &core.Genesis{} + if err := json.Unmarshal(genesisData, gen); err != nil { t.Fatalf("%s", err) } + ethConf := ð.Config{ Genesis: gen, } + ethConf.Genesis.MustCommit(db) ethereum := utils.CreateBorEthereum(ethConf) @@ -65,6 +74,7 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { } ethConf.Genesis.MustCommit(ethereum.ChainDb()) + return &initializeData{ genesis: gen, ethereum: ethereum, @@ -72,12 +82,16 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { } func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) { + t.Helper() + if _, err := chain.InsertChain([]*types.Block{block}); err != nil { t.Fatalf("%s", err) } } func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block { + t.Helper() + header := block.Header() header.Number.Add(header.Number, big.NewInt(1)) number := header.Number.Uint64() @@ -90,11 +104,12 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block * header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig) header.Extra = make([]byte, 32+65) // vanity + extraSeal - currentValidators := []*bor.Validator{bor.NewValidator(addr, 10)} + currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)} isSpanEnd := (number+1)%spanSize == 0 isSpanStart := number%spanSize == 0 isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0 + if isSpanEnd { _, heimdallSpan := loadSpanFromFile(t) // this is to stash the validator bytes in the header @@ -102,18 +117,23 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block * } else if isSpanStart { header.Difficulty = new(big.Int).SetInt64(3) } + if isSprintEnd { - sort.Sort(bor.ValidatorsByAddress(currentValidators)) + sort.Sort(valset.ValidatorsByAddress(currentValidators)) + validatorBytes := make([]byte, len(currentValidators)*validatorHeaderBytesLength) header.Extra = make([]byte, 32+len(validatorBytes)+65) // vanity + validatorBytes + extraSeal + for i, val := range currentValidators { copy(validatorBytes[i*validatorHeaderBytesLength:], val.HeaderBytes()) } + copy(header.Extra[32:], validatorBytes) } if chain.Config().IsLondon(header.Number) { header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header()) + if !chain.Config().IsLondon(block.Number()) { parentGasLimit := block.GasLimit() * params.ElasticityMultiplier header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit) @@ -124,58 +144,73 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block * if err != nil { t.Fatalf("%s", err) } + _, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil) if err != nil { t.Fatalf("%s", err) } + sign(t, header, signer, borConfig) + return types.NewBlockWithHeader(header) } func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) { + t.Helper() + sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header, c)), signer) if err != nil { t.Fatalf("%s", err) } + copy(header.Extra[len(header.Extra)-extraSeal:], sig) } -func stateSyncEventsPayload(t *testing.T) *bor.ResponseWithHeight { +//nolint:unused,deadcode +func stateSyncEventsPayload(t *testing.T) *heimdall.StateSyncEventsResponse { + t.Helper() + stateData, err := ioutil.ReadFile("./testdata/states.json") if err != nil { t.Fatalf("%s", err) } - res := &bor.ResponseWithHeight{} + + res := &heimdall.StateSyncEventsResponse{} if err := json.Unmarshal(stateData, res); err != nil { t.Fatalf("%s", err) } + return res } -func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) { +//nolint:unused,deadcode +func loadSpanFromFile(t *testing.T) (*heimdall.SpanResponse, *span.HeimdallSpan) { + t.Helper() + spanData, err := ioutil.ReadFile("./testdata/span.json") if err != nil { t.Fatalf("%s", err) } - res := &bor.ResponseWithHeight{} + + res := &heimdall.SpanResponse{} + if err := json.Unmarshal(spanData, res); err != nil { t.Fatalf("%s", err) } - heimdallSpan := &bor.HeimdallSpan{} - if err := json.Unmarshal(res.Result, heimdallSpan); err != nil { - t.Fatalf("%s", err) - } - return res, heimdallSpan + return res, &res.Result } func getSignerKey(number uint64) []byte { signerKey := privKey + isSpanStart := number%spanSize == 0 if isSpanStart { // validator set in the new span has changed signerKey = privKey2 } + _key, _ := hex.DecodeString(signerKey) + return _key } diff --git a/tests/bor/mocks/IHeimdallClient.go b/tests/bor/mocks/IHeimdallClient.go index 9420c261fb..f770ed9fa8 100644 --- a/tests/bor/mocks/IHeimdallClient.go +++ b/tests/bor/mocks/IHeimdallClient.go @@ -7,7 +7,9 @@ package mocks import ( reflect "reflect" - bor "github.com/ethereum/go-ethereum/consensus/bor" + clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk" + checkpoint "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" + span "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" gomock "github.com/golang/mock/gomock" ) @@ -46,26 +48,11 @@ func (mr *MockIHeimdallClientMockRecorder) Close() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIHeimdallClient)(nil).Close)) } -// Fetch mocks base method. -func (m *MockIHeimdallClient) Fetch(arg0, arg1 string) (*bor.ResponseWithHeight, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Fetch", arg0, arg1) - ret0, _ := ret[0].(*bor.ResponseWithHeight) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Fetch indicates an expected call of Fetch. -func (mr *MockIHeimdallClientMockRecorder) Fetch(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockIHeimdallClient)(nil).Fetch), arg0, arg1) -} - // FetchLatestCheckpoint mocks base method. -func (m *MockIHeimdallClient) FetchLatestCheckpoint() (*bor.Checkpoint, error) { +func (m *MockIHeimdallClient) FetchLatestCheckpoint() (*checkpoint.Checkpoint, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FetchLatestCheckpoint") - ret0, _ := ret[0].(*bor.Checkpoint) + ret0, _ := ret[0].(*checkpoint.Checkpoint) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -76,32 +63,32 @@ func (mr *MockIHeimdallClientMockRecorder) FetchLatestCheckpoint() *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchLatestCheckpoint", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchLatestCheckpoint)) } -// FetchStateSyncEvents mocks base method. -func (m *MockIHeimdallClient) FetchStateSyncEvents(arg0 uint64, arg1 int64) ([]*bor.EventRecordWithTime, error) { +// Span mocks base method. +func (m *MockIHeimdallClient) Span(arg0 uint64) (*span.HeimdallSpan, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchStateSyncEvents", arg0, arg1) - ret0, _ := ret[0].([]*bor.EventRecordWithTime) + ret := m.ctrl.Call(m, "Span", arg0) + ret0, _ := ret[0].(*span.HeimdallSpan) ret1, _ := ret[1].(error) return ret0, ret1 } -// FetchStateSyncEvents indicates an expected call of FetchStateSyncEvents. -func (mr *MockIHeimdallClientMockRecorder) FetchStateSyncEvents(arg0, arg1 interface{}) *gomock.Call { +// Span indicates an expected call of Span. +func (mr *MockIHeimdallClientMockRecorder) Span(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchStateSyncEvents", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchStateSyncEvents), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Span", reflect.TypeOf((*MockIHeimdallClient)(nil).Span), arg0) } -// FetchWithRetry mocks base method. -func (m *MockIHeimdallClient) FetchWithRetry(arg0, arg1 string) (*bor.ResponseWithHeight, error) { +// StateSyncEvents mocks base method. +func (m *MockIHeimdallClient) StateSyncEvents(arg0 uint64, arg1 int64) ([]*clerk.EventRecordWithTime, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchWithRetry", arg0, arg1) - ret0, _ := ret[0].(*bor.ResponseWithHeight) + ret := m.ctrl.Call(m, "StateSyncEvents", arg0, arg1) + ret0, _ := ret[0].([]*clerk.EventRecordWithTime) ret1, _ := ret[1].(error) return ret0, ret1 } -// FetchWithRetry indicates an expected call of FetchWithRetry. -func (mr *MockIHeimdallClientMockRecorder) FetchWithRetry(arg0, arg1 interface{}) *gomock.Call { +// StateSyncEvents indicates an expected call of StateSyncEvents. +func (mr *MockIHeimdallClientMockRecorder) StateSyncEvents(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchWithRetry", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchWithRetry), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateSyncEvents", reflect.TypeOf((*MockIHeimdallClient)(nil).StateSyncEvents), arg0, arg1) } diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index 192dff12cc..0b030c1485 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -14,6 +14,9 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +//go:build integration +// +build integration + package tests import ( diff --git a/tests/init_test.go b/tests/init_test.go index 7e2f3ff7f5..4ade0bfb90 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -14,6 +14,9 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +//go:build integration +// +build integration + package tests import ( diff --git a/tests/rlp_test.go b/tests/rlp_test.go index 79a1683eb2..dbca73efc6 100644 --- a/tests/rlp_test.go +++ b/tests/rlp_test.go @@ -14,6 +14,9 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +//go:build integration +// +build integration + package tests import ( diff --git a/tests/state_test.go b/tests/state_test.go index d2c92b211c..8fcf35b864 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -14,6 +14,9 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +//go:build integration +// +build integration + package tests import ( diff --git a/tests/transaction_test.go b/tests/transaction_test.go index cb0f262318..1197eebe19 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -14,6 +14,9 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +//go:build integration +// +build integration + package tests import ( diff --git a/trie/hasher.go b/trie/hasher.go index 7f0748c13d..c085970a3f 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -19,9 +19,10 @@ package trie import ( "sync" + "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" ) // hasher is a type used for the trie Hash operation. A hasher has some