mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
merge conflicts
This commit is contained in:
commit
543170235d
62 changed files with 6179 additions and 144 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -6,9 +6,9 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2.1.3
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16.7
|
||||
go-version: 1.17
|
||||
- name: "Build binaries"
|
||||
run: make all
|
||||
- name: "Run tests"
|
||||
|
|
|
|||
26
.github/workflows/dockerimage-latest.yml
vendored
26
.github/workflows/dockerimage-latest.yml
vendored
|
|
@ -1,26 +0,0 @@
|
|||
name: Docker Images For Latest Branches
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build docker image
|
||||
env:
|
||||
DOCKERHUB: ${{ secrets.DOCKERHUB }}
|
||||
DOCKERHUB_KEY: ${{ secrets.DOCKERHUB_KEY }}
|
||||
run: |
|
||||
set -x
|
||||
ls -l
|
||||
echo "Docker login"
|
||||
docker login -u $DOCKERHUB -p $DOCKERHUB_KEY
|
||||
echo "Running build"
|
||||
docker build -t maticnetwork/bor:${GITHUB_REF/refs\/heads\//} .
|
||||
echo "Pushing image"
|
||||
docker push maticnetwork/bor:${GITHUB_REF/refs\/heads\//}
|
||||
echo "Done"
|
||||
25
.github/workflows/dockerimage.yml
vendored
25
.github/workflows/dockerimage.yml
vendored
|
|
@ -1,25 +0,0 @@
|
|||
name: Bor Docker Image CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '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 -t maticnetwork/bor:${GITHUB_REF/refs\/tags\//} .
|
||||
echo "pushing image"
|
||||
docker push maticnetwork/bor:${GITHUB_REF/refs\/tags\//}
|
||||
echo "DONE!"
|
||||
67
.github/workflows/linuxpackage.yml
vendored
67
.github/workflows/linuxpackage.yml
vendored
|
|
@ -1,67 +0,0 @@
|
|||
name: Linux package
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: Set up Ruby 2.6
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
|
||||
- name: Retrieve release version
|
||||
run: |
|
||||
echo "RELEASE_VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build package
|
||||
run: |
|
||||
set -x
|
||||
|
||||
echo "Release version: ${{ env.RELEASE_VERSION }}"
|
||||
|
||||
sudo apt-get -yqq install libpq-dev build-essential
|
||||
gem install --no-document fpm
|
||||
fpm --version
|
||||
|
||||
make bor-all
|
||||
|
||||
fpm -s dir -t deb --deb-user root --deb-group root -n matic-bor -v ${{ env.RELEASE_VERSION }} \
|
||||
build/bin/bor=/usr/bin/ \
|
||||
build/bin/bootnode=/usr/bin/
|
||||
|
||||
mkdir packages-v${{ env.RELEASE_VERSION }}
|
||||
|
||||
mv matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb packages-v${{ env.RELEASE_VERSION }}/
|
||||
|
||||
ls packages-v${{ env.RELEASE_VERSION }}/
|
||||
|
||||
- name: S3 upload
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
with:
|
||||
args: --acl public-read
|
||||
env:
|
||||
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: "us-east-1" # optional: defaults to us-east-1
|
||||
SOURCE_DIR: "packages-v${{ env.RELEASE_VERSION }}"
|
||||
DEST_DIR: "v${{ env.RELEASE_VERSION }}"
|
||||
|
||||
- name: Slack Notification
|
||||
uses: rtCamp/action-slack-notify@v2.0.0
|
||||
env:
|
||||
SLACK_CHANNEL: code-releases
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
|
||||
SLACK_TITLE: "New linux package for Bor v${{ env.RELEASE_VERSION }} just got released"
|
||||
SLACK_MESSAGE: "Package has been uploaded to S3 bucket for public use and available at https://matic-public.s3.amazonaws.com/v${{ env.RELEASE_VERSION }}/matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb"
|
||||
43
.github/workflows/release.yml
vendored
Normal file
43
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- '**'
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
# to be used by fork patch-releases ^^
|
||||
- 'v*.*.*-*'
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: 1.17.x
|
||||
|
||||
- name: Prepare
|
||||
id: prepare
|
||||
run: |
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
echo ::set-output name=tag_name::${TAG}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Run GoReleaser
|
||||
run: |
|
||||
make release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ steps.prepare.outputs.tag_name }}
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKERHUB }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_KEY }}
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -47,3 +47,7 @@ profile.cov
|
|||
/dashboard/assets/package-lock.json
|
||||
|
||||
**/yarn-error.log
|
||||
./test
|
||||
./bor-debug-*
|
||||
|
||||
dist
|
||||
|
|
|
|||
126
.goreleaser.yml
Normal file
126
.goreleaser.yml
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
project_name: bor
|
||||
|
||||
release:
|
||||
disable: false
|
||||
draft: true
|
||||
prerelease: auto
|
||||
|
||||
builds:
|
||||
- id: darwin-amd64
|
||||
main: ./cmd/geth
|
||||
binary: bor
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
env:
|
||||
- CC=o64-clang
|
||||
- CXX=o64-clang++
|
||||
ldflags:
|
||||
-s -w
|
||||
|
||||
- id: darwin-arm64
|
||||
main: ./cmd/geth
|
||||
binary: bor
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- arm64
|
||||
env:
|
||||
- CC=oa64-clang
|
||||
- CXX=oa64-clang++
|
||||
ldflags:
|
||||
-s -w
|
||||
|
||||
- id: linux-amd64
|
||||
main: ./cmd/geth
|
||||
binary: bor
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
env:
|
||||
- CC=gcc
|
||||
- CXX=g++
|
||||
ldflags:
|
||||
# We need to build a static binary because we are building in a glibc based system and running in a musl container
|
||||
-s -w -linkmode external -extldflags "-static"
|
||||
|
||||
- id: linux-arm64
|
||||
main: ./cmd/geth
|
||||
binary: bor
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- arm64
|
||||
env:
|
||||
- CC=aarch64-linux-gnu-gcc
|
||||
- CXX=aarch64-linux-gnu-g++
|
||||
ldflags:
|
||||
# We need to build a static binary because we are building in a glibc based system and running in a musl container
|
||||
-s -w -linkmode external -extldflags "-static"
|
||||
|
||||
nfpms:
|
||||
- vendor: 0xPolygon
|
||||
homepage: https://polygon.technology
|
||||
maintainer: Polygon Team <team@polygon.technology>
|
||||
description: Polygon Blockchain
|
||||
license: GPLv3 LGPLv3
|
||||
|
||||
formats:
|
||||
- apk
|
||||
- deb
|
||||
- rpm
|
||||
|
||||
contents:
|
||||
- src: builder/files/bor.service
|
||||
dst: /lib/systemd/system/bor.service
|
||||
type: config
|
||||
|
||||
overrides:
|
||||
rpm:
|
||||
replacements:
|
||||
amd64: x86_64
|
||||
|
||||
snapshot:
|
||||
name_template: "{{ .Tag }}.next"
|
||||
|
||||
dockers:
|
||||
- image_templates:
|
||||
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-amd64
|
||||
dockerfile: Dockerfile.release
|
||||
use: buildx
|
||||
goarch: amd64
|
||||
ids:
|
||||
- linux-amd64
|
||||
build_flag_templates:
|
||||
- --platform=linux/amd64
|
||||
skip_push: true
|
||||
|
||||
- image_templates:
|
||||
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64
|
||||
dockerfile: Dockerfile.release
|
||||
use: buildx
|
||||
goarch: arm64
|
||||
ids:
|
||||
- linux-arm64
|
||||
build_flag_templates:
|
||||
- --platform=linux/arm64
|
||||
skip_push: true
|
||||
|
||||
docker_manifests:
|
||||
- name_template: 0xpolygon/{{ .ProjectName }}:{{ .Version }}
|
||||
image_templates:
|
||||
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-amd64
|
||||
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64
|
||||
|
||||
- name_template: 0xpolygon/{{ .ProjectName }}:latest
|
||||
image_templates:
|
||||
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-amd64
|
||||
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64
|
||||
|
||||
announce:
|
||||
slack:
|
||||
enabled: true
|
||||
# The name of the channel that the user selected as a destination for webhook messages.
|
||||
channel: '#code-releases'
|
||||
25
Dockerfile
25
Dockerfile
|
|
@ -1,18 +1,17 @@
|
|||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.17-alpine as builder
|
||||
FROM golang:latest
|
||||
|
||||
RUN apk add --no-cache make gcc musl-dev linux-headers git bash
|
||||
ARG BOR_DIR=/bor
|
||||
ENV BOR_DIR=$BOR_DIR
|
||||
|
||||
ADD . /bor
|
||||
RUN cd /bor && make bor-all
|
||||
RUN apt-get update -y && apt-get upgrade -y \
|
||||
&& apt install build-essential git tini -y \
|
||||
&& mkdir -p /bor
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
WORKDIR ${BOR_DIR}
|
||||
COPY . .
|
||||
RUN make bor-all
|
||||
|
||||
# Pull Bor into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
ENV SHELL /bin/bash
|
||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
||||
|
||||
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
|
||||
ENTRYPOINT ["bor"]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ RUN cd /bor && make bor-all
|
|||
# Pull all binaries into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache ca-certificates
|
||||
RUN set -x \
|
||||
&& apk add --update --no-cache \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
COPY --from=builder /bor/build/bin/* /usr/local/bin/
|
||||
|
||||
EXPOSE 8545 8546 30303 30303/udp
|
||||
EXPOSE 8545 8546 30303 30303/udp
|
||||
|
|
|
|||
10
Dockerfile.release
Normal file
10
Dockerfile.release
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
FROM alpine:3.14
|
||||
|
||||
RUN set -x \
|
||||
&& apk add --update --no-cache \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
COPY bor /usr/local/bin/
|
||||
|
||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
||||
ENTRYPOINT ["bor"]
|
||||
37
Makefile
37
Makefile
|
|
@ -13,6 +13,9 @@ GO ?= latest
|
|||
GORUN = env GO111MODULE=on go run
|
||||
GOPATH = $(shell go env GOPATH)
|
||||
|
||||
protoc:
|
||||
protoc --go_out=. --go-grpc_out=. ./command/server/proto/*.proto
|
||||
|
||||
bor:
|
||||
$(GORUN) build/ci.go install ./cmd/geth
|
||||
mkdir -p $(GOPATH)/bin/
|
||||
|
|
@ -160,3 +163,37 @@ geth-windows-amd64:
|
|||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/geth
|
||||
@echo "Windows amd64 cross compilation done:"
|
||||
@ls -ld $(GOBIN)/geth-windows-* | grep amd64
|
||||
|
||||
PACKAGE_NAME := github.com/maticnetwork/bor
|
||||
GOLANG_CROSS_VERSION ?= v1.17.2
|
||||
|
||||
.PHONY: release-dry-run
|
||||
release-dry-run:
|
||||
@docker run \
|
||||
--rm \
|
||||
--privileged \
|
||||
-e CGO_ENABLED=1 \
|
||||
-e GITHUB_TOKEN \
|
||||
-e DOCKER_USERNAME \
|
||||
-e DOCKER_PASSWORD \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v `pwd`:/go/src/$(PACKAGE_NAME) \
|
||||
-w /go/src/$(PACKAGE_NAME) \
|
||||
ghcr.io/troian/golang-cross:${GOLANG_CROSS_VERSION} \
|
||||
--rm-dist --skip-validate --skip-publish
|
||||
|
||||
.PHONY: release
|
||||
release:
|
||||
@docker run \
|
||||
--rm \
|
||||
--privileged \
|
||||
-e CGO_ENABLED=1 \
|
||||
-e GITHUB_TOKEN \
|
||||
-e DOCKER_USERNAME \
|
||||
-e DOCKER_PASSWORD \
|
||||
-e SLACK_WEBHOOK \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v `pwd`:/go/src/$(PACKAGE_NAME) \
|
||||
-w /go/src/$(PACKAGE_NAME) \
|
||||
ghcr.io/troian/golang-cross:${GOLANG_CROSS_VERSION} \
|
||||
--rm-dist --skip-validate
|
||||
|
|
|
|||
|
|
@ -113,6 +113,12 @@ them using your favourite package manager. Once the dependencies are installed,
|
|||
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
||||
|
||||
|
||||
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
|
||||
|
|
|
|||
18
builder/files/bor.service
Normal file
18
builder/files/bor.service
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[Unit]
|
||||
Description=bor
|
||||
StartLimitIntervalSec=500
|
||||
StartLimitBurst=5
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
WorkingDirectory=$NODE_DIR
|
||||
EnvironmentFile=/etc/matic/metadata
|
||||
ExecStart=/usr/local/bin/bor $VALIDATOR_ADDRESS
|
||||
Type=simple
|
||||
User=$USER
|
||||
KillSignal=SIGINT
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
36
command/account.go
Normal file
36
command/account.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import "github.com/mitchellh/cli"
|
||||
|
||||
type Account struct {
|
||||
UI cli.Ui
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (a *Account) Help() string {
|
||||
return `Usage: bor account <subcommand>
|
||||
|
||||
This command groups actions to interact with accounts.
|
||||
|
||||
List the running deployments:
|
||||
|
||||
$ bor account new
|
||||
|
||||
Display the status of a specific deployment:
|
||||
|
||||
$ bor account import
|
||||
|
||||
List the imported accounts in the keystore:
|
||||
|
||||
$ bor account list`
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (a *Account) Synopsis() string {
|
||||
return "Interact with accounts"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (a *Account) Run(args []string) int {
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
74
command/account_import.go
Normal file
74
command/account_import.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
type AccountImportCommand struct {
|
||||
*Meta
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (a *AccountImportCommand) Help() string {
|
||||
return `Usage: bor account import
|
||||
|
||||
Import a private key into a new account.
|
||||
|
||||
Import an account:
|
||||
|
||||
$ bor account import key.json
|
||||
|
||||
` + a.Flags().Help()
|
||||
}
|
||||
|
||||
func (a *AccountImportCommand) Flags() *flagset.Flagset {
|
||||
return a.NewFlagSet("account import")
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (a *AccountImportCommand) Synopsis() string {
|
||||
return "Import a private key into a new account"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (a *AccountImportCommand) Run(args []string) int {
|
||||
flags := a.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
a.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
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
|
||||
}
|
||||
|
||||
keystore, err := a.GetKeystore()
|
||||
if err != nil {
|
||||
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
password, err := a.AskPassword()
|
||||
if err != nil {
|
||||
a.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
acct, err := keystore.ImportECDSA(key, password)
|
||||
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
|
||||
}
|
||||
62
command/account_list.go
Normal file
62
command/account_list.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
)
|
||||
|
||||
type AccountListCommand struct {
|
||||
*Meta
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (a *AccountListCommand) Help() string {
|
||||
return `Usage: bor account list
|
||||
|
||||
List the local accounts.
|
||||
|
||||
` + a.Flags().Help()
|
||||
}
|
||||
|
||||
func (a *AccountListCommand) Flags() *flagset.Flagset {
|
||||
return a.NewFlagSet("account list")
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (a *AccountListCommand) Synopsis() string {
|
||||
return "List the local accounts"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (a *AccountListCommand) Run(args []string) int {
|
||||
flags := a.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
a.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
keystore, err := a.GetKeystore()
|
||||
if err != nil {
|
||||
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||
return 1
|
||||
}
|
||||
a.UI.Output(formatAccounts(keystore.Accounts()))
|
||||
return 0
|
||||
}
|
||||
|
||||
func formatAccounts(accts []accounts.Account) string {
|
||||
if len(accts) == 0 {
|
||||
return "No accounts found"
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
62
command/account_new.go
Normal file
62
command/account_new.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
)
|
||||
|
||||
type AccountNewCommand struct {
|
||||
*Meta
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (a *AccountNewCommand) Help() string {
|
||||
return `Usage: bor account new
|
||||
|
||||
Create a new local account.
|
||||
|
||||
` + a.Flags().Help()
|
||||
}
|
||||
|
||||
func (a *AccountNewCommand) Flags() *flagset.Flagset {
|
||||
return a.NewFlagSet("account new")
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (a *AccountNewCommand) Synopsis() string {
|
||||
return "Create a new local account"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (a *AccountNewCommand) Run(args []string) int {
|
||||
flags := a.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
a.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
keystore, err := a.GetKeystore()
|
||||
if err != nil {
|
||||
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
password, err := a.AskPassword()
|
||||
if err != nil {
|
||||
a.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
account, err := keystore.NewAccount(password)
|
||||
if err != nil {
|
||||
a.UI.Error(fmt.Sprintf("Failed to create new account: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
a.UI.Output("\nYour new key was generated")
|
||||
a.UI.Output(fmt.Sprintf("Public address of the key: %s", account.Address.Hex()))
|
||||
a.UI.Output(fmt.Sprintf("Path of the secret key file: %s", account.URL.Path))
|
||||
|
||||
return 0
|
||||
}
|
||||
31
command/chain.go
Normal file
31
command/chain.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// ChainCommand is the command to group the peers commands
|
||||
type ChainCommand struct {
|
||||
UI cli.Ui
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (c *ChainCommand) Help() string {
|
||||
return `Usage: bor chain <subcommand>
|
||||
|
||||
This command groups actions to interact with the chain.
|
||||
|
||||
Set the new head of the chain:
|
||||
|
||||
$ bor chain sethead <number>`
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *ChainCommand) Synopsis() string {
|
||||
return "Interact with the chain"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *ChainCommand) Run(args []string) int {
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
91
command/chain_sethead.go
Normal file
91
command/chain_sethead.go
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
)
|
||||
|
||||
// ChainSetHeadCommand is the command to group the peers commands
|
||||
type ChainSetHeadCommand struct {
|
||||
*Meta2
|
||||
|
||||
yes bool
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (c *ChainSetHeadCommand) Help() string {
|
||||
return `Usage: bor chain sethead <number> [--yes]
|
||||
|
||||
This command sets the current chain to a certain block`
|
||||
}
|
||||
|
||||
func (c *ChainSetHeadCommand) Flags() *flagset.Flagset {
|
||||
flags := c.NewFlagSet("chain sethead")
|
||||
|
||||
flags.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "yes",
|
||||
Usage: "Force set head",
|
||||
Default: false,
|
||||
Value: &c.yes,
|
||||
})
|
||||
return flags
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *ChainSetHeadCommand) Synopsis() string {
|
||||
return "Set the new head of the chain"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *ChainSetHeadCommand) Run(args []string) int {
|
||||
flags := c.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.UI.Error("No number provided")
|
||||
return 1
|
||||
}
|
||||
|
||||
borClt, err := c.BorConn()
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
arg := args[0]
|
||||
fmt.Println(arg)
|
||||
|
||||
number, err := strconv.Atoi(arg)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if !c.yes {
|
||||
response, err := c.UI.Ask("Are you sure you want to reset the database? (y/n)")
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
if response != "y" {
|
||||
c.UI.Output("set head aborted")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := borClt.ChainSetHead(context.Background(), &proto.ChainSetHeadRequest{Number: uint64(number)}); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
c.UI.Output("Done!")
|
||||
return 0
|
||||
}
|
||||
242
command/debug.go
Normal file
242
command/debug.go
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
package main
|
||||
|
||||
// Based on https://github.com/hashicorp/nomad/blob/main/command/operator_debug.go
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
)
|
||||
|
||||
type DebugCommand struct {
|
||||
*Meta2
|
||||
|
||||
seconds uint64
|
||||
output string
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (d *DebugCommand) Help() string {
|
||||
return `Usage: bor debug
|
||||
|
||||
Build an archive containing Bor pprof traces
|
||||
|
||||
` + d.Flags().Help()
|
||||
}
|
||||
|
||||
func (d *DebugCommand) 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 *DebugCommand) Synopsis() string {
|
||||
return "Build an archive containing Bor pprof traces"
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
clt, err := d.BorConn()
|
||||
if err != nil {
|
||||
d.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
stamped := "bor-debug-" + time.Now().UTC().Format("2006-01-02-150405Z")
|
||||
|
||||
// Create the output directory
|
||||
var tmp string
|
||||
if d.output != "" {
|
||||
// User specified output directory
|
||||
tmp = filepath.Join(d.output, stamped)
|
||||
_, err := os.Stat(tmp)
|
||||
if !os.IsNotExist(err) {
|
||||
d.UI.Error("Output directory already exists")
|
||||
return 1
|
||||
}
|
||||
} else {
|
||||
// Generate temp directory
|
||||
tmp, err = ioutil.TempDir(os.TempDir(), stamped)
|
||||
if err != nil {
|
||||
d.UI.Error(fmt.Sprintf("Error creating tmp directory: %s", err.Error()))
|
||||
return 1
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
resp, err := clt.Pprof(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// write file
|
||||
raw, err := hex.DecodeString(resp.Payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(tmp, filename+".prof"), raw, 0755); 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
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
d.UI.Output(fmt.Sprintf("Created debug archive: %s", archiveFile))
|
||||
return 0
|
||||
}
|
||||
|
||||
func trapSignal(cancel func()) {
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh,
|
||||
syscall.SIGHUP,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGQUIT)
|
||||
|
||||
go func() {
|
||||
<-sigCh
|
||||
cancel()
|
||||
}()
|
||||
}
|
||||
|
||||
func tarCZF(archive string, src, target string) error {
|
||||
// ensure the src actually exists before trying to tar it
|
||||
if _, err := os.Stat(src); err != nil {
|
||||
return fmt.Errorf("unable to tar files - %v", err.Error())
|
||||
}
|
||||
|
||||
// create the archive
|
||||
fh, err := os.Create(archive)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
zz := gzip.NewWriter(fh)
|
||||
defer zz.Close()
|
||||
|
||||
tw := tar.NewWriter(zz)
|
||||
defer tw.Close()
|
||||
|
||||
// tar
|
||||
return filepath.Walk(src, func(file string, fi os.FileInfo, err error) error {
|
||||
// return on any error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !fi.Mode().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
|
||||
header, err := tar.FileInfoHeader(fi, fi.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove leading path to the src, so files are relative to the archive
|
||||
path := strings.ReplaceAll(file, src, "")
|
||||
if target != "" {
|
||||
path = filepath.Join([]string{target, path}...)
|
||||
}
|
||||
path = strings.TrimPrefix(path, string(filepath.Separator))
|
||||
|
||||
header.Name = path
|
||||
|
||||
if err := tw.WriteHeader(header); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy the file contents
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(tw, f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Close()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
242
command/flagset/flagset.go
Normal file
242
command/flagset/flagset.go
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
package flagset
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Flagset struct {
|
||||
flags []*FlagVar
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
func NewFlagSet(name string) *Flagset {
|
||||
f := &Flagset{
|
||||
flags: []*FlagVar{},
|
||||
set: flag.NewFlagSet(name, flag.ContinueOnError),
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
type FlagVar struct {
|
||||
Name string
|
||||
Usage string
|
||||
}
|
||||
|
||||
func (f *Flagset) addFlag(fl *FlagVar) {
|
||||
f.flags = append(f.flags, fl)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
func (f *Flagset) Parse(args []string) error {
|
||||
return f.set.Parse(args)
|
||||
}
|
||||
|
||||
func (f *Flagset) Args() []string {
|
||||
return f.set.Args()
|
||||
}
|
||||
|
||||
type BoolFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Default bool
|
||||
Value *bool
|
||||
}
|
||||
|
||||
func (f *Flagset) BoolFlag(b *BoolFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: b.Name,
|
||||
Usage: b.Usage,
|
||||
})
|
||||
f.set.BoolVar(b.Value, b.Name, b.Default, b.Usage)
|
||||
}
|
||||
|
||||
type StringFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Default string
|
||||
Value *string
|
||||
}
|
||||
|
||||
func (f *Flagset) StringFlag(b *StringFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: b.Name,
|
||||
Usage: b.Usage,
|
||||
})
|
||||
f.set.StringVar(b.Value, b.Name, b.Default, b.Usage)
|
||||
}
|
||||
|
||||
type IntFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Value *int
|
||||
Default int
|
||||
}
|
||||
|
||||
func (f *Flagset) IntFlag(i *IntFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: i.Name,
|
||||
Usage: i.Usage,
|
||||
})
|
||||
f.set.IntVar(i.Value, i.Name, i.Default, i.Usage)
|
||||
}
|
||||
|
||||
type Uint64Flag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Value *uint64
|
||||
Default uint64
|
||||
}
|
||||
|
||||
func (f *Flagset) Uint64Flag(i *Uint64Flag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: i.Name,
|
||||
Usage: i.Usage,
|
||||
})
|
||||
f.set.Uint64Var(i.Value, i.Name, i.Default, i.Usage)
|
||||
}
|
||||
|
||||
type BigIntFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Value *big.Int
|
||||
}
|
||||
|
||||
func (b *BigIntFlag) String() string {
|
||||
if b.Value == nil {
|
||||
return ""
|
||||
}
|
||||
return b.Value.String()
|
||||
}
|
||||
|
||||
func (b *BigIntFlag) Set(value string) error {
|
||||
num := new(big.Int)
|
||||
|
||||
var ok bool
|
||||
if strings.HasPrefix(value, "0x") {
|
||||
num, ok = num.SetString(value[2:], 16)
|
||||
} else {
|
||||
num, ok = num.SetString(value, 10)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to set big int")
|
||||
}
|
||||
b.Value = num
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Flagset) BigIntFlag(b *BigIntFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: b.Name,
|
||||
Usage: b.Usage,
|
||||
})
|
||||
f.set.Var(b, b.Name, b.Usage)
|
||||
}
|
||||
|
||||
type SliceStringFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Value *[]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
|
||||
}
|
||||
|
||||
func (f *Flagset) SliceStringFlag(s *SliceStringFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: s.Name,
|
||||
Usage: s.Usage,
|
||||
})
|
||||
f.set.Var(s, s.Name, s.Usage)
|
||||
}
|
||||
|
||||
type DurationFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Value *time.Duration
|
||||
Default time.Duration
|
||||
}
|
||||
|
||||
func (f *Flagset) DurationFlag(d *DurationFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: d.Name,
|
||||
Usage: d.Usage,
|
||||
})
|
||||
f.set.DurationVar(d.Value, d.Name, d.Default, "")
|
||||
}
|
||||
|
||||
type MapStringFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Value *map[string]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, ",")
|
||||
}
|
||||
|
||||
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, "=")
|
||||
|
||||
if len(kv) == 2 {
|
||||
(*m.Value)[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Flagset) MapStringFlag(m *MapStringFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: m.Name,
|
||||
Usage: m.Usage,
|
||||
})
|
||||
f.set.Var(m, m.Name, m.Usage)
|
||||
}
|
||||
|
||||
type Float64Flag struct {
|
||||
Name string
|
||||
Usage string
|
||||
Value *float64
|
||||
Default float64
|
||||
}
|
||||
|
||||
func (f *Flagset) Float64Flag(i *Float64Flag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: i.Name,
|
||||
Usage: i.Usage,
|
||||
})
|
||||
f.set.Float64Var(i.Value, i.Name, i.Default, "")
|
||||
}
|
||||
60
command/flagset/flagset_test.go
Normal file
60
command/flagset/flagset_test.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package flagset
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFlagsetBool(t *testing.T) {
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := false
|
||||
f.BoolFlag(&BoolFlag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "true"}))
|
||||
assert.Equal(t, value, true)
|
||||
}
|
||||
|
||||
func TestFlagsetSliceString(t *testing.T) {
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := []string{}
|
||||
f.SliceStringFlag(&SliceStringFlag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "a,b", "--flag", "c"}))
|
||||
assert.Equal(t, value, []string{"a", "b", "c"})
|
||||
}
|
||||
|
||||
func TestFlagsetDuration(t *testing.T) {
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := time.Duration(0)
|
||||
f.DurationFlag(&DurationFlag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "1m"}))
|
||||
assert.Equal(t, value, 1*time.Minute)
|
||||
}
|
||||
|
||||
func TestFlagsetMapString(t *testing.T) {
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := map[string]string{}
|
||||
f.MapStringFlag(&MapStringFlag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "a=b,c=d"}))
|
||||
assert.Equal(t, value, map[string]string{"a": "b", "c": "d"})
|
||||
}
|
||||
217
command/main.go
Normal file
217
command/main.go
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/command/server"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/ryanuber/columnize"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(Run(os.Args[1:]))
|
||||
}
|
||||
|
||||
func Run(args []string) int {
|
||||
commands := commands()
|
||||
|
||||
cli := &cli.CLI{
|
||||
Name: "bor",
|
||||
Args: args,
|
||||
Commands: commands,
|
||||
}
|
||||
|
||||
exitCode, err := cli.Run()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
|
||||
return 1
|
||||
}
|
||||
return exitCode
|
||||
}
|
||||
|
||||
func commands() map[string]cli.CommandFactory {
|
||||
ui := &cli.BasicUi{
|
||||
Reader: os.Stdin,
|
||||
Writer: os.Stdout,
|
||||
ErrorWriter: os.Stderr,
|
||||
}
|
||||
|
||||
meta2 := &Meta2{
|
||||
UI: ui,
|
||||
}
|
||||
meta := &Meta{
|
||||
UI: ui,
|
||||
}
|
||||
return map[string]cli.CommandFactory{
|
||||
"server": func() (cli.Command, error) {
|
||||
return &server.Command{
|
||||
UI: ui,
|
||||
}, nil
|
||||
},
|
||||
"version": func() (cli.Command, error) {
|
||||
return &VersionCommand{
|
||||
UI: ui,
|
||||
}, nil
|
||||
},
|
||||
"debug": func() (cli.Command, error) {
|
||||
return &DebugCommand{
|
||||
Meta2: meta2,
|
||||
}, nil
|
||||
},
|
||||
"chain": func() (cli.Command, error) {
|
||||
return &ChainCommand{
|
||||
UI: ui,
|
||||
}, nil
|
||||
},
|
||||
"chain sethead": func() (cli.Command, error) {
|
||||
return &ChainSetHeadCommand{
|
||||
Meta2: meta2,
|
||||
}, nil
|
||||
},
|
||||
"account": func() (cli.Command, error) {
|
||||
return &Account{
|
||||
UI: ui,
|
||||
}, nil
|
||||
},
|
||||
"account new": func() (cli.Command, error) {
|
||||
return &AccountNewCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"account import": func() (cli.Command, error) {
|
||||
return &AccountImportCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"account list": func() (cli.Command, error) {
|
||||
return &AccountListCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"peers": func() (cli.Command, error) {
|
||||
return &PeersCommand{
|
||||
UI: ui,
|
||||
}, nil
|
||||
},
|
||||
"peers add": func() (cli.Command, error) {
|
||||
return &PeersAddCommand{
|
||||
Meta2: meta2,
|
||||
}, nil
|
||||
},
|
||||
"peers remove": func() (cli.Command, error) {
|
||||
return &PeersRemoveCommand{
|
||||
Meta2: meta2,
|
||||
}, nil
|
||||
},
|
||||
"peers list": func() (cli.Command, error) {
|
||||
return &PeersListCommand{
|
||||
Meta2: meta2,
|
||||
}, nil
|
||||
},
|
||||
"peers status": func() (cli.Command, error) {
|
||||
return &PeersStatusCommand{
|
||||
Meta2: meta2,
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type Meta2 struct {
|
||||
UI cli.Ui
|
||||
|
||||
addr string
|
||||
}
|
||||
|
||||
func (m *Meta2) NewFlagSet(n string) *flagset.Flagset {
|
||||
f := flagset.NewFlagSet(n)
|
||||
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "address",
|
||||
Value: &m.addr,
|
||||
Usage: "Address of the grpc endpoint",
|
||||
Default: "127.0.0.1:3131",
|
||||
})
|
||||
return f
|
||||
}
|
||||
|
||||
func (m *Meta2) Conn() (*grpc.ClientConn, error) {
|
||||
conn, err := grpc.Dial(m.addr, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to server: %v", err)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (m *Meta2) BorConn() (proto.BorClient, error) {
|
||||
conn, err := m.Conn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.NewBorClient(conn), nil
|
||||
}
|
||||
|
||||
// Meta is a helper utility for the commands
|
||||
type Meta struct {
|
||||
UI cli.Ui
|
||||
|
||||
dataDir string
|
||||
keyStoreDir string
|
||||
}
|
||||
|
||||
func (m *Meta) NewFlagSet(n string) *flagset.Flagset {
|
||||
f := flagset.NewFlagSet(n)
|
||||
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "datadir",
|
||||
Value: &m.dataDir,
|
||||
Usage: "Path of the data directory to store information",
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "keystore",
|
||||
Value: &m.keyStoreDir,
|
||||
Usage: "Path of the data directory to store information",
|
||||
})
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (m *Meta) AskPassword() (string, error) {
|
||||
return m.UI.AskSecret("Your new account is locked with a password. Please give a password. Do not forget this password")
|
||||
}
|
||||
|
||||
func (m *Meta) GetKeystore() (*keystore.KeyStore, error) {
|
||||
cfg := node.DefaultConfig
|
||||
cfg.DataDir = m.dataDir
|
||||
cfg.KeyStoreDir = m.keyStoreDir
|
||||
|
||||
stack, err := node.New(&cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keydir := stack.KeyStoreDir()
|
||||
scryptN := keystore.StandardScryptN
|
||||
scryptP := keystore.StandardScryptP
|
||||
|
||||
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func formatList(in []string) string {
|
||||
columnConf := columnize.DefaultConfig()
|
||||
columnConf.Empty = "<none>"
|
||||
return columnize.Format(in, columnConf)
|
||||
}
|
||||
|
||||
func formatKV(in []string) string {
|
||||
columnConf := columnize.DefaultConfig()
|
||||
columnConf.Empty = "<none>"
|
||||
columnConf.Glue = " = "
|
||||
return columnize.Format(in, columnConf)
|
||||
}
|
||||
43
command/peers.go
Normal file
43
command/peers.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// PeersCommand is the command to group the peers commands
|
||||
type PeersCommand struct {
|
||||
UI cli.Ui
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (c *PeersCommand) Help() string {
|
||||
return `Usage: bor peers <subcommand>
|
||||
|
||||
This command groups actions to interact with peers.
|
||||
|
||||
List the connected peers:
|
||||
|
||||
$ bor account new
|
||||
|
||||
Add a new peer by enode:
|
||||
|
||||
$ bor account import
|
||||
|
||||
Remove a connected peer by enode:
|
||||
|
||||
$ bor peers remove <enode>
|
||||
|
||||
Display information about a peer:
|
||||
|
||||
$ bor peers status <peer id>`
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *PeersCommand) Synopsis() string {
|
||||
return "Interact with peers"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *PeersCommand) Run(args []string) int {
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
72
command/peers_add.go
Normal file
72
command/peers_add.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
)
|
||||
|
||||
// PeersAddCommand is the command to group the peers commands
|
||||
type PeersAddCommand struct {
|
||||
*Meta2
|
||||
|
||||
trusted bool
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (p *PeersAddCommand) Help() string {
|
||||
return `Usage: bor peers add <enode>
|
||||
|
||||
Joins the local client to another remote peer.
|
||||
|
||||
` + p.Flags().Help()
|
||||
}
|
||||
|
||||
func (p *PeersAddCommand) Flags() *flagset.Flagset {
|
||||
flags := p.NewFlagSet("peers add")
|
||||
|
||||
flags.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "trusted",
|
||||
Usage: "Add the peer as a trusted",
|
||||
Value: &p.trusted,
|
||||
})
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *PeersAddCommand) Synopsis() string {
|
||||
return "Join the client to a remote peer"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *PeersAddCommand) Run(args []string) int {
|
||||
flags := c.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.UI.Error("No enode address provided")
|
||||
return 1
|
||||
}
|
||||
|
||||
borClt, err := c.BorConn()
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
req := &proto.PeersAddRequest{
|
||||
Enode: args[0],
|
||||
Trusted: c.trusted,
|
||||
}
|
||||
if _, err := borClt.PeersAdd(context.Background(), req); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
81
command/peers_list.go
Normal file
81
command/peers_list.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
)
|
||||
|
||||
// PeersListCommand is the command to group the peers commands
|
||||
type PeersListCommand struct {
|
||||
*Meta2
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (p *PeersListCommand) Help() string {
|
||||
return `Usage: bor peers list
|
||||
|
||||
Build an archive containing Bor pprof traces
|
||||
|
||||
` + p.Flags().Help()
|
||||
}
|
||||
|
||||
func (p *PeersListCommand) Flags() *flagset.Flagset {
|
||||
flags := p.NewFlagSet("peers list")
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *PeersListCommand) Synopsis() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *PeersListCommand) Run(args []string) int {
|
||||
flags := c.Flags()
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func formatPeers(peers []*proto.Peer) string {
|
||||
if len(peers) == 0 {
|
||||
return "No peers found"
|
||||
}
|
||||
|
||||
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://")
|
||||
|
||||
rows[i+1] = fmt.Sprintf("%s|%s|%s|%s|%v|%v",
|
||||
d.Id,
|
||||
enode[:10],
|
||||
d.Name,
|
||||
strings.Join(d.Caps, ","),
|
||||
d.Static,
|
||||
d.Trusted)
|
||||
}
|
||||
return formatList(rows)
|
||||
}
|
||||
72
command/peers_remove.go
Normal file
72
command/peers_remove.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
)
|
||||
|
||||
// PeersRemoveCommand is the command to group the peers commands
|
||||
type PeersRemoveCommand struct {
|
||||
*Meta2
|
||||
|
||||
trusted bool
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (p *PeersRemoveCommand) Help() string {
|
||||
return `Usage: bor peers remove <enode>
|
||||
|
||||
Disconnects the local client from a connected peer if exists.
|
||||
|
||||
` + p.Flags().Help()
|
||||
}
|
||||
|
||||
func (p *PeersRemoveCommand) Flags() *flagset.Flagset {
|
||||
flags := p.NewFlagSet("peers remove")
|
||||
|
||||
flags.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "trusted",
|
||||
Usage: "Add the peer as a trusted",
|
||||
Value: &p.trusted,
|
||||
})
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *PeersRemoveCommand) Synopsis() string {
|
||||
return "Disconnects a peer from the client"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *PeersRemoveCommand) Run(args []string) int {
|
||||
flags := c.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.UI.Error("No enode address provided")
|
||||
return 1
|
||||
}
|
||||
|
||||
borClt, err := c.BorConn()
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
req := &proto.PeersRemoveRequest{
|
||||
Enode: args[0],
|
||||
Trusted: c.trusted,
|
||||
}
|
||||
if _, err := borClt.PeersRemove(context.Background(), req); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
81
command/peers_status.go
Normal file
81
command/peers_status.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
)
|
||||
|
||||
// PeersStatusCommand is the command to group the peers commands
|
||||
type PeersStatusCommand struct {
|
||||
*Meta2
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (p *PeersStatusCommand) Help() string {
|
||||
return `Usage: bor peers status <peer id>
|
||||
|
||||
Display the status of a peer by its id.
|
||||
|
||||
` + p.Flags().Help()
|
||||
}
|
||||
|
||||
func (p *PeersStatusCommand) Flags() *flagset.Flagset {
|
||||
flags := p.NewFlagSet("peers status")
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *PeersStatusCommand) Synopsis() string {
|
||||
return "Display the status of a peer"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *PeersStatusCommand) Run(args []string) int {
|
||||
flags := c.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.UI.Error("No enode address provided")
|
||||
return 1
|
||||
}
|
||||
|
||||
borClt, err := c.BorConn()
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
req := &proto.PeersStatusRequest{
|
||||
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
|
||||
}
|
||||
|
||||
func formatPeer(peer *proto.Peer) string {
|
||||
base := formatKV([]string{
|
||||
fmt.Sprintf("Name|%s", peer.Name),
|
||||
fmt.Sprintf("ID|%s", peer.Id),
|
||||
fmt.Sprintf("ENR|%s", peer.Enr),
|
||||
fmt.Sprintf("Capabilities|%s", strings.Join(peer.Caps, ",")),
|
||||
fmt.Sprintf("Enode|%s", peer.Enode),
|
||||
fmt.Sprintf("Static|%v", peer.Static),
|
||||
fmt.Sprintf("Trusted|%v", peer.Trusted),
|
||||
})
|
||||
return base
|
||||
}
|
||||
35
command/server/chains/allocs/mainnet.json
Normal file
35
command/server/chains/allocs/mainnet.json
Normal file
File diff suppressed because one or more lines are too long
30
command/server/chains/allocs/mumbai.json
Normal file
30
command/server/chains/allocs/mumbai.json
Normal file
File diff suppressed because one or more lines are too long
24
command/server/chains/chain.go
Normal file
24
command/server/chains/chain.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package chains
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
)
|
||||
|
||||
type Chain struct {
|
||||
Hash common.Hash
|
||||
Genesis *core.Genesis
|
||||
Bootnodes []string
|
||||
NetworkId uint64
|
||||
DNS []string
|
||||
}
|
||||
|
||||
var chains = map[string]*Chain{
|
||||
"mainnet": mainnetBor,
|
||||
"mumbai": mumbaiTestnet,
|
||||
}
|
||||
|
||||
func GetChain(name string) (*Chain, bool) {
|
||||
chain, ok := chains[name]
|
||||
return chain, ok
|
||||
}
|
||||
62
command/server/chains/mainnet.go
Normal file
62
command/server/chains/mainnet.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package chains
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var mainnetBor = &Chain{
|
||||
Hash: common.HexToHash("0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b"),
|
||||
NetworkId: 137,
|
||||
Genesis: &core.Genesis{
|
||||
Config: ¶ms.ChainConfig{
|
||||
ChainID: big.NewInt(137),
|
||||
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(3395000),
|
||||
MuirGlacierBlock: big.NewInt(3395000),
|
||||
BerlinBlock: big.NewInt(14750000),
|
||||
Bor: ¶ms.BorConfig{
|
||||
Period: 2,
|
||||
ProducerDelay: 6,
|
||||
Sprint: 64,
|
||||
BackupMultiplier: 2,
|
||||
ValidatorContract: "0x0000000000000000000000000000000000001000",
|
||||
StateReceiverContract: "0x0000000000000000000000000000000000001001",
|
||||
OverrideStateSyncRecords: map[string]int{
|
||||
"14949120": 8,
|
||||
"14949184": 0,
|
||||
"14953472": 0,
|
||||
"14953536": 5,
|
||||
"14953600": 0,
|
||||
"14953664": 0,
|
||||
"14953728": 0,
|
||||
"14953792": 0,
|
||||
"14953856": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
Nonce: 0,
|
||||
Timestamp: 1590824836,
|
||||
GasLimit: 10000000,
|
||||
Difficulty: big.NewInt(1),
|
||||
Mixhash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
Coinbase: common.HexToAddress("0x0000000000000000000000000000000000000000"),
|
||||
Alloc: readPrealloc("allocs/mainnet.json"),
|
||||
},
|
||||
Bootnodes: []string{
|
||||
"enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303",
|
||||
"enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303",
|
||||
},
|
||||
}
|
||||
51
command/server/chains/mumbai.go
Normal file
51
command/server/chains/mumbai.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package chains
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var mumbaiTestnet = &Chain{
|
||||
Hash: common.HexToHash("0x7b66506a9ebdbf30d32b43c5f15a3b1216269a1ec3a75aa3182b86176a2b1ca7"),
|
||||
NetworkId: 80001,
|
||||
Genesis: &core.Genesis{
|
||||
Config: ¶ms.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(2722000),
|
||||
MuirGlacierBlock: big.NewInt(2722000),
|
||||
BerlinBlock: big.NewInt(13996000),
|
||||
Bor: ¶ms.BorConfig{
|
||||
Period: 2,
|
||||
ProducerDelay: 6,
|
||||
Sprint: 64,
|
||||
BackupMultiplier: 2,
|
||||
ValidatorContract: "0x0000000000000000000000000000000000001000",
|
||||
StateReceiverContract: "0x0000000000000000000000000000000000001001",
|
||||
},
|
||||
},
|
||||
Nonce: 0,
|
||||
Timestamp: 1558348305,
|
||||
GasLimit: 10000000,
|
||||
Difficulty: big.NewInt(1),
|
||||
Mixhash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
Coinbase: common.HexToAddress("0x0000000000000000000000000000000000000000"),
|
||||
Alloc: readPrealloc("allocs/mumbai.json"),
|
||||
},
|
||||
Bootnodes: []string{
|
||||
"enode://320553cda00dfc003f499a3ce9598029f364fbb3ed1222fdc20a94d97dcc4d8ba0cd0bfa996579dcc6d17a534741fb0a5da303a90579431259150de66b597251@54.147.31.250:30303",
|
||||
"enode://f0f48a8781629f95ff02606081e6e43e4aebd503f3d07fc931fad7dd5ca1ba52bd849a6f6c3be0e375cf13c9ae04d859c4a9ae3546dc8ed4f10aa5dbb47d4998@34.226.134.117:30303",
|
||||
},
|
||||
}
|
||||
27
command/server/chains/utils.go
Normal file
27
command/server/chains/utils.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package chains
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
)
|
||||
|
||||
//go:embed allocs
|
||||
var allocs embed.FS
|
||||
|
||||
func readPrealloc(filename string) core.GenesisAlloc {
|
||||
f, err := allocs.Open(filename)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Could not open genesis preallocation for %s: %v", filename, err))
|
||||
}
|
||||
defer f.Close()
|
||||
decoder := json.NewDecoder(f)
|
||||
ga := make(core.GenesisAlloc)
|
||||
err = decoder.Decode(&ga)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Could not parse genesis preallocation for %s: %v", filename, err))
|
||||
}
|
||||
return ga
|
||||
}
|
||||
102
command/server/command.go
Normal file
102
command/server/command.go
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// Command is the command to start the sever
|
||||
type Command struct {
|
||||
UI cli.Ui
|
||||
|
||||
// cli configuration
|
||||
cliConfig *Config
|
||||
|
||||
// final configuration
|
||||
config *Config
|
||||
|
||||
configFile []string
|
||||
|
||||
srv *Server
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (c *Command) Help() string {
|
||||
return `Usage: bor [options]
|
||||
|
||||
Run the Bor server.
|
||||
` + c.Flags().Help()
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *Command) Synopsis() string {
|
||||
return "Run the Bor server"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *Command) Run(args []string) int {
|
||||
flags := c.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
// read config file
|
||||
config := DefaultConfig()
|
||||
for _, configFile := range c.configFile {
|
||||
cfg, err := readConfigFile(configFile)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
if err := config.Merge(cfg); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
}
|
||||
if err := config.Merge(c.cliConfig); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
c.config = config
|
||||
|
||||
srv, err := NewServer(config)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
c.srv = srv
|
||||
|
||||
return c.handleSignals()
|
||||
}
|
||||
|
||||
func (c *Command) handleSignals() int {
|
||||
signalCh := make(chan os.Signal, 4)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
|
||||
|
||||
sig := <-signalCh
|
||||
|
||||
c.UI.Output(fmt.Sprintf("Caught signal: %v", sig))
|
||||
c.UI.Output("Gracefully shutting down agent...")
|
||||
|
||||
gracefulCh := make(chan struct{})
|
||||
go func() {
|
||||
c.srv.Stop()
|
||||
close(gracefulCh)
|
||||
}()
|
||||
|
||||
for i := 10; i > 0; i-- {
|
||||
select {
|
||||
case <-signalCh:
|
||||
log.Warn("Already shutting down, interrupt more force stop.", "times", i-1)
|
||||
case <-gracefulCh:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
899
command/server/config.go
Normal file
899
command/server/config.go
Normal file
|
|
@ -0,0 +1,899 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
godebug "runtime/debug"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/server/chains"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/fdlimit"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/hashicorp/hcl/v2/hclsimple"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
gopsutil "github.com/shirou/gopsutil/mem"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
chain *chains.Chain
|
||||
|
||||
// Chain is the chain to sync with
|
||||
Chain string `hcl:"chain,optional"`
|
||||
|
||||
// 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"`
|
||||
|
||||
// LogLevel is the level of the logs to put out
|
||||
LogLevel string `hcl:"log-level,optional"`
|
||||
|
||||
// DataDir is the directory to store the state in
|
||||
DataDir string `hcl:"data-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"`
|
||||
|
||||
// Ethstats is the address of the ethstats server to send telemetry
|
||||
Ethstats string `hcl:"ethstats,optional"`
|
||||
|
||||
// P2P has the p2p network related settings
|
||||
P2P *P2PConfig `hcl:"p2p,block"`
|
||||
|
||||
// Heimdall has the heimdall connection related settings
|
||||
Heimdall *HeimdallConfig `hcl:"heimdall,block"`
|
||||
|
||||
// TxPool has the transaction pool related settings
|
||||
TxPool *TxPoolConfig `hcl:"txpool,block"`
|
||||
|
||||
// Sealer has the validator related settings
|
||||
Sealer *SealerConfig `hcl:"sealer,block"`
|
||||
|
||||
// JsonRPC has the json-rpc related settings
|
||||
JsonRPC *JsonRPCConfig `hcl:"jsonrpc,block"`
|
||||
|
||||
// Gpo has the gas price oracle related settings
|
||||
Gpo *GpoConfig `hcl:"gpo,block"`
|
||||
|
||||
// Telemetry has the telemetry related settings
|
||||
Telemetry *TelemetryConfig `hcl:"telemetry,block"`
|
||||
|
||||
// Cache has the cache related settings
|
||||
Cache *CacheConfig `hcl:"cache,block"`
|
||||
|
||||
// Account has the validator account related settings
|
||||
Accounts *AccountsConfig `hcl:"accounts,block"`
|
||||
|
||||
// GRPC has the grpc server related settings
|
||||
GRPC *GRPCConfig
|
||||
}
|
||||
|
||||
type P2PConfig struct {
|
||||
// MaxPeers sets the maximum number of connected peers
|
||||
MaxPeers uint64 `hcl:"max-peers,optional"`
|
||||
|
||||
// MaxPendPeers sets the maximum number of pending connected peers
|
||||
MaxPendPeers uint64 `hcl:"max-pend-peers,optional"`
|
||||
|
||||
// Bind is the bind address
|
||||
Bind string `hcl:"bind,optional"`
|
||||
|
||||
// Port is the port number
|
||||
Port uint64 `hcl:"port,optional"`
|
||||
|
||||
// NoDiscover is used to disable discovery
|
||||
NoDiscover bool `hcl:"no-discover,optional"`
|
||||
|
||||
// NAT it used to set NAT options
|
||||
NAT string `hcl:"nat,optional"`
|
||||
|
||||
// Discovery has the p2p discovery related settings
|
||||
Discovery *P2PDiscovery `hcl:"discovery,block"`
|
||||
}
|
||||
|
||||
type P2PDiscovery struct {
|
||||
// V5Enabled is used to enable disc v5 discovery mode
|
||||
V5Enabled bool `hcl:"v5-enabled,optional"`
|
||||
|
||||
// Bootnodes is the list of initial bootnodes
|
||||
Bootnodes []string `hcl:"bootnodes,optional"`
|
||||
|
||||
// BootnodesV4 is the list of initial v4 bootnodes
|
||||
BootnodesV4 []string `hcl:"bootnodesv4,optional"`
|
||||
|
||||
// BootnodesV5 is the list of initial v5 bootnodes
|
||||
BootnodesV5 []string `hcl:"bootnodesv5,optional"`
|
||||
|
||||
// StaticNodes is the list of static nodes
|
||||
StaticNodes []string `hcl:"static-nodes,optional"`
|
||||
|
||||
// TrustedNodes is the list of trusted nodes
|
||||
TrustedNodes []string `hcl:"trusted-nodes,optional"`
|
||||
|
||||
// DNS is the list of enrtree:// URLs which will be queried for nodes to connect to
|
||||
DNS []string `hcl:"dns,optional"`
|
||||
}
|
||||
|
||||
type HeimdallConfig struct {
|
||||
// URL is the url of the heimdall server
|
||||
URL string `hcl:"url,optional"`
|
||||
|
||||
// Without is used to disable remote heimdall during testing
|
||||
Without bool `hcl:"without,optional"`
|
||||
}
|
||||
|
||||
type TxPoolConfig struct {
|
||||
// Locals are the addresses that should be treated by default as local
|
||||
Locals []string `hcl:"locals,optional"`
|
||||
|
||||
// NoLocals enables whether local transaction handling should be disabled
|
||||
NoLocals bool `hcl:"no-locals,optional"`
|
||||
|
||||
// Journal is the path to store local transactions to survive node restarts
|
||||
Journal string `hcl:"journal,optional"`
|
||||
|
||||
// Rejournal is the time interval to regenerate the local transaction journal
|
||||
Rejournal time.Duration
|
||||
RejournalRaw string `hcl:"rejournal,optional"`
|
||||
|
||||
// PriceLimit is the minimum gas price to enforce for acceptance into the pool
|
||||
PriceLimit uint64 `hcl:"price-limit,optional"`
|
||||
|
||||
// PriceBump is the minimum price bump percentage to replace an already existing transaction (nonce)
|
||||
PriceBump uint64 `hcl:"price-bump,optional"`
|
||||
|
||||
// AccountSlots is the number of executable transaction slots guaranteed per account
|
||||
AccountSlots uint64 `hcl:"account-slots,optional"`
|
||||
|
||||
// GlobalSlots is the maximum number of executable transaction slots for all accounts
|
||||
GlobalSlots uint64 `hcl:"global-slots,optional"`
|
||||
|
||||
// AccountQueue is the maximum number of non-executable transaction slots permitted per account
|
||||
AccountQueue uint64 `hcl:"account-queue,optional"`
|
||||
|
||||
// GlobalQueueis the maximum number of non-executable transaction slots for all accounts
|
||||
GlobalQueue uint64 `hcl:"global-queue,optional"`
|
||||
|
||||
// Lifetime is the maximum amount of time non-executable transaction are queued
|
||||
LifeTime time.Duration
|
||||
LifeTimeRaw string `hcl:"lifetime,optional"`
|
||||
}
|
||||
|
||||
type SealerConfig struct {
|
||||
// Enabled is used to enable validator mode
|
||||
Enabled bool `hcl:"enabled,optional"`
|
||||
|
||||
// Etherbase is the address of the validator
|
||||
Etherbase string `hcl:"etherbase,optional"`
|
||||
|
||||
// ExtraData is the block extra data set by the miner
|
||||
ExtraData string `hcl:"extra-data,optional"`
|
||||
|
||||
// GasCeil is the target gas ceiling for mined blocks.
|
||||
GasCeil uint64 `hcl:"gas-ceil,optional"`
|
||||
|
||||
// GasPrice is the minimum gas price for mining a transaction
|
||||
GasPrice *big.Int
|
||||
GasPriceRaw string `hcl:"gas-price,optional"`
|
||||
}
|
||||
|
||||
type JsonRPCConfig struct {
|
||||
// IPCDisable enables whether ipc is enabled or not
|
||||
IPCDisable bool `hcl:"ipc-disable,optional"`
|
||||
|
||||
// IPCPath is the path of the ipc endpoint
|
||||
IPCPath string `hcl:"ipc-path,optional"`
|
||||
|
||||
// Modules is the list of enabled api modules
|
||||
Modules []string `hcl:"modules,optional"`
|
||||
|
||||
// VHost is the list of valid virtual hosts
|
||||
VHost []string `hcl:"vhost,optional"`
|
||||
|
||||
// Cors is the list of Cors endpoints
|
||||
Cors []string `hcl:"cors,optional"`
|
||||
|
||||
// GasCap is the global gas cap for eth-call variants.
|
||||
GasCap uint64 `hcl:"gas-cap,optional"`
|
||||
|
||||
// TxFeeCap is the global transaction fee cap for send-transaction variants
|
||||
TxFeeCap float64 `hcl:"tx-fee-cap,optional"`
|
||||
|
||||
// Http has the json-rpc http related settings
|
||||
Http *APIConfig `hcl:"http,block"`
|
||||
|
||||
// Http has the json-rpc websocket related settings
|
||||
Ws *APIConfig `hcl:"ws,block"`
|
||||
|
||||
// Http has the json-rpc graphql related settings
|
||||
Graphql *APIConfig `hcl:"graphql,block"`
|
||||
}
|
||||
|
||||
type GRPCConfig struct {
|
||||
// Addr is the bind address for the grpc rpc server
|
||||
Addr string
|
||||
}
|
||||
|
||||
type APIConfig struct {
|
||||
// Enabled selects whether the api is enabled
|
||||
Enabled bool `hcl:"enabled,optional"`
|
||||
|
||||
// Port is the port number for this api
|
||||
Port uint64 `hcl:"port,optional"`
|
||||
|
||||
// Prefix is the http prefix to expose this api
|
||||
Prefix string `hcl:"prefix,optional"`
|
||||
|
||||
// Host is the address to bind the api
|
||||
Host string `hcl:"host,optional"`
|
||||
}
|
||||
|
||||
type GpoConfig struct {
|
||||
// Blocks is the number of blocks to track to compute the price oracle
|
||||
Blocks uint64 `hcl:"blocks,optional"`
|
||||
|
||||
// Percentile sets the weights to new blocks
|
||||
Percentile uint64 `hcl:"percentile,optional"`
|
||||
|
||||
// MaxPrice is an upper bound gas price
|
||||
MaxPrice *big.Int
|
||||
MaxPriceRaw string `hcl:"max-price,optional"`
|
||||
|
||||
// IgnorePrice is a lower bound gas price
|
||||
IgnorePrice *big.Int
|
||||
IgnorePriceRaw string `hcl:"ignore-price,optional"`
|
||||
}
|
||||
|
||||
type TelemetryConfig struct {
|
||||
// Enabled enables metrics
|
||||
Enabled bool `hcl:"enabled,optional"`
|
||||
|
||||
// Expensive enables expensive metrics
|
||||
Expensive bool `hcl:"expensive,optional"`
|
||||
|
||||
// InfluxDB has the influxdb related settings
|
||||
InfluxDB *InfluxDBConfig `hcl:"influx,block"`
|
||||
|
||||
// Prometheus Address
|
||||
PrometheusAddr string `hcl:"prometheus-addr,optional"`
|
||||
|
||||
// Open collector endpoint
|
||||
OpenCollectorEndpoint string `hcl:"opencollector-endpoint,optional"`
|
||||
}
|
||||
|
||||
type InfluxDBConfig struct {
|
||||
// V1Enabled enables influx v1 mode
|
||||
V1Enabled bool `hcl:"v1-enabled,optional"`
|
||||
|
||||
// Endpoint is the url endpoint of the influxdb service
|
||||
Endpoint string `hcl:"endpoint,optional"`
|
||||
|
||||
// Database is the name of the database in Influxdb to store the metrics.
|
||||
Database string `hcl:"database,optional"`
|
||||
|
||||
// Enabled is the username to authorize access to Influxdb
|
||||
Username string `hcl:"username,optional"`
|
||||
|
||||
// Password is the password to authorize access to Influxdb
|
||||
Password string `hcl:"password,optional"`
|
||||
|
||||
// Tags are tags attaches to all generated metrics
|
||||
Tags map[string]string `hcl:"tags,optional"`
|
||||
|
||||
// Enabled enables influx v2 mode
|
||||
V2Enabled bool `hcl:"v2-enabled,optional"`
|
||||
|
||||
// Token is the token to authorize access to Influxdb V2.
|
||||
Token string `hcl:"token,optional"`
|
||||
|
||||
// Bucket is the bucket to store metrics in Influxdb V2.
|
||||
Bucket string `hcl:"bucket,optional"`
|
||||
|
||||
// Organization is the name of the organization for Influxdb V2.
|
||||
Organization string `hcl:"organization,optional"`
|
||||
}
|
||||
|
||||
type CacheConfig struct {
|
||||
// Cache is the amount of cache of the node
|
||||
Cache uint64 `hcl:"cache,optional"`
|
||||
|
||||
// PercGc is percentage of cache used for garbage collection
|
||||
PercGc uint64 `hcl:"perc-gc,optional"`
|
||||
|
||||
// PercSnapshot is percentage of cache used for snapshots
|
||||
PercSnapshot uint64 `hcl:"perc-snapshot,optional"`
|
||||
|
||||
// PercDatabase is percentage of cache used for the database
|
||||
PercDatabase uint64 `hcl:"perc-database,optional"`
|
||||
|
||||
// PercTrie is percentage of cache used for the trie
|
||||
PercTrie uint64 `hcl:"perc-trie,optional"`
|
||||
|
||||
// Journal is the disk journal directory for trie cache to survive node restarts
|
||||
Journal string `hcl:"journal,optional"`
|
||||
|
||||
// Rejournal is the time interval to regenerate the journal for clean cache
|
||||
Rejournal time.Duration
|
||||
RejournalRaw string `hcl:"rejournal,optional"`
|
||||
|
||||
// NoPrefetch is used to disable prefetch of tries
|
||||
NoPrefetch bool `hcl:"no-prefetch,optional"`
|
||||
|
||||
// Preimages is used to enable the track of hash preimages
|
||||
Preimages bool `hcl:"preimages,optional"`
|
||||
|
||||
// TxLookupLimit sets the maximum number of blocks from head whose tx indices are reserved.
|
||||
TxLookupLimit uint64 `hcl:"tx-lookup-limit,optional"`
|
||||
}
|
||||
|
||||
type AccountsConfig struct {
|
||||
// Unlock is the list of addresses to unlock in the node
|
||||
Unlock []string `hcl:"unlock,optional"`
|
||||
|
||||
// PasswordFile is the file where the account passwords are stored
|
||||
PasswordFile string `hcl:"password-file,optional"`
|
||||
|
||||
// AllowInsecureUnlock allows user to unlock accounts in unsafe http environment.
|
||||
AllowInsecureUnlock bool `hcl:"allow-insecure-unlock,optional"`
|
||||
|
||||
// UseLightweightKDF enables a faster but less secure encryption of accounts
|
||||
UseLightweightKDF bool `hcl:"use-lightweight-kdf,optional"`
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Chain: "mainnet",
|
||||
Name: Hostname(),
|
||||
Whitelist: map[string]string{},
|
||||
LogLevel: "INFO",
|
||||
DataDir: defaultDataDir(),
|
||||
P2P: &P2PConfig{
|
||||
MaxPeers: 30,
|
||||
MaxPendPeers: 50,
|
||||
Bind: "0.0.0.0",
|
||||
Port: 30303,
|
||||
NoDiscover: false,
|
||||
NAT: "any",
|
||||
Discovery: &P2PDiscovery{
|
||||
V5Enabled: false,
|
||||
Bootnodes: []string{},
|
||||
BootnodesV4: []string{},
|
||||
BootnodesV5: []string{},
|
||||
StaticNodes: []string{},
|
||||
TrustedNodes: []string{},
|
||||
DNS: []string{},
|
||||
},
|
||||
},
|
||||
Heimdall: &HeimdallConfig{
|
||||
URL: "http://localhost:1317",
|
||||
Without: false,
|
||||
},
|
||||
SyncMode: "fast",
|
||||
GcMode: "full",
|
||||
Snapshot: true,
|
||||
TxPool: &TxPoolConfig{
|
||||
Locals: []string{},
|
||||
NoLocals: false,
|
||||
Journal: "",
|
||||
Rejournal: time.Duration(1 * time.Hour),
|
||||
PriceLimit: 1,
|
||||
PriceBump: 10,
|
||||
AccountSlots: 16,
|
||||
GlobalSlots: 4096,
|
||||
AccountQueue: 64,
|
||||
GlobalQueue: 1024,
|
||||
LifeTime: time.Duration(3 * time.Hour),
|
||||
},
|
||||
Sealer: &SealerConfig{
|
||||
Enabled: false,
|
||||
Etherbase: "",
|
||||
GasCeil: 8000000,
|
||||
GasPrice: big.NewInt(params.GWei),
|
||||
ExtraData: "",
|
||||
},
|
||||
Gpo: &GpoConfig{
|
||||
Blocks: 20,
|
||||
Percentile: 60,
|
||||
MaxPrice: gasprice.DefaultMaxPrice,
|
||||
IgnorePrice: gasprice.DefaultIgnorePrice,
|
||||
},
|
||||
JsonRPC: &JsonRPCConfig{
|
||||
IPCDisable: false,
|
||||
IPCPath: "",
|
||||
Modules: []string{"web3", "net"},
|
||||
Cors: []string{"*"},
|
||||
VHost: []string{"*"},
|
||||
GasCap: ethconfig.Defaults.RPCGasCap,
|
||||
TxFeeCap: ethconfig.Defaults.RPCTxFeeCap,
|
||||
Http: &APIConfig{
|
||||
Enabled: false,
|
||||
Port: 8545,
|
||||
Prefix: "",
|
||||
Host: "localhost",
|
||||
},
|
||||
Ws: &APIConfig{
|
||||
Enabled: false,
|
||||
Port: 8546,
|
||||
Prefix: "",
|
||||
Host: "localhost",
|
||||
},
|
||||
Graphql: &APIConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
Ethstats: "",
|
||||
Telemetry: &TelemetryConfig{
|
||||
Enabled: false,
|
||||
Expensive: false,
|
||||
PrometheusAddr: "",
|
||||
OpenCollectorEndpoint: "",
|
||||
InfluxDB: &InfluxDBConfig{
|
||||
V1Enabled: false,
|
||||
Endpoint: "",
|
||||
Database: "",
|
||||
Username: "",
|
||||
Password: "",
|
||||
Tags: map[string]string{},
|
||||
V2Enabled: false,
|
||||
Token: "",
|
||||
Bucket: "",
|
||||
Organization: "",
|
||||
},
|
||||
},
|
||||
Cache: &CacheConfig{
|
||||
Cache: 1024,
|
||||
PercDatabase: 50,
|
||||
PercTrie: 15,
|
||||
PercGc: 25,
|
||||
PercSnapshot: 10,
|
||||
Journal: "triecache",
|
||||
Rejournal: 60 * time.Minute,
|
||||
NoPrefetch: false,
|
||||
Preimages: false,
|
||||
TxLookupLimit: 2350000,
|
||||
},
|
||||
Accounts: &AccountsConfig{
|
||||
Unlock: []string{},
|
||||
PasswordFile: "",
|
||||
AllowInsecureUnlock: false,
|
||||
UseLightweightKDF: false,
|
||||
},
|
||||
GRPC: &GRPCConfig{
|
||||
Addr: ":3131",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) fillBigInt() error {
|
||||
tds := []struct {
|
||||
path string
|
||||
td **big.Int
|
||||
str *string
|
||||
}{
|
||||
{"gpo.maxprice", &c.Gpo.MaxPrice, &c.Gpo.MaxPriceRaw},
|
||||
{"gpo.ignoreprice", &c.Gpo.IgnorePrice, &c.Gpo.IgnorePriceRaw},
|
||||
{"sealer.gasprice", &c.Sealer.GasPrice, &c.Sealer.GasPriceRaw},
|
||||
}
|
||||
|
||||
for _, x := range tds {
|
||||
if *x.str != "" {
|
||||
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
|
||||
}
|
||||
|
||||
func (c *Config) fillTimeDurations() error {
|
||||
tds := []struct {
|
||||
path string
|
||||
td *time.Duration
|
||||
str *string
|
||||
}{
|
||||
{"txpool.lifetime", &c.TxPool.LifeTime, &c.TxPool.LifeTimeRaw},
|
||||
{"txpool.rejournal", &c.TxPool.Rejournal, &c.TxPool.RejournalRaw},
|
||||
{"cache.rejournal", &c.Cache.Rejournal, &c.Cache.RejournalRaw},
|
||||
}
|
||||
|
||||
for _, x := range tds {
|
||||
if x.td != nil && x.str != nil && *x.str != "" {
|
||||
d, err := time.ParseDuration(*x.str)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s can't parse time duration %s", x.path, *x.str)
|
||||
}
|
||||
*x.str = ""
|
||||
*x.td = d
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readConfigFile(path string) (*Config, error) {
|
||||
ext := filepath.Ext(path)
|
||||
if ext == ".toml" {
|
||||
// read file and apply the legacy config
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return readLegacyConfig(data)
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
TxPool: &TxPoolConfig{},
|
||||
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 {
|
||||
chain, ok := chains.GetChain(c.Chain)
|
||||
if !ok {
|
||||
return fmt.Errorf("chain '%s' not found", c.Chain)
|
||||
}
|
||||
c.chain = chain
|
||||
|
||||
// preload some default values that depend on the chain file
|
||||
if c.P2P.Discovery.DNS == nil {
|
||||
c.P2P.Discovery.DNS = c.chain.DNS
|
||||
}
|
||||
|
||||
// depending on the chain we have different cache values
|
||||
if c.Chain != "mainnet" {
|
||||
c.Cache.Cache = 4096
|
||||
} else {
|
||||
c.Cache.Cache = 1024
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) buildEth() (*ethconfig.Config, error) {
|
||||
dbHandles, err := makeDatabaseHandles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n := ethconfig.Defaults
|
||||
n.NetworkId = c.chain.NetworkId
|
||||
n.Genesis = c.chain.Genesis
|
||||
n.HeimdallURL = c.Heimdall.URL
|
||||
n.WithoutHeimdall = c.Heimdall.Without
|
||||
|
||||
// gas price oracle
|
||||
{
|
||||
n.GPO.Blocks = int(c.Gpo.Blocks)
|
||||
n.GPO.Percentile = int(c.Gpo.Percentile)
|
||||
n.GPO.MaxPrice = c.Gpo.MaxPrice
|
||||
n.GPO.IgnorePrice = c.Gpo.IgnorePrice
|
||||
}
|
||||
|
||||
// txpool options
|
||||
{
|
||||
n.TxPool.NoLocals = c.TxPool.NoLocals
|
||||
n.TxPool.Journal = c.TxPool.Journal
|
||||
n.TxPool.Rejournal = c.TxPool.Rejournal
|
||||
n.TxPool.PriceLimit = c.TxPool.PriceLimit
|
||||
n.TxPool.PriceBump = c.TxPool.PriceBump
|
||||
n.TxPool.AccountSlots = c.TxPool.AccountSlots
|
||||
n.TxPool.GlobalSlots = c.TxPool.GlobalSlots
|
||||
n.TxPool.AccountQueue = c.TxPool.AccountQueue
|
||||
n.TxPool.GlobalQueue = c.TxPool.GlobalQueue
|
||||
n.TxPool.Lifetime = c.TxPool.LifeTime
|
||||
}
|
||||
|
||||
// miner options
|
||||
{
|
||||
n.Miner.GasPrice = c.Sealer.GasPrice
|
||||
n.Miner.GasCeil = c.Sealer.GasCeil
|
||||
n.Miner.ExtraData = []byte(c.Sealer.ExtraData)
|
||||
|
||||
if etherbase := c.Sealer.Etherbase; etherbase != "" {
|
||||
if !common.IsHexAddress(etherbase) {
|
||||
return nil, fmt.Errorf("etherbase is not an address: %s", etherbase)
|
||||
}
|
||||
n.Miner.Etherbase = common.HexToAddress(etherbase)
|
||||
}
|
||||
}
|
||||
|
||||
// discovery (this params should be in node.Config)
|
||||
{
|
||||
n.EthDiscoveryURLs = c.P2P.Discovery.DNS
|
||||
n.SnapDiscoveryURLs = c.P2P.Discovery.DNS
|
||||
}
|
||||
|
||||
// whitelist
|
||||
{
|
||||
n.Whitelist = map[uint64]common.Hash{}
|
||||
for k, v := range c.Whitelist {
|
||||
number, err := strconv.ParseUint(k, 0, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid whitelist 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)
|
||||
}
|
||||
n.Whitelist[number] = hash
|
||||
}
|
||||
}
|
||||
|
||||
// cache
|
||||
{
|
||||
cache := c.Cache.Cache
|
||||
calcPerc := func(val uint64) int {
|
||||
return int(cache * (val) / 100)
|
||||
}
|
||||
|
||||
// Cap the cache allowance
|
||||
mem, err := gopsutil.VirtualMemory()
|
||||
if err == nil {
|
||||
if 32<<(^uintptr(0)>>63) == 32 && mem.Total > 2*1024*1024*1024 {
|
||||
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)
|
||||
cache = allowance
|
||||
}
|
||||
}
|
||||
// Tune the garbage collector
|
||||
gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))
|
||||
|
||||
log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
|
||||
godebug.SetGCPercent(int(gogc))
|
||||
|
||||
n.TrieCleanCacheJournal = c.Cache.Journal
|
||||
n.TrieCleanCacheRejournal = c.Cache.Rejournal
|
||||
n.DatabaseCache = calcPerc(c.Cache.PercDatabase)
|
||||
n.SnapshotCache = calcPerc(c.Cache.PercSnapshot)
|
||||
n.TrieCleanCache = calcPerc(c.Cache.PercTrie)
|
||||
n.TrieDirtyCache = calcPerc(c.Cache.PercGc)
|
||||
n.NoPrefetch = c.Cache.NoPrefetch
|
||||
n.Preimages = c.Cache.Preimages
|
||||
n.TxLookupLimit = c.Cache.TxLookupLimit
|
||||
}
|
||||
|
||||
n.RPCGasCap = c.JsonRPC.GasCap
|
||||
if n.RPCGasCap != 0 {
|
||||
log.Info("Set global gas cap", "cap", n.RPCGasCap)
|
||||
} else {
|
||||
log.Info("Global gas cap disabled")
|
||||
}
|
||||
n.RPCTxFeeCap = c.JsonRPC.TxFeeCap
|
||||
|
||||
// sync mode. It can either be "fast", "full" or "snap". We disable
|
||||
// for now the "light" mode.
|
||||
switch c.SyncMode {
|
||||
case "fast":
|
||||
n.SyncMode = downloader.FastSync
|
||||
case "full":
|
||||
n.SyncMode = downloader.FullSync
|
||||
case "snap":
|
||||
n.SyncMode = downloader.SnapSync
|
||||
default:
|
||||
return nil, fmt.Errorf("sync mode '%s' not found", c.SyncMode)
|
||||
}
|
||||
|
||||
// archive mode. It can either be "archive" or "full".
|
||||
switch c.GcMode {
|
||||
case "full":
|
||||
n.NoPruning = false
|
||||
case "archive":
|
||||
n.NoPruning = true
|
||||
if !n.Preimages {
|
||||
n.Preimages = true
|
||||
log.Info("Enabling recording of key preimages since archive mode is used")
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("gcmode '%s' not found", c.GcMode)
|
||||
}
|
||||
|
||||
// snapshot disable check
|
||||
if c.Snapshot {
|
||||
if n.SyncMode == downloader.SnapSync {
|
||||
log.Info("Snap sync requested, enabling --snapshot")
|
||||
} else {
|
||||
// disable snapshot
|
||||
n.TrieCleanCache += n.SnapshotCache
|
||||
n.SnapshotCache = 0
|
||||
}
|
||||
}
|
||||
|
||||
n.DatabaseHandles = dbHandles
|
||||
return &n, nil
|
||||
}
|
||||
|
||||
var (
|
||||
clientIdentifier = "bor"
|
||||
gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags)
|
||||
gitDate = "" // Git commit date YYYYMMDD of the release (set via linker flags)
|
||||
)
|
||||
|
||||
func (c *Config) buildNode() (*node.Config, error) {
|
||||
ipcPath := ""
|
||||
if !c.JsonRPC.IPCDisable {
|
||||
ipcPath = clientIdentifier + ".ipc"
|
||||
if c.JsonRPC.IPCPath != "" {
|
||||
ipcPath = c.JsonRPC.IPCPath
|
||||
}
|
||||
}
|
||||
|
||||
cfg := &node.Config{
|
||||
Name: clientIdentifier,
|
||||
DataDir: c.DataDir,
|
||||
UseLightweightKDF: c.Accounts.UseLightweightKDF,
|
||||
InsecureUnlockAllowed: c.Accounts.AllowInsecureUnlock,
|
||||
Version: params.VersionWithCommit(gitCommit, gitDate),
|
||||
IPCPath: ipcPath,
|
||||
P2P: p2p.Config{
|
||||
MaxPeers: int(c.P2P.MaxPeers),
|
||||
MaxPendingPeers: int(c.P2P.MaxPendPeers),
|
||||
ListenAddr: c.P2P.Bind + ":" + strconv.Itoa(int(c.P2P.Port)),
|
||||
DiscoveryV5: c.P2P.Discovery.V5Enabled,
|
||||
},
|
||||
HTTPModules: c.JsonRPC.Modules,
|
||||
HTTPCors: c.JsonRPC.Cors,
|
||||
HTTPVirtualHosts: c.JsonRPC.VHost,
|
||||
HTTPPathPrefix: c.JsonRPC.Http.Prefix,
|
||||
WSModules: c.JsonRPC.Modules,
|
||||
WSOrigins: c.JsonRPC.Cors,
|
||||
WSPathPrefix: c.JsonRPC.Ws.Prefix,
|
||||
GraphQLCors: c.JsonRPC.Cors,
|
||||
GraphQLVirtualHosts: c.JsonRPC.VHost,
|
||||
}
|
||||
|
||||
// enable jsonrpc endpoints
|
||||
{
|
||||
if c.JsonRPC.Http.Enabled {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
natif, err := nat.Parse(c.P2P.NAT)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wrong 'nat' flag: %v", err)
|
||||
}
|
||||
cfg.P2P.NAT = natif
|
||||
|
||||
// Discovery
|
||||
// if no bootnodes are defined, use the ones from the chain file.
|
||||
bootnodes := c.P2P.Discovery.Bootnodes
|
||||
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 cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.P2P.NoDiscover {
|
||||
// Disable networking, for now, we will not even allow incomming connections
|
||||
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 {
|
||||
return fmt.Errorf("failed to merge configurations: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeDatabaseHandles() (int, error) {
|
||||
limit, err := fdlimit.Maximum()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
raised, err := fdlimit.Raise(uint64(limit))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return int(raised / 2), nil
|
||||
}
|
||||
|
||||
func parseBootnodes(urls []string) ([]*enode.Node, error) {
|
||||
dst := []*enode.Node{}
|
||||
for _, url := range urls {
|
||||
if url != "" {
|
||||
node, err := enode.Parse(enode.ValidSchemes, url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid bootstrap url '%s': %v", url, err)
|
||||
}
|
||||
dst = append(dst, node)
|
||||
}
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func defaultDataDir() string {
|
||||
// Try to place the data folder in the user's home dir
|
||||
home, _ := homedir.Dir()
|
||||
if home == "" {
|
||||
// we cannot guess a stable location
|
||||
return ""
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
return filepath.Join(home, "Library", "Bor")
|
||||
case "windows":
|
||||
appdata := os.Getenv("LOCALAPPDATA")
|
||||
if appdata == "" {
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
func Hostname() string {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return "bor"
|
||||
}
|
||||
return hostname
|
||||
}
|
||||
33
command/server/config_legacy.go
Normal file
33
command/server/config_legacy.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
type legacyConfig struct {
|
||||
Node struct {
|
||||
P2P struct {
|
||||
StaticNodes []string
|
||||
TrustedNodes []string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *legacyConfig) Config() *Config {
|
||||
c := DefaultConfig()
|
||||
c.P2P.Discovery.StaticNodes = l.Node.P2P.StaticNodes
|
||||
c.P2P.Discovery.TrustedNodes = l.Node.P2P.TrustedNodes
|
||||
return c
|
||||
}
|
||||
|
||||
func readLegacyConfig(data []byte) (*Config, error) {
|
||||
var legacy legacyConfig
|
||||
|
||||
r := toml.NewDecoder(bytes.NewReader(data))
|
||||
if err := r.Decode(&legacy); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return legacy.Config(), nil
|
||||
}
|
||||
21
command/server/config_legacy_test.go
Normal file
21
command/server/config_legacy_test.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfigLegacy(t *testing.T) {
|
||||
toml := `[Node.P2P]
|
||||
StaticNodes = ["node1"]
|
||||
TrustedNodes = ["node2"]`
|
||||
|
||||
config, err := readLegacyConfig([]byte(toml))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, config.P2P.Discovery.StaticNodes, []string{"node1"})
|
||||
assert.Equal(t, config.P2P.Discovery.TrustedNodes, []string{"node2"})
|
||||
}
|
||||
133
command/server/config_test.go
Normal file
133
command/server/config_test.go
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfigDefault(t *testing.T) {
|
||||
// the default config should work out of the box
|
||||
config := DefaultConfig()
|
||||
assert.NoError(t, config.loadChain())
|
||||
|
||||
_, err := config.buildNode()
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = config.buildEth()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestConfigMerge(t *testing.T) {
|
||||
c0 := &Config{
|
||||
Chain: "0",
|
||||
Snapshot: true,
|
||||
Whitelist: map[string]string{
|
||||
"a": "b",
|
||||
},
|
||||
TxPool: &TxPoolConfig{
|
||||
LifeTime: 5 * time.Second,
|
||||
},
|
||||
P2P: &P2PConfig{
|
||||
Discovery: &P2PDiscovery{
|
||||
StaticNodes: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
c1 := &Config{
|
||||
Chain: "1",
|
||||
Whitelist: map[string]string{
|
||||
"b": "c",
|
||||
},
|
||||
P2P: &P2PConfig{
|
||||
MaxPeers: 10,
|
||||
Discovery: &P2PDiscovery{
|
||||
StaticNodes: []string{
|
||||
"b",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
expected := &Config{
|
||||
Chain: "1",
|
||||
Snapshot: true,
|
||||
Whitelist: map[string]string{
|
||||
"a": "b",
|
||||
"b": "c",
|
||||
},
|
||||
TxPool: &TxPoolConfig{
|
||||
LifeTime: 5 * time.Second,
|
||||
},
|
||||
P2P: &P2PConfig{
|
||||
MaxPeers: 10,
|
||||
Discovery: &P2PDiscovery{
|
||||
StaticNodes: []string{
|
||||
"a",
|
||||
"b",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.NoError(t, c0.Merge(c1))
|
||||
assert.Equal(t, c0, expected)
|
||||
}
|
||||
|
||||
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{
|
||||
"a": "b",
|
||||
},
|
||||
P2P: &P2PConfig{
|
||||
MaxPeers: 30,
|
||||
},
|
||||
TxPool: &TxPoolConfig{
|
||||
LifeTime: time.Duration(1 * time.Second),
|
||||
},
|
||||
Gpo: &GpoConfig{
|
||||
MaxPrice: big.NewInt(100),
|
||||
},
|
||||
Sealer: &SealerConfig{},
|
||||
Cache: &CacheConfig{},
|
||||
})
|
||||
}
|
||||
|
||||
// read file in hcl format
|
||||
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")
|
||||
})
|
||||
}
|
||||
|
||||
var dummyEnodeAddr = "enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303"
|
||||
|
||||
func TestConfigBootnodesDefault(t *testing.T) {
|
||||
t.Run("EmptyBootnodes", func(t *testing.T) {
|
||||
// if no bootnodes are specific, we use the ones from the genesis chain
|
||||
config := DefaultConfig()
|
||||
assert.NoError(t, config.loadChain())
|
||||
|
||||
cfg, err := config.buildNode()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, cfg.P2P.BootstrapNodes)
|
||||
})
|
||||
t.Run("NotEmptyBootnodes", func(t *testing.T) {
|
||||
// if bootnodes specific, DO NOT load the genesis bootnodes
|
||||
config := DefaultConfig()
|
||||
config.P2P.Discovery.Bootnodes = []string{dummyEnodeAddr}
|
||||
|
||||
cfg, err := config.buildNode()
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, cfg.P2P.BootstrapNodes, 1)
|
||||
})
|
||||
}
|
||||
465
command/server/flags.go
Normal file
465
command/server/flags.go
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/command/flagset"
|
||||
)
|
||||
|
||||
func (c *Command) Flags() *flagset.Flagset {
|
||||
c.cliConfig = DefaultConfig()
|
||||
|
||||
f := flagset.NewFlagSet("server")
|
||||
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "chain",
|
||||
Usage: "Name of the chain to sync",
|
||||
Value: &c.cliConfig.Chain,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "Name/Identity of the node",
|
||||
Value: &c.cliConfig.Name,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "log-level",
|
||||
Usage: "Set log level for the server",
|
||||
Value: &c.cliConfig.LogLevel,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "datadir",
|
||||
Usage: "Path of the data directory to store information",
|
||||
Value: &c.cliConfig.DataDir,
|
||||
})
|
||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||
Name: "config",
|
||||
Usage: "File for the config file",
|
||||
Value: &c.configFile,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "syncmode",
|
||||
Usage: `Blockchain sync mode ("fast", "full", "snap" or "light")`,
|
||||
Value: &c.cliConfig.SyncMode,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "gcmode",
|
||||
Usage: `Blockchain garbage collection mode ("full", "archive")`,
|
||||
Value: &c.cliConfig.GcMode,
|
||||
})
|
||||
f.MapStringFlag(&flagset.MapStringFlag{
|
||||
Name: "whitelist",
|
||||
Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
|
||||
Value: &c.cliConfig.Whitelist,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "snapshot",
|
||||
Usage: `Enables snapshot-database mode (default = enable)`,
|
||||
Value: &c.cliConfig.Snapshot,
|
||||
})
|
||||
|
||||
// heimdall
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "bor.heimdall",
|
||||
Usage: "URL of Heimdall service",
|
||||
Value: &c.cliConfig.Heimdall.URL,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "bor.withoutheimdall",
|
||||
Usage: "Run without Heimdall service (for testing purpose)",
|
||||
Value: &c.cliConfig.Heimdall.Without,
|
||||
})
|
||||
|
||||
// txpool options
|
||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||
Name: "txpool.locals",
|
||||
Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
|
||||
Value: &c.cliConfig.TxPool.Locals,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "txpool.nolocals",
|
||||
Usage: "Disables price exemptions for locally submitted transactions",
|
||||
Value: &c.cliConfig.TxPool.NoLocals,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "txpool.journal",
|
||||
Usage: "Disk journal for local transaction to survive node restarts",
|
||||
Value: &c.cliConfig.TxPool.Journal,
|
||||
})
|
||||
f.DurationFlag(&flagset.DurationFlag{
|
||||
Name: "txpool.rejournal",
|
||||
Usage: "Time interval to regenerate the local transaction journal",
|
||||
Value: &c.cliConfig.TxPool.Rejournal,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "txpool.pricelimit",
|
||||
Usage: "Minimum gas price limit to enforce for acceptance into the pool",
|
||||
Value: &c.cliConfig.TxPool.PriceLimit,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "txpool.pricebump",
|
||||
Usage: "Price bump percentage to replace an already existing transaction",
|
||||
Value: &c.cliConfig.TxPool.PriceBump,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "txpool.accountslots",
|
||||
Usage: "Minimum number of executable transaction slots guaranteed per account",
|
||||
Value: &c.cliConfig.TxPool.AccountSlots,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "txpool.globalslots",
|
||||
Usage: "Maximum number of executable transaction slots for all accounts",
|
||||
Value: &c.cliConfig.TxPool.GlobalSlots,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "txpool.accountqueue",
|
||||
Usage: "Maximum number of non-executable transaction slots permitted per account",
|
||||
Value: &c.cliConfig.TxPool.AccountQueue,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "txpool.globalqueue",
|
||||
Usage: "Maximum number of non-executable transaction slots for all accounts",
|
||||
Value: &c.cliConfig.TxPool.GlobalQueue,
|
||||
})
|
||||
f.DurationFlag(&flagset.DurationFlag{
|
||||
Name: "txpool.lifetime",
|
||||
Usage: "Maximum amount of time non-executable transaction are queued",
|
||||
Value: &c.cliConfig.TxPool.LifeTime,
|
||||
})
|
||||
|
||||
// sealer options
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "mine",
|
||||
Usage: "Enable mining",
|
||||
Value: &c.cliConfig.Sealer.Enabled,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "miner.etherbase",
|
||||
Usage: "Public address for block mining rewards (default = first account)",
|
||||
Value: &c.cliConfig.Sealer.Etherbase,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "miner.extradata",
|
||||
Usage: "Block extra data set by the miner (default = client version)",
|
||||
Value: &c.cliConfig.Sealer.ExtraData,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "miner.gaslimit",
|
||||
Usage: "Target gas ceiling for mined blocks",
|
||||
Value: &c.cliConfig.Sealer.GasCeil,
|
||||
})
|
||||
f.BigIntFlag(&flagset.BigIntFlag{
|
||||
Name: "miner.gasprice",
|
||||
Usage: "Minimum gas price for mining a transaction",
|
||||
Value: c.cliConfig.Sealer.GasPrice,
|
||||
})
|
||||
|
||||
// ethstats
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "ethstats",
|
||||
Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
|
||||
Value: &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,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.BigIntFlag(&flagset.BigIntFlag{
|
||||
Name: "gpo.maxprice",
|
||||
Usage: "Maximum gas price will be recommended by gpo",
|
||||
Value: c.cliConfig.Gpo.MaxPrice,
|
||||
})
|
||||
f.BigIntFlag(&flagset.BigIntFlag{
|
||||
Name: "gpo.ignoreprice",
|
||||
Usage: "Gas price below which gpo will ignore transactions",
|
||||
Value: c.cliConfig.Gpo.IgnorePrice,
|
||||
})
|
||||
|
||||
// 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,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "cache.database",
|
||||
Usage: "Percentage of cache memory allowance to use for database io",
|
||||
Value: &c.cliConfig.Cache.PercDatabase,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "cache.trie.journal",
|
||||
Usage: "Disk journal directory for trie cache to survive node restarts",
|
||||
Value: &c.cliConfig.Cache.Journal,
|
||||
})
|
||||
f.DurationFlag(&flagset.DurationFlag{
|
||||
Name: "cache.trie.rejournal",
|
||||
Usage: "Time interval to regenerate the trie cache journal",
|
||||
Value: &c.cliConfig.Cache.Rejournal,
|
||||
})
|
||||
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,
|
||||
})
|
||||
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,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "cache.preimages",
|
||||
Usage: "Enable recording the SHA3/keccak preimages of trie keys",
|
||||
Value: &c.cliConfig.Cache.Preimages,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "txlookuplimit",
|
||||
Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)",
|
||||
Value: &c.cliConfig.Cache.TxLookupLimit,
|
||||
})
|
||||
|
||||
// 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,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "ipcdisable",
|
||||
Usage: "Disable the IPC-RPC server",
|
||||
Value: &c.cliConfig.JsonRPC.IPCDisable,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "ipcpath",
|
||||
Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
|
||||
Value: &c.cliConfig.JsonRPC.IPCPath,
|
||||
})
|
||||
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,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||
Name: "jsonrpc.modules",
|
||||
Usage: "API's offered over the HTTP-RPC interface",
|
||||
Value: &c.cliConfig.JsonRPC.Modules,
|
||||
})
|
||||
|
||||
// http options
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "http",
|
||||
Usage: "Enable the HTTP-RPC server",
|
||||
Value: &c.cliConfig.JsonRPC.Http.Enabled,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "http.addr",
|
||||
Usage: "HTTP-RPC server listening interface",
|
||||
Value: &c.cliConfig.JsonRPC.Http.Host,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "http.port",
|
||||
Usage: "HTTP-RPC server listening port",
|
||||
Value: &c.cliConfig.JsonRPC.Http.Port,
|
||||
})
|
||||
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,
|
||||
})
|
||||
// ws options
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "ws",
|
||||
Usage: "Enable the WS-RPC server",
|
||||
Value: &c.cliConfig.JsonRPC.Ws.Enabled,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "ws.addr",
|
||||
Usage: "WS-RPC server listening interface",
|
||||
Value: &c.cliConfig.JsonRPC.Ws.Host,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "ws.port",
|
||||
Usage: "WS-RPC server listening port",
|
||||
Value: &c.cliConfig.JsonRPC.Ws.Port,
|
||||
})
|
||||
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,
|
||||
})
|
||||
// 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,
|
||||
})
|
||||
|
||||
// p2p options
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "bind",
|
||||
Usage: "Network binding address",
|
||||
Value: &c.cliConfig.P2P.Bind,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "port",
|
||||
Usage: "Network listening port",
|
||||
Value: &c.cliConfig.P2P.Port,
|
||||
})
|
||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||
Name: "bootnodes",
|
||||
Usage: "Comma separated enode URLs for P2P discovery bootstrap",
|
||||
Value: &c.cliConfig.P2P.Discovery.Bootnodes,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "maxpeers",
|
||||
Usage: "Maximum number of network peers (network disabled if set to 0)",
|
||||
Value: &c.cliConfig.P2P.MaxPeers,
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "maxpendpeers",
|
||||
Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
|
||||
Value: &c.cliConfig.P2P.MaxPendPeers,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "nat",
|
||||
Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
|
||||
Value: &c.cliConfig.P2P.NAT,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "nodiscover",
|
||||
Usage: "Disables the peer discovery mechanism (manual peer addition)",
|
||||
Value: &c.cliConfig.P2P.NoDiscover,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "v5disc",
|
||||
Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
|
||||
Value: &c.cliConfig.P2P.Discovery.V5Enabled,
|
||||
})
|
||||
|
||||
// metrics
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "metrics",
|
||||
Usage: "Enable metrics collection and reporting",
|
||||
Value: &c.cliConfig.Telemetry.Enabled,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "metrics.expensive",
|
||||
Usage: "Enable expensive metrics collection and reporting",
|
||||
Value: &c.cliConfig.Telemetry.Expensive,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "metrics.influxdb",
|
||||
Usage: "Enable metrics export/push to an external InfluxDB database (v1)",
|
||||
Value: &c.cliConfig.Telemetry.InfluxDB.V1Enabled,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.influxdb.endpoint",
|
||||
Usage: "InfluxDB API endpoint to report metrics to",
|
||||
Value: &c.cliConfig.Telemetry.InfluxDB.Endpoint,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.influxdb.database",
|
||||
Usage: "InfluxDB database name to push reported metrics to",
|
||||
Value: &c.cliConfig.Telemetry.InfluxDB.Database,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.influxdb.username",
|
||||
Usage: "Username to authorize access to the database",
|
||||
Value: &c.cliConfig.Telemetry.InfluxDB.Username,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.influxdb.password",
|
||||
Usage: "Password to authorize access to the database",
|
||||
Value: &c.cliConfig.Telemetry.InfluxDB.Password,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.prometheus-addr",
|
||||
Usage: "Address for Prometheus Server",
|
||||
Value: &c.cliConfig.Telemetry.PrometheusAddr,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.opencollector-endpoint",
|
||||
Usage: "OpenCollector Endpoint (host:port)",
|
||||
Value: &c.cliConfig.Telemetry.OpenCollectorEndpoint,
|
||||
})
|
||||
// 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,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.influxdb.token",
|
||||
Usage: "Token to authorize access to the database (v2 only)",
|
||||
Value: &c.cliConfig.Telemetry.InfluxDB.Token,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "metrics.influxdb.organization",
|
||||
Usage: "InfluxDB organization name (v2 only)",
|
||||
Value: &c.cliConfig.Telemetry.InfluxDB.Organization,
|
||||
})
|
||||
|
||||
// account
|
||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||
Name: "unlock",
|
||||
Usage: "Comma separated list of accounts to unlock",
|
||||
Value: &c.cliConfig.Accounts.Unlock,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "password",
|
||||
Usage: "Password file to use for non-interactive password input",
|
||||
Value: &c.cliConfig.Accounts.PasswordFile,
|
||||
})
|
||||
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,
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "lightkdf",
|
||||
Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
|
||||
Value: &c.cliConfig.Accounts.UseLightweightKDF,
|
||||
})
|
||||
|
||||
// grpc
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "grpc.addr",
|
||||
Usage: "Address and port to bind the GRPC server",
|
||||
Value: &c.cliConfig.GRPC.Addr,
|
||||
})
|
||||
return f
|
||||
}
|
||||
93
command/server/pprof/pprof.go
Normal file
93
command/server/pprof/pprof.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package pprof
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"runtime/trace"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Profile generates a pprof.Profile report for the given profile name.
|
||||
func Profile(profile string, debug, gc int) ([]byte, map[string]string, error) {
|
||||
p := pprof.Lookup(profile)
|
||||
if p == nil {
|
||||
return nil, nil, fmt.Errorf("profile '%s' not found", profile)
|
||||
}
|
||||
|
||||
if profile == "heap" && gc > 0 {
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := p.WriteTo(&buf, debug); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
headers := map[string]string{
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
}
|
||||
if debug != 0 {
|
||||
headers["Content-Type"] = "text/plain; charset=utf-8"
|
||||
} else {
|
||||
headers["Content-Type"] = "application/octet-stream"
|
||||
headers["Content-Disposition"] = fmt.Sprintf(`attachment; filename="%s"`, profile)
|
||||
}
|
||||
return buf.Bytes(), headers, nil
|
||||
}
|
||||
|
||||
// CPUProfile generates a CPU Profile for a given duration
|
||||
func CPUProfile(ctx context.Context, sec int) ([]byte, map[string]string, error) {
|
||||
if sec <= 0 {
|
||||
sec = 1
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := pprof.StartCPUProfile(&buf); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sleep(ctx, time.Duration(sec)*time.Second)
|
||||
|
||||
pprof.StopCPUProfile()
|
||||
|
||||
return buf.Bytes(),
|
||||
map[string]string{
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Disposition": `attachment; filename="profile"`,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Trace runs a trace profile for a given duration
|
||||
func Trace(ctx context.Context, sec int) ([]byte, map[string]string, error) {
|
||||
if sec <= 0 {
|
||||
sec = 1
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := trace.Start(&buf); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sleep(ctx, time.Duration(sec)*time.Second)
|
||||
|
||||
trace.Stop()
|
||||
|
||||
return buf.Bytes(),
|
||||
map[string]string{
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Disposition": `attachment; filename="trace"`,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func sleep(ctx context.Context, d time.Duration) {
|
||||
// Sleep until duration is met or ctx is cancelled
|
||||
select {
|
||||
case <-time.After(d):
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
1068
command/server/proto/server.pb.go
Normal file
1068
command/server/proto/server.pb.go
Normal file
File diff suppressed because it is too large
Load diff
87
command/server/proto/server.proto
Normal file
87
command/server/proto/server.proto
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package proto;
|
||||
|
||||
option go_package = "/command/server/proto";
|
||||
|
||||
service Bor {
|
||||
rpc Pprof(PprofRequest) returns (PprofResponse);
|
||||
|
||||
rpc PeersAdd(PeersAddRequest) returns (PeersAddResponse);
|
||||
|
||||
rpc PeersRemove(PeersRemoveRequest) returns (PeersRemoveResponse);
|
||||
|
||||
rpc PeersList(PeersListRequest) returns (PeersListResponse);
|
||||
|
||||
rpc PeersStatus(PeersStatusRequest) returns (PeersStatusResponse);
|
||||
|
||||
rpc ChainSetHead(ChainSetHeadRequest) returns (ChainSetHeadResponse);
|
||||
}
|
||||
|
||||
|
||||
message PeersAddRequest {
|
||||
string enode = 1;
|
||||
bool trusted = 2;
|
||||
}
|
||||
|
||||
message PeersAddResponse {
|
||||
}
|
||||
|
||||
message PeersRemoveRequest {
|
||||
string enode = 1;
|
||||
bool trusted = 2;
|
||||
}
|
||||
|
||||
message PeersRemoveResponse {
|
||||
}
|
||||
|
||||
message PeersListRequest {
|
||||
}
|
||||
|
||||
message PeersListResponse {
|
||||
repeated Peer peers = 1;
|
||||
}
|
||||
|
||||
message PeersStatusRequest {
|
||||
string enode = 1;
|
||||
}
|
||||
|
||||
message PeersStatusResponse {
|
||||
Peer peer = 1;
|
||||
}
|
||||
|
||||
message Peer {
|
||||
string id = 1;
|
||||
string enode = 2;
|
||||
string enr = 3;
|
||||
repeated string caps = 4;
|
||||
string name = 5;
|
||||
bool trusted = 6;
|
||||
bool static = 7;
|
||||
}
|
||||
|
||||
message ChainSetHeadRequest {
|
||||
uint64 number = 1;
|
||||
}
|
||||
|
||||
message ChainSetHeadResponse {
|
||||
}
|
||||
|
||||
message PprofRequest {
|
||||
Type type = 1;
|
||||
|
||||
string profile = 2;
|
||||
|
||||
int64 seconds = 3;
|
||||
|
||||
enum Type {
|
||||
LOOKUP = 0;
|
||||
CPU = 1;
|
||||
TRACE = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message PprofResponse {
|
||||
string payload = 1;
|
||||
map<string, string> headers = 2;
|
||||
}
|
||||
281
command/server/proto/server_grpc.pb.go
Normal file
281
command/server/proto/server_grpc.pb.go
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// BorClient is the client API for Bor service.
|
||||
//
|
||||
// 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) (*PprofResponse, 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)
|
||||
PeersStatus(ctx context.Context, in *PeersStatusRequest, opts ...grpc.CallOption) (*PeersStatusResponse, error)
|
||||
ChainSetHead(ctx context.Context, in *ChainSetHeadRequest, opts ...grpc.CallOption) (*ChainSetHeadResponse, error)
|
||||
}
|
||||
|
||||
type borClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewBorClient(cc grpc.ClientConnInterface) BorClient {
|
||||
return &borClient{cc}
|
||||
}
|
||||
|
||||
func (c *borClient) Pprof(ctx context.Context, in *PprofRequest, opts ...grpc.CallOption) (*PprofResponse, error) {
|
||||
out := new(PprofResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Bor/Pprof", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, 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...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *borClient) PeersRemove(ctx context.Context, in *PeersRemoveRequest, opts ...grpc.CallOption) (*PeersRemoveResponse, error) {
|
||||
out := new(PeersRemoveResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Bor/PeersRemove", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *borClient) PeersList(ctx context.Context, in *PeersListRequest, opts ...grpc.CallOption) (*PeersListResponse, error) {
|
||||
out := new(PeersListResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Bor/PeersList", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *borClient) PeersStatus(ctx context.Context, in *PeersStatusRequest, opts ...grpc.CallOption) (*PeersStatusResponse, error) {
|
||||
out := new(PeersStatusResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Bor/PeersStatus", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *borClient) ChainSetHead(ctx context.Context, in *ChainSetHeadRequest, opts ...grpc.CallOption) (*ChainSetHeadResponse, error) {
|
||||
out := new(ChainSetHeadResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Bor/ChainSetHead", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// BorServer is the server API for Bor service.
|
||||
// All implementations must embed UnimplementedBorServer
|
||||
// for forward compatibility
|
||||
type BorServer interface {
|
||||
Pprof(context.Context, *PprofRequest) (*PprofResponse, error)
|
||||
PeersAdd(context.Context, *PeersAddRequest) (*PeersAddResponse, error)
|
||||
PeersRemove(context.Context, *PeersRemoveRequest) (*PeersRemoveResponse, error)
|
||||
PeersList(context.Context, *PeersListRequest) (*PeersListResponse, error)
|
||||
PeersStatus(context.Context, *PeersStatusRequest) (*PeersStatusResponse, error)
|
||||
ChainSetHead(context.Context, *ChainSetHeadRequest) (*ChainSetHeadResponse, error)
|
||||
mustEmbedUnimplementedBorServer()
|
||||
}
|
||||
|
||||
// UnimplementedBorServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedBorServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedBorServer) Pprof(context.Context, *PprofRequest) (*PprofResponse, error) {
|
||||
return nil, 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")
|
||||
}
|
||||
func (UnimplementedBorServer) PeersRemove(context.Context, *PeersRemoveRequest) (*PeersRemoveResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PeersRemove not implemented")
|
||||
}
|
||||
func (UnimplementedBorServer) PeersList(context.Context, *PeersListRequest) (*PeersListResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PeersList not implemented")
|
||||
}
|
||||
func (UnimplementedBorServer) PeersStatus(context.Context, *PeersStatusRequest) (*PeersStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PeersStatus not implemented")
|
||||
}
|
||||
func (UnimplementedBorServer) ChainSetHead(context.Context, *ChainSetHeadRequest) (*ChainSetHeadResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ChainSetHead not implemented")
|
||||
}
|
||||
func (UnimplementedBorServer) mustEmbedUnimplementedBorServer() {}
|
||||
|
||||
// UnsafeBorServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to BorServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeBorServer interface {
|
||||
mustEmbedUnimplementedBorServer()
|
||||
}
|
||||
|
||||
func RegisterBorServer(s grpc.ServiceRegistrar, srv BorServer) {
|
||||
s.RegisterService(&Bor_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Bor_Pprof_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(PprofRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BorServer).Pprof(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Bor/Pprof",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BorServer).Pprof(ctx, req.(*PprofRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BorServer).PeersAdd(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Bor/PeersAdd",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BorServer).PeersAdd(ctx, req.(*PeersAddRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Bor_PeersRemove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(PeersRemoveRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BorServer).PeersRemove(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Bor/PeersRemove",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BorServer).PeersRemove(ctx, req.(*PeersRemoveRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Bor_PeersList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(PeersListRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BorServer).PeersList(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Bor/PeersList",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BorServer).PeersList(ctx, req.(*PeersListRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Bor_PeersStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(PeersStatusRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BorServer).PeersStatus(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Bor/PeersStatus",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BorServer).PeersStatus(ctx, req.(*PeersStatusRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Bor_ChainSetHead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ChainSetHeadRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BorServer).ChainSetHead(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Bor/ChainSetHead",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BorServer).ChainSetHead(ctx, req.(*ChainSetHeadRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// 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)
|
||||
var Bor_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.Bor",
|
||||
HandlerType: (*BorServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Pprof",
|
||||
Handler: _Bor_Pprof_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "PeersAdd",
|
||||
Handler: _Bor_PeersAdd_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "PeersRemove",
|
||||
Handler: _Bor_PeersRemove_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "PeersList",
|
||||
Handler: _Bor_PeersList_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "PeersStatus",
|
||||
Handler: _Bor_PeersStatus_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ChainSetHead",
|
||||
Handler: _Bor_ChainSetHead_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "command/server/proto/server.proto",
|
||||
}
|
||||
282
command/server/server.go
Normal file
282
command/server/server.go
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/ethstats"
|
||||
"github.com/ethereum/go-ethereum/graphql"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"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 {
|
||||
proto.UnimplementedBorServer
|
||||
node *node.Node
|
||||
backend *eth.Ethereum
|
||||
grpcServer *grpc.Server
|
||||
tracer *sdktrace.TracerProvider
|
||||
}
|
||||
|
||||
func NewServer(config *Config) (*Server, error) {
|
||||
srv := &Server{}
|
||||
|
||||
// start the logger
|
||||
setupLogger(config.LogLevel)
|
||||
|
||||
if err := srv.setupGRPCServer(config.GRPC.Addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// load the chain genesis
|
||||
if err := config.loadChain(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create the node/stack
|
||||
nodeCfg, err := config.buildNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stack, err := node.New(nodeCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
srv.node = stack
|
||||
|
||||
// register the ethereum backend
|
||||
ethCfg, err := config.buildEth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
backend, err := eth.New(stack, ethCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
srv.backend = backend
|
||||
|
||||
// debug tracing is enabled by default
|
||||
stack.RegisterAPIs(tracers.APIs(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.Modules); 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 {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// setup account manager (only keystore)
|
||||
{
|
||||
keydir := stack.KeyStoreDir()
|
||||
n, p := keystore.StandardScryptN, keystore.StandardScryptP
|
||||
if config.Accounts.UseLightweightKDF {
|
||||
n, p = keystore.LightScryptN, keystore.LightScryptP
|
||||
}
|
||||
stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p))
|
||||
}
|
||||
|
||||
// sealing (if enabled)
|
||||
if config.Sealer.Enabled {
|
||||
if err := backend.StartMining(1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := srv.setupMetrics(config.Telemetry, config.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// start the node
|
||||
if err := srv.node.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop() {
|
||||
s.node.Close()
|
||||
|
||||
// shutdown the tracer
|
||||
if s.tracer != nil {
|
||||
if err := s.tracer.Shutdown(context.Background()); err != nil {
|
||||
log.Error("Failed to shutdown open telemetry tracer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error {
|
||||
metrics.Enabled = config.Enabled
|
||||
metrics.EnabledExpensive = config.Expensive
|
||||
|
||||
if !metrics.Enabled {
|
||||
// metrics are disabled, do not set up any sink
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Info("Enabling metrics collection")
|
||||
|
||||
// influxdb
|
||||
if v1Enabled, v2Enabled := config.InfluxDB.V1Enabled, config.InfluxDB.V2Enabled; v1Enabled || v2Enabled {
|
||||
if v1Enabled && v2Enabled {
|
||||
return fmt.Errorf("both influx v1 and influx v2 cannot be enabled")
|
||||
}
|
||||
|
||||
cfg := config.InfluxDB
|
||||
tags := cfg.Tags
|
||||
endpoint := cfg.Endpoint
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Start system runtime metrics collection
|
||||
go metrics.CollectProcessMetrics(3 * time.Second)
|
||||
|
||||
if config.PrometheusAddr != "" {
|
||||
|
||||
prometheusMux := http.NewServeMux()
|
||||
|
||||
prometheusMux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
|
||||
prometheus.Handler(metrics.DefaultRegistry)
|
||||
})
|
||||
|
||||
promServer := &http.Server{
|
||||
Addr: config.PrometheusAddr,
|
||||
Handler: prometheusMux,
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := promServer.ListenAndServe(); err != nil {
|
||||
log.Error("Failure in running Prometheus server", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
if config.OpenCollectorEndpoint != "" {
|
||||
// setup open collector tracer
|
||||
ctx := context.Background()
|
||||
|
||||
res, err := resource.New(ctx,
|
||||
resource.WithAttributes(
|
||||
// the service name used to display traces in backends
|
||||
semconv.ServiceNameKey.String(serviceName),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create open telemetry resource for service: %v", err)
|
||||
}
|
||||
|
||||
// Set up a trace exporter
|
||||
traceExporter, err := otlptracegrpc.New(
|
||||
ctx,
|
||||
otlptracegrpc.WithInsecure(),
|
||||
otlptracegrpc.WithEndpoint(config.OpenCollectorEndpoint),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create open telemetry tracer exporter for service: %v", err)
|
||||
}
|
||||
|
||||
// Register the trace exporter with a TracerProvider, using a batch
|
||||
// span processor to aggregate spans before export.
|
||||
bsp := sdktrace.NewBatchSpanProcessor(traceExporter)
|
||||
tracerProvider := sdktrace.NewTracerProvider(
|
||||
sdktrace.WithSampler(sdktrace.AlwaysSample()),
|
||||
sdktrace.WithResource(res),
|
||||
sdktrace.WithSpanProcessor(bsp),
|
||||
)
|
||||
otel.SetTracerProvider(tracerProvider)
|
||||
|
||||
// set global propagator to tracecontext (the default is no-op).
|
||||
otel.SetTextMapPropagator(propagation.TraceContext{})
|
||||
|
||||
// set the tracer
|
||||
s.tracer = tracerProvider
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) setupGRPCServer(addr string) error {
|
||||
s.grpcServer = grpc.NewServer(s.withLoggingUnaryInterceptor())
|
||||
proto.RegisterBorServer(s.grpcServer, s)
|
||||
|
||||
lis, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := s.grpcServer.Serve(lis); err != nil {
|
||||
log.Error("failed to serve grpc server", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Info("GRPC Server started", "addr", addr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) withLoggingUnaryInterceptor() grpc.ServerOption {
|
||||
return grpc.UnaryInterceptor(s.loggingServerInterceptor)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// logging
|
||||
lvl, err := log.LvlFromString(strings.ToLower(logLevel))
|
||||
if err == nil {
|
||||
glogger.Verbosity(lvl)
|
||||
} else {
|
||||
glogger.Verbosity(log.LvlInfo)
|
||||
}
|
||||
log.Root().SetHandler(glogger)
|
||||
}
|
||||
109
command/server/service.go
Normal file
109
command/server/service.go
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/command/server/pprof"
|
||||
"github.com/ethereum/go-ethereum/command/server/proto"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
)
|
||||
|
||||
func (s *Server) Pprof(ctx context.Context, req *proto.PprofRequest) (*proto.PprofResponse, error) {
|
||||
var payload []byte
|
||||
var headers map[string]string
|
||||
var err error
|
||||
|
||||
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 nil, err
|
||||
}
|
||||
|
||||
resp := &proto.PprofResponse{
|
||||
Payload: hex.EncodeToString(payload),
|
||||
Headers: headers,
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) PeersAdd(ctx context.Context, req *proto.PeersAddRequest) (*proto.PeersAddResponse, error) {
|
||||
node, err := enode.Parse(enode.ValidSchemes, req.Enode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid enode: %v", err)
|
||||
}
|
||||
srv := s.node.Server()
|
||||
if req.Trusted {
|
||||
srv.AddTrustedPeer(node)
|
||||
} else {
|
||||
srv.AddPeer(node)
|
||||
}
|
||||
return &proto.PeersAddResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) PeersRemove(ctx context.Context, req *proto.PeersRemoveRequest) (*proto.PeersRemoveResponse, error) {
|
||||
node, err := enode.Parse(enode.ValidSchemes, req.Enode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid enode: %v", err)
|
||||
}
|
||||
srv := s.node.Server()
|
||||
if req.Trusted {
|
||||
srv.RemoveTrustedPeer(node)
|
||||
} else {
|
||||
srv.RemovePeer(node)
|
||||
}
|
||||
return &proto.PeersRemoveResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) PeersList(ctx context.Context, req *proto.PeersListRequest) (*proto.PeersListResponse, error) {
|
||||
resp := &proto.PeersListResponse{}
|
||||
|
||||
peers := s.node.Server().PeersInfo()
|
||||
for _, p := range peers {
|
||||
resp.Peers = append(resp.Peers, peerInfoToPeer(p))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) PeersStatus(ctx context.Context, req *proto.PeersStatusRequest) (*proto.PeersStatusResponse, error) {
|
||||
var peerInfo *p2p.PeerInfo
|
||||
for _, p := range s.node.Server().PeersInfo() {
|
||||
if strings.HasPrefix(p.ID, req.Enode) {
|
||||
if peerInfo != nil {
|
||||
return nil, fmt.Errorf("more than one peer with the same prefix")
|
||||
}
|
||||
peerInfo = p
|
||||
}
|
||||
}
|
||||
resp := &proto.PeersStatusResponse{}
|
||||
if peerInfo != nil {
|
||||
resp.Peer = peerInfoToPeer(peerInfo)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func peerInfoToPeer(info *p2p.PeerInfo) *proto.Peer {
|
||||
return &proto.Peer{
|
||||
Id: info.ID,
|
||||
Enode: info.Enode,
|
||||
Enr: info.ENR,
|
||||
Caps: info.Caps,
|
||||
Name: info.Name,
|
||||
Trusted: info.Network.Trusted,
|
||||
Static: info.Network.Static,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ChainSetHead(ctx context.Context, req *proto.ChainSetHeadRequest) (*proto.ChainSetHeadResponse, error) {
|
||||
s.backend.APIBackend.SetHead(req.Number)
|
||||
return &proto.ChainSetHeadResponse{}, nil
|
||||
}
|
||||
17
command/server/testdata/simple.hcl
vendored
Normal file
17
command/server/testdata/simple.hcl
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
data-dir = "./data"
|
||||
|
||||
whitelist = {
|
||||
a = "b"
|
||||
}
|
||||
|
||||
p2p {
|
||||
max-peers = 30
|
||||
}
|
||||
|
||||
txpool {
|
||||
lifetime = "1s"
|
||||
}
|
||||
|
||||
gpo {
|
||||
max-price = "100"
|
||||
}
|
||||
15
command/server/testdata/simple.json
vendored
Normal file
15
command/server/testdata/simple.json
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"data-dir": "./data",
|
||||
"whitelist": {
|
||||
"a": "b"
|
||||
},
|
||||
"p2p": {
|
||||
"max-peers": 30
|
||||
},
|
||||
"txpool": {
|
||||
"lifetime": "1s"
|
||||
},
|
||||
"gpo": {
|
||||
"max-price": "100"
|
||||
}
|
||||
}
|
||||
30
command/version.go
Normal file
30
command/version.go
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// VersionCommand is the command to show the version of the agent
|
||||
type VersionCommand struct {
|
||||
UI cli.Ui
|
||||
}
|
||||
|
||||
// Help implements the cli.Command interface
|
||||
func (c *VersionCommand) Help() string {
|
||||
return `Usage: bor version
|
||||
|
||||
Display the Bor version`
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
func (c *VersionCommand) Synopsis() string {
|
||||
return "Display the Bor version"
|
||||
}
|
||||
|
||||
// Run implements the cli.Command interface
|
||||
func (c *VersionCommand) Run(args []string) int {
|
||||
c.UI.Output(params.VersionWithMeta)
|
||||
|
||||
return 0
|
||||
}
|
||||
36
docs/README.md
Normal file
36
docs/README.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
# Documentation
|
||||
|
||||
- [Command-line-interface](./cli)
|
||||
|
||||
- [Configuration file](./config.md)
|
||||
|
||||
## Deprecation notes
|
||||
|
||||
- The new entrypoint to run the Bor client is ```server```.
|
||||
|
||||
```
|
||||
$ bor server
|
||||
```
|
||||
|
||||
- Toml files to configure nodes are being deprecated. Currently, we only allow for static and trusted nodes to be configured using toml files.
|
||||
|
||||
```
|
||||
$ bor server --config ./legacy.toml
|
||||
```
|
||||
|
||||
- Modules, vhost and Cors configuration are common for all jsonrpc endpoints.
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
$ bor --http --http.modules "eth,web" --ws --ws.modules "eth,web"
|
||||
```
|
||||
|
||||
Now:
|
||||
|
||||
```
|
||||
$ bor server --http --ws --jsonrpc.modules "eth,web"
|
||||
```
|
||||
|
||||
- ```Admin```, ```Personal``` and account related endpoints in ```Eth``` are being removed from the JsonRPC interface. Some of this functionality will be moved to the new GRPC server for operational tasks.
|
||||
18
docs/cli/README.md
Normal file
18
docs/cli/README.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
# Command line interface
|
||||
|
||||
## Commands
|
||||
|
||||
- [```server```](./server.md)
|
||||
|
||||
- [```debug```](./debug.md)
|
||||
|
||||
- [```account```](./account.md)
|
||||
|
||||
- [```account new```](./account_new.md)
|
||||
|
||||
- [```account list```](./account_list.md)
|
||||
|
||||
- [```account import```](./account_import.md)
|
||||
|
||||
- [```version```](./version.md)
|
||||
10
docs/cli/account.md
Normal file
10
docs/cli/account.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# 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.
|
||||
4
docs/cli/account_import.md
Normal file
4
docs/cli/account_import.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
# Account import
|
||||
|
||||
The ```account import``` command imports an account in Json format to the Bor data directory.
|
||||
4
docs/cli/account_list.md
Normal file
4
docs/cli/account_list.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
# Account list
|
||||
|
||||
The ```account list``` command lists all the accounts in the Bor data directory.
|
||||
4
docs/cli/account_new.md
Normal file
4
docs/cli/account_new.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
# 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.
|
||||
30
docs/cli/debug.md
Normal file
30
docs/cli/debug.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
# Debug
|
||||
|
||||
The ```bor debug``` command takes a debug dump of the running client.
|
||||
|
||||
## Options
|
||||
|
||||
- ```seconds```: Number of seconds to trace cpu and traces.
|
||||
|
||||
- ```output```: Output directory for the data dump.
|
||||
|
||||
## Examples
|
||||
|
||||
By default it creates a tar.gz file with the output:
|
||||
|
||||
```
|
||||
$ bor debug
|
||||
Starting debugger...
|
||||
|
||||
Created debug archive: bor-debug-2021-10-26-073819Z.tar.gz
|
||||
```
|
||||
|
||||
Send the output to a specific directory:
|
||||
|
||||
```
|
||||
$ bor debug --output data
|
||||
Starting debugger...
|
||||
|
||||
Created debug directory: data/bor-debug-2021-10-26-075437Z
|
||||
```
|
||||
192
docs/cli/server.md
Normal file
192
docs/cli/server.md
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
# Server
|
||||
|
||||
The ```bor server``` command runs the Bor client.
|
||||
|
||||
## General Options
|
||||
|
||||
- ```chain```: Name of the chain to sync (mainnet or mumbai).
|
||||
|
||||
- ```log-level```: Set log level for the server (info, warn, debug, trace).
|
||||
|
||||
- ```datadir```: Path of the data directory to store information (defaults to $HOME).
|
||||
|
||||
- ```config```: List of files that contain the configuration.
|
||||
|
||||
- ```syncmode```: Blockchain sync mode ("fast", "full", "snap" or "light").
|
||||
|
||||
- ```gcmode```: Blockchain garbage collection mode ("full", "archive").
|
||||
|
||||
- ```whitelist```: Comma separated block number-to-hash mappings to enforce (<number>=<hash>).
|
||||
|
||||
- ```snapshot```: Enables snapshot-database mode (default = enable).
|
||||
|
||||
- ```bor.heimdall```: URL of Heimdall service.
|
||||
|
||||
- ```bor.withoutheimdall```: Run without Heimdall service (for testing purpose).
|
||||
|
||||
- ```ethstats```: Reporting URL of a ethstats service (nodename:secret@host:port).
|
||||
|
||||
- ```gpo.blocks```: Number of recent blocks to check for gas prices.
|
||||
|
||||
- ```gpo.percentile```: Suggested gas price is the given percentile of a set of recent transaction gas prices.
|
||||
|
||||
- ```gpo.maxprice```: Maximum gas price will be recommended by gpo.
|
||||
|
||||
- ```gpo.ignoreprice```: Gas price below which gpo will ignore transactions.
|
||||
|
||||
- ```grpc.addr```: Address and port to bind the GRPC server.
|
||||
|
||||
### Transaction Pool Options
|
||||
|
||||
- ```txpool.locals```: Comma separated accounts to treat as locals (no flush, priority inclusion).
|
||||
|
||||
- ```txpool.nolocals```: Disables price exemptions for locally submitted transactions
|
||||
|
||||
- ```txpool.journal```: Disk journal for local transaction to survive node restarts
|
||||
|
||||
- ```txpool.rejournal```: Time interval to regenerate the local transaction journal
|
||||
|
||||
- ```txpool.pricelimit```: Minimum gas price limit to enforce for acceptance into the pool
|
||||
|
||||
- ```txpool.pricebump```: Price bump percentage to replace an already existing transaction
|
||||
|
||||
- ```txpool.accountslots```: Minimum number of executable transaction slots guaranteed per account
|
||||
|
||||
- ```txpool.globalslots```: Maximum number of executable transaction slots for all accounts
|
||||
|
||||
- ```txpool.accountqueue```: Maximum number of non-executable transaction slots permitted per account
|
||||
|
||||
- ```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 one year, 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.
|
||||
|
||||
- ```jsonrpc.modules```: API's offered over the HTTP-RPC interface.
|
||||
|
||||
- ```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.
|
||||
|
||||
- ```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.
|
||||
|
||||
- ```graphql```: Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.
|
||||
|
||||
### P2P Options
|
||||
|
||||
- ```bind```: Network binding address
|
||||
|
||||
- ```port```: Network listening port
|
||||
|
||||
- ```bootnodes```: Comma separated enode URLs for P2P discovery bootstrap
|
||||
|
||||
- ```maxpeers```: "Maximum number of network peers (network disabled if set to 0)
|
||||
|
||||
- ```maxpendpeers```: Maximum number of pending connection attempts (defaults used if set to 0)
|
||||
|
||||
- ```nat```: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)
|
||||
|
||||
- ```nodiscover```: "Disables the peer discovery mechanism (manual peer addition)
|
||||
|
||||
- ```v5disc```: "Enables the experimental RLPx V5 (Topic Discovery) mechanism
|
||||
|
||||
### Telemetry Options
|
||||
|
||||
- ```metrics```: Enable metrics collection and reporting.
|
||||
|
||||
- ```metrics.expensive```: Enable expensive metrics collection and reporting.
|
||||
|
||||
- ```metrics.influxdb```: Enable metrics export/push to an external InfluxDB database (v1).
|
||||
|
||||
- ```metrics.influxdb.endpoint```: InfluxDB API endpoint to report metrics to.
|
||||
|
||||
- ```metrics.influxdb.database```: InfluxDB database name to push reported metrics to.
|
||||
|
||||
- ```metrics.influxdb.username```: Username to authorize access to the database.
|
||||
|
||||
- ```metrics.influxdb.password```: Password to authorize access to the database.
|
||||
|
||||
- ```metrics.influxdb.tags```: Comma-separated InfluxDB tags (key/values) attached to all measurements.
|
||||
|
||||
- ```metrics.influxdbv2```: Enable metrics export/push to an external InfluxDB v2 database.
|
||||
|
||||
- ```metrics.influxdb.token```: Token to authorize access to the database (v2 only).
|
||||
|
||||
- ```metrics.influxdb.bucket```: InfluxDB bucket name to push reported metrics to (v2 only).
|
||||
|
||||
- ```metrics.influxdb.organization```: InfluxDB organization name (v2 only).
|
||||
|
||||
### Account Management Options
|
||||
|
||||
- ```unlock```: "Comma separated list of accounts to unlock.
|
||||
|
||||
- ```password```: Password file to use for non-interactive password input.
|
||||
|
||||
- ```allow-insecure-unlock```: Allow insecure account unlocking when account-related RPCs are exposed by http.
|
||||
|
||||
- ```lightkdf```: Reduce key-derivation RAM & CPU usage at some expense of KDF strength.
|
||||
|
||||
## Usage
|
||||
|
||||
Use multiple files to configure the client:
|
||||
|
||||
```
|
||||
$ bor server --config ./legacy-config.toml --config ./config2.hcl
|
||||
```
|
||||
11
docs/cli/version.md
Normal file
11
docs/cli/version.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
# Version
|
||||
|
||||
The ```bor version``` command outputs the version of the binary.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
$ bor version
|
||||
0.2.9-stable
|
||||
```
|
||||
133
docs/config.md
Normal file
133
docs/config.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
# Config
|
||||
|
||||
Toml files format used in geth are being deprecated.
|
||||
|
||||
Bor uses uses JSON and [HCL](https://github.com/hashicorp/hcl) formats to create configuration files. This is the format in HCL alongside the default values:
|
||||
|
||||
```
|
||||
chain = "mainnet"
|
||||
log-level = "info"
|
||||
data-dir = ""
|
||||
sync-mode = "fast"
|
||||
gc-mode = "full"
|
||||
snapshot = true
|
||||
ethstats = ""
|
||||
whitelist = {}
|
||||
|
||||
p2p {
|
||||
max-peers = 30
|
||||
max-pend-peers = 50
|
||||
bind = "0.0.0.0"
|
||||
port = 30303
|
||||
no-discover = false
|
||||
nat = "any"
|
||||
discovery {
|
||||
v5-enabled = false
|
||||
bootnodes = []
|
||||
bootnodesv4 = []
|
||||
bootnodesv5 = []
|
||||
staticNodes = []
|
||||
trustedNodes = []
|
||||
dns = []
|
||||
}
|
||||
}
|
||||
|
||||
heimdall {
|
||||
url = "http://localhost:1317"
|
||||
without = false
|
||||
}
|
||||
|
||||
txpool {
|
||||
locals = []
|
||||
no-locals = false
|
||||
journal = ""
|
||||
rejournal = "1h"
|
||||
price-limit = 1
|
||||
price-bump = 10
|
||||
account-slots = 16
|
||||
global-slots = 4096
|
||||
account-queue = 64
|
||||
global-queue = 1024
|
||||
lifetime = "3h"
|
||||
}
|
||||
|
||||
sealer {
|
||||
enabled = false
|
||||
etherbase = ""
|
||||
gas-ceil = 8000000
|
||||
extra-data = ""
|
||||
}
|
||||
|
||||
gpo {
|
||||
blocks = 20
|
||||
percentile = 60
|
||||
}
|
||||
|
||||
jsonrpc {
|
||||
ipc-disable = false
|
||||
ipc-path = ""
|
||||
modules = ["web3", "net"]
|
||||
cors = ["*"]
|
||||
vhost = ["*"]
|
||||
|
||||
http {
|
||||
enabled = false
|
||||
port = 8545
|
||||
prefix = ""
|
||||
host = "localhost"
|
||||
}
|
||||
|
||||
ws {
|
||||
enabled = false
|
||||
port = 8546
|
||||
prefix = ""
|
||||
host = "localhost"
|
||||
}
|
||||
|
||||
graphqh {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
telemetry {
|
||||
enabled = false
|
||||
expensive = false
|
||||
|
||||
influxdb {
|
||||
v1-enabled = false
|
||||
endpoint = ""
|
||||
database = ""
|
||||
username = ""
|
||||
password = ""
|
||||
v2-enabled = false
|
||||
token = ""
|
||||
bucket = ""
|
||||
organization = ""
|
||||
}
|
||||
}
|
||||
|
||||
cache {
|
||||
cache = 1024
|
||||
perc-database = 50
|
||||
perc-trie = 15
|
||||
perc-gc = 25
|
||||
perc-snapshot = 10
|
||||
journal = "triecache"
|
||||
rejournal = "60m"
|
||||
no-prefetch = false
|
||||
preimages = false
|
||||
tx-lookup-limit = 2350000
|
||||
}
|
||||
|
||||
accounts {
|
||||
unlock = []
|
||||
password-file = ""
|
||||
allow-insecure-unlock = false
|
||||
use-lightweight-kdf = false
|
||||
}
|
||||
|
||||
grpc {
|
||||
addr = ":3131"
|
||||
}
|
||||
```
|
||||
16
go.mod
16
go.mod
|
|
@ -25,9 +25,11 @@ require (
|
|||
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/protobuf v1.4.3
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
|
||||
github.com/google/uuid v1.1.5
|
||||
|
|
@ -35,19 +37,23 @@ require (
|
|||
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29
|
||||
github.com/hashicorp/go-bexpr v0.1.10
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
|
||||
github.com/hashicorp/hcl/v2 v2.10.1
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3
|
||||
github.com/holiman/uint256 v1.2.0
|
||||
github.com/huin/goupnp v1.0.2
|
||||
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-0.20160603034137-1fa385a6f458
|
||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
||||
github.com/julienschmidt/httprouter v1.2.0
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559
|
||||
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-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
|
||||
|
|
@ -55,6 +61,7 @@ require (
|
|||
github.com/prometheus/tsdb v0.7.1
|
||||
github.com/rjeczalik/notify v0.9.1
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
||||
github.com/stretchr/testify v1.7.0
|
||||
|
|
@ -62,12 +69,17 @@ require (
|
|||
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
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912
|
||||
golang.org/x/text v0.3.6
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
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
|
||||
|
|
|
|||
132
go.sum
132
go.sum
|
|
@ -33,6 +33,7 @@ github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSW
|
|||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
|
|
@ -41,19 +42,35 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
|
||||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
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=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go-v2 v1.2.0 h1:BS+UYpbsElC82gB+2E2jiCBg36i8HlubTB/dO/moQ9c=
|
||||
github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.1.1 h1:ZAoq32boMzcaTW9bcUacBswAmHTbvlvDJICgHFZuECo=
|
||||
|
|
@ -74,6 +91,8 @@ github.com/aws/smithy-go v1.1.0 h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU=
|
|||
github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||
|
|
@ -86,6 +105,8 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku
|
|||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
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=
|
||||
|
|
@ -99,6 +120,12 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA=
|
||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
|
||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8=
|
||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
|
||||
|
|
@ -129,7 +156,11 @@ github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA
|
|||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
|
|
@ -149,11 +180,13 @@ github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1T
|
|||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
|
|
@ -163,6 +196,8 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq
|
|||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
|
|
@ -174,17 +209,23 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
|
|||
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/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
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=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
|
|
@ -198,8 +239,11 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
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/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=
|
||||
|
|
@ -207,6 +251,7 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
|
|||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I=
|
||||
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
|
|
@ -217,21 +262,33 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
|
|||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29 h1:sezaKhEfPFg8W0Enm61B9Gs911H8iesGY5R8NDPtd1M=
|
||||
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
|
||||
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl/v2 v2.10.1 h1:h4Xx4fsrRE26ohAk/1iGF/JBqRQbyUqu5Lvj60U54ys=
|
||||
github.com/hashicorp/hcl/v2 v2.10.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI=
|
||||
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=
|
||||
github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8=
|
||||
|
|
@ -260,8 +317,9 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
|||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||
github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559 h1:0VWDXPNE0brOek1Q8bLfzKkvOzwbQE/snjGojlCr8CY=
|
||||
|
|
@ -274,7 +332,6 @@ github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM52
|
|||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
|
|
@ -283,6 +340,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||
|
|
@ -301,6 +359,7 @@ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
|
|||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d h1:oNAwILwmgWKFpuU+dXvI6dl9jG2mAWAZLX3r9s0PPiw=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
|
|
@ -312,10 +371,20 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
|||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw=
|
||||
github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
|
||||
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
|
|
@ -355,6 +424,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
|
|
@ -370,12 +441,16 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
|||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
|
||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
|
|
@ -386,6 +461,7 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
|
|||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
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=
|
||||
|
|
@ -397,6 +473,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
|
||||
|
|
@ -412,20 +489,41 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X
|
|||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
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/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=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
|
||||
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 h1:xzbcGykysUh776gzD1LUPsNNHKWN0kQWDnJhn1ddUuk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0/go.mod h1:14T5gr+Y6s2AgHPqBMgnGwp04csUjQmYXFWPeiBoq5s=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0 h1:VsgsSCDwOSuO8eMVh63Cd4nACMqgjpmAeJSIvVNneD0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0/go.mod h1:9mLBBnPRf3sf+ASVH2p9xREXVBvwib02FxcKnavtExg=
|
||||
go.opentelemetry.io/otel/sdk v1.2.0 h1:wKN260u4DesJYhyjxDa7LRFkuhH7ncEVKU37LWcyNIo=
|
||||
go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U=
|
||||
go.opentelemetry.io/otel/trace v1.2.0 h1:Ys3iqbqZhcf28hHzrm5WAquMkDHNZTUkw7KHbuNjej0=
|
||||
go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
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/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-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
|
@ -464,6 +562,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -478,6 +577,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
|
|
@ -512,6 +612,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -538,6 +639,7 @@ golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/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/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
|
|
@ -620,18 +722,34 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx
|
|||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
|||
5
scripts/tools-protobuf.sh
Normal file
5
scripts/tools-protobuf.sh
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.12.0/protoc-3.12.0-linux-x86_64.zip
|
||||
sudo unzip protoc-3.12.0-linux-x86_64.zip -d /usr/local/bin
|
||||
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.25.0
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
|
||||
Loading…
Reference in a new issue