mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-15 00:13:46 +00:00
commit
b797f25a80
24 changed files with 2502 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -47,3 +47,4 @@ profile.cov
|
||||||
/dashboard/assets/package-lock.json
|
/dashboard/assets/package-lock.json
|
||||||
|
|
||||||
**/yarn-error.log
|
**/yarn-error.log
|
||||||
|
./test
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,12 @@ them using your favourite package manager. Once the dependencies are installed,
|
||||||
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
||||||
|
|
||||||
|
|
||||||
|
Build the beta client:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
go build -o bor-beta command/*.go
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
|
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
|
||||||
|
|
|
||||||
32
command/account.go
Normal file
32
command/account.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
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`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
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"})
|
||||||
|
}
|
||||||
131
command/main.go
Normal file
131
command/main.go
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
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/node"
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/ryanuber/columnize"
|
||||||
|
)
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
318
command/server/command.go
Normal file
318
command/server/command.go
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"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/node"
|
||||||
|
"github.com/mattn/go-colorable"
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
|
"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
|
||||||
|
|
||||||
|
// bor node
|
||||||
|
node *node.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
if c.configFile != "" {
|
||||||
|
cfg, err := readConfigFile(c.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
|
||||||
|
|
||||||
|
// start the logger
|
||||||
|
setupLogger(config.LogLevel)
|
||||||
|
|
||||||
|
// load the chain genesis
|
||||||
|
if err := config.loadChain(); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the node/stack
|
||||||
|
nodeCfg, err := config.buildNode()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
stack, err := node.New(nodeCfg)
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
c.node = stack
|
||||||
|
|
||||||
|
// register the ethereum backend
|
||||||
|
ethCfg, err := config.buildEth()
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
backend, err := eth.New(stack, ethCfg)
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Heimdall setup", "url", ethCfg.HeimdallURL)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
c.UI.Error(fmt.Sprintf("Failed to register the GraphQL service: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register ethash service
|
||||||
|
if config.EthStats != "" {
|
||||||
|
if err := ethstats.New(stack, backend.APIBackend, backend.Engine(), config.EthStats); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup account manager (only keystore)
|
||||||
|
var borKeystore *keystore.KeyStore
|
||||||
|
{
|
||||||
|
keydir := stack.KeyStoreDir()
|
||||||
|
n, p := keystore.StandardScryptN, keystore.StandardScryptP
|
||||||
|
if config.Accounts.UseLightweightKDF {
|
||||||
|
n, p = keystore.LightScryptN, keystore.LightScryptP
|
||||||
|
}
|
||||||
|
borKeystore = keystore.NewKeyStore(keydir, n, p)
|
||||||
|
stack.AccountManager().AddBackend(borKeystore)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlock accounts if necessary
|
||||||
|
if len(config.Accounts.Unlock) != 0 {
|
||||||
|
if err := c.unlockAccounts(borKeystore); err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("failed to unlock: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sealing (if enabled)
|
||||||
|
if config.Sealer.Enabled {
|
||||||
|
if err := backend.StartMining(1); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.setupMetrics(config.Metrics); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the node
|
||||||
|
if err := c.node.Start(); err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return c.handleSignals()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) unlockAccounts(borKeystore *keystore.KeyStore) error {
|
||||||
|
// If insecure account unlocking is not allowed if node's APIs are exposed to external.
|
||||||
|
if !c.node.Config().InsecureUnlockAllowed && c.node.Config().ExtRPCEnabled() {
|
||||||
|
return fmt.Errorf("account unlock with HTTP access is forbidden")
|
||||||
|
}
|
||||||
|
|
||||||
|
// read passwords from file if possible
|
||||||
|
passwords := []string{}
|
||||||
|
if c.config.Accounts.PasswordFile != "" {
|
||||||
|
var err error
|
||||||
|
if passwords, err = readMultilineFile(c.config.Accounts.PasswordFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decodePassword := func(addr common.Address, index int) (string, error) {
|
||||||
|
if len(passwords) > 0 {
|
||||||
|
if index < len(passwords) {
|
||||||
|
return passwords[index], nil
|
||||||
|
}
|
||||||
|
return passwords[len(passwords)-1], nil
|
||||||
|
}
|
||||||
|
// ask for the password
|
||||||
|
return c.UI.AskSecret(fmt.Sprintf("Please give a password to unlock '%s'", addr.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
for index, addrStr := range c.config.Accounts.Unlock {
|
||||||
|
if !common.IsHexAddress(addrStr) {
|
||||||
|
return fmt.Errorf("unlock value '%s' is not an address", addrStr)
|
||||||
|
}
|
||||||
|
acct := accounts.Account{Address: common.HexToAddress(addrStr)}
|
||||||
|
|
||||||
|
password, err := decodePassword(acct.Address, index)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := borKeystore.Unlock(acct, password); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Info("Unlocked account", "address", acct.Address.Hex())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) setupMetrics(config *MetricsConfig) 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)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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.node.Close()
|
||||||
|
c.node.Wait()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readMultilineFile(path string) ([]string, error) {
|
||||||
|
text, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lines := strings.Split(string(text), "\n")
|
||||||
|
// Sanitise DOS line endings.
|
||||||
|
for i := range lines {
|
||||||
|
lines[i] = strings.TrimRight(lines[i], "\r")
|
||||||
|
}
|
||||||
|
return lines, nil
|
||||||
|
}
|
||||||
616
command/server/config.go
Normal file
616
command/server/config.go
Normal file
|
|
@ -0,0 +1,616 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"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/imdario/mergo"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
gopsutil "github.com/shirou/gopsutil/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
chain *chains.Chain
|
||||||
|
|
||||||
|
Chain string
|
||||||
|
Debug bool
|
||||||
|
Whitelist map[string]string
|
||||||
|
LogLevel string
|
||||||
|
DataDir string
|
||||||
|
P2P *P2PConfig
|
||||||
|
SyncMode string
|
||||||
|
GcMode string
|
||||||
|
Snapshot bool
|
||||||
|
EthStats string
|
||||||
|
Heimdall *HeimdallConfig
|
||||||
|
TxPool *TxPoolConfig
|
||||||
|
Sealer *SealerConfig
|
||||||
|
JsonRPC *JsonRPCConfig
|
||||||
|
Gpo *GpoConfig
|
||||||
|
Ethstats string
|
||||||
|
Metrics *MetricsConfig
|
||||||
|
Cache *CacheConfig
|
||||||
|
Accounts *AccountsConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type P2PConfig struct {
|
||||||
|
MaxPeers uint64
|
||||||
|
MaxPendPeers uint64
|
||||||
|
Bind string
|
||||||
|
Port uint64
|
||||||
|
NoDiscover bool
|
||||||
|
NAT string
|
||||||
|
Discovery *P2PDiscovery
|
||||||
|
}
|
||||||
|
|
||||||
|
type P2PDiscovery struct {
|
||||||
|
V5Enabled bool
|
||||||
|
Bootnodes []string
|
||||||
|
BootnodesV4 []string
|
||||||
|
BootnodesV5 []string
|
||||||
|
StaticNodes []string
|
||||||
|
TrustedNodes []string
|
||||||
|
DNS []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HeimdallConfig struct {
|
||||||
|
URL string
|
||||||
|
Without bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type TxPoolConfig struct {
|
||||||
|
Locals []string
|
||||||
|
NoLocals bool
|
||||||
|
Journal string
|
||||||
|
Rejournal time.Duration
|
||||||
|
PriceLimit uint64
|
||||||
|
PriceBump uint64
|
||||||
|
AccountSlots uint64
|
||||||
|
GlobalSlots uint64
|
||||||
|
AccountQueue uint64
|
||||||
|
GlobalQueue uint64
|
||||||
|
LifeTime time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type SealerConfig struct {
|
||||||
|
Enabled bool
|
||||||
|
Etherbase string
|
||||||
|
ExtraData string
|
||||||
|
GasCeil uint64
|
||||||
|
GasPrice *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type JsonRPCConfig struct {
|
||||||
|
IPCDisable bool
|
||||||
|
IPCPath string
|
||||||
|
|
||||||
|
Modules []string
|
||||||
|
VHost []string
|
||||||
|
Cors []string
|
||||||
|
|
||||||
|
GasCap uint64
|
||||||
|
TxFeeCap float64
|
||||||
|
|
||||||
|
Http *APIConfig
|
||||||
|
Ws *APIConfig
|
||||||
|
Graphql *APIConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type APIConfig struct {
|
||||||
|
Enabled bool
|
||||||
|
Port uint64
|
||||||
|
Prefix string
|
||||||
|
Host string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GpoConfig struct {
|
||||||
|
Blocks uint64
|
||||||
|
Percentile uint64
|
||||||
|
MaxPrice *big.Int
|
||||||
|
IgnorePrice *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type MetricsConfig struct {
|
||||||
|
Enabled bool
|
||||||
|
Expensive bool
|
||||||
|
InfluxDB *InfluxDBConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type InfluxDBConfig struct {
|
||||||
|
V1Enabled bool
|
||||||
|
Endpoint string
|
||||||
|
Database string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Tags map[string]string
|
||||||
|
V2Enabled bool
|
||||||
|
Token string
|
||||||
|
Bucket string
|
||||||
|
Organization string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CacheConfig struct {
|
||||||
|
Cache uint64
|
||||||
|
PercGc uint64
|
||||||
|
PercSnapshot uint64
|
||||||
|
PercDatabase uint64
|
||||||
|
PercTrie uint64
|
||||||
|
Journal string
|
||||||
|
Rejournal time.Duration
|
||||||
|
NoPrefetch bool
|
||||||
|
Preimages bool
|
||||||
|
TxLookupLimit uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountsConfig struct {
|
||||||
|
Unlock []string
|
||||||
|
PasswordFile string
|
||||||
|
AllowInsecureUnlock bool
|
||||||
|
UseLightweightKDF bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
Chain: "mainnet",
|
||||||
|
Debug: false,
|
||||||
|
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,
|
||||||
|
EthStats: "",
|
||||||
|
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: "",
|
||||||
|
Metrics: &MetricsConfig{
|
||||||
|
Enabled: false,
|
||||||
|
Expensive: false,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readConfigFile(path string) (*Config, error) {
|
||||||
|
data, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// TODO: Use hcl as config format
|
||||||
|
ext := filepath.Ext(path)
|
||||||
|
switch ext {
|
||||||
|
case ".toml":
|
||||||
|
return readLegacyConfig(data)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("file path extension '%s' not found", ext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
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"})
|
||||||
|
}
|
||||||
99
command/server/config_test.go
Normal file
99
command/server/config_test.go
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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",
|
||||||
|
Debug: 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",
|
||||||
|
Debug: 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
449
command/server/flags.go
Normal file
449
command/server/flags.go
Normal file
|
|
@ -0,0 +1,449 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/command/flagset"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Command) Flags() *flagset.Flagset {
|
||||||
|
c.cliConfig = DefaultConfig()
|
||||||
|
|
||||||
|
f := flagset.NewFlagSet("server")
|
||||||
|
|
||||||
|
f.BoolFlag(&flagset.BoolFlag{
|
||||||
|
Name: "debug",
|
||||||
|
Usage: "Path of the file to apply",
|
||||||
|
Value: &c.cliConfig.Debug,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "chain",
|
||||||
|
Usage: "Name of the chain to sync",
|
||||||
|
Value: &c.cliConfig.Chain,
|
||||||
|
})
|
||||||
|
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.StringFlag(&flagset.StringFlag{
|
||||||
|
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.Metrics.Enabled,
|
||||||
|
})
|
||||||
|
f.BoolFlag(&flagset.BoolFlag{
|
||||||
|
Name: "metrics.expensive",
|
||||||
|
Usage: "Enable expensive metrics collection and reporting",
|
||||||
|
Value: &c.cliConfig.Metrics.Expensive,
|
||||||
|
})
|
||||||
|
f.BoolFlag(&flagset.BoolFlag{
|
||||||
|
Name: "metrics.influxdb",
|
||||||
|
Usage: "Enable metrics export/push to an external InfluxDB database (v1)",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.V1Enabled,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "metrics.influxdb.endpoint",
|
||||||
|
Usage: "InfluxDB API endpoint to report metrics to",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.Endpoint,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "metrics.influxdb.database",
|
||||||
|
Usage: "InfluxDB database name to push reported metrics to",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.Database,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "metrics.influxdb.username",
|
||||||
|
Usage: "Username to authorize access to the database",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.Username,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "metrics.influxdb.password",
|
||||||
|
Usage: "Password to authorize access to the database",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.Password,
|
||||||
|
})
|
||||||
|
f.MapStringFlag(&flagset.MapStringFlag{
|
||||||
|
Name: "metrics.influxdb.tags",
|
||||||
|
Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.Tags,
|
||||||
|
})
|
||||||
|
// influx db v2
|
||||||
|
f.BoolFlag(&flagset.BoolFlag{
|
||||||
|
Name: "metrics.influxdbv2",
|
||||||
|
Usage: "Enable metrics export/push to an external InfluxDB v2 database",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.V2Enabled,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "metrics.influxdb.token",
|
||||||
|
Usage: "Token to authorize access to the database (v2 only)",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.Token,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "metrics.influxdb.bucket",
|
||||||
|
Usage: "InfluxDB bucket name to push reported metrics to (v2 only)",
|
||||||
|
Value: &c.cliConfig.Metrics.InfluxDB.Bucket,
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "metrics.influxdb.organization",
|
||||||
|
Usage: "InfluxDB organization name (v2 only)",
|
||||||
|
Value: &c.cliConfig.Metrics.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,
|
||||||
|
})
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
4
go.mod
4
go.mod
|
|
@ -39,6 +39,7 @@ require (
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3
|
github.com/holiman/bloomfilter/v2 v2.0.3
|
||||||
github.com/holiman/uint256 v1.2.0
|
github.com/holiman/uint256 v1.2.0
|
||||||
github.com/huin/goupnp v1.0.2
|
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 v1.8.3
|
||||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
||||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||||
|
|
@ -49,6 +50,8 @@ require (
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.8
|
github.com/mattn/go-colorable v0.1.8
|
||||||
github.com/mattn/go-isatty v0.0.12
|
github.com/mattn/go-isatty v0.0.12
|
||||||
|
github.com/mitchellh/cli v1.1.2
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/naoina/go-stringutil v0.1.0 // indirect
|
github.com/naoina/go-stringutil v0.1.0 // indirect
|
||||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
|
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
|
|
@ -56,6 +59,7 @@ require (
|
||||||
github.com/prometheus/tsdb v0.7.1
|
github.com/prometheus/tsdb v0.7.1
|
||||||
github.com/rjeczalik/notify v0.9.1
|
github.com/rjeczalik/notify v0.9.1
|
||||||
github.com/rs/cors v1.7.0
|
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/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
||||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
|
|
|
||||||
33
go.sum
33
go.sum
|
|
@ -41,6 +41,12 @@ 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/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/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/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/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 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
|
||||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||||
|
|
@ -54,6 +60,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
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/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||||
|
github.com/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 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 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.1.1 h1:ZAoq32boMzcaTW9bcUacBswAmHTbvlvDJICgHFZuECo=
|
github.com/aws/aws-sdk-go-v2/config v1.1.1 h1:ZAoq32boMzcaTW9bcUacBswAmHTbvlvDJICgHFZuECo=
|
||||||
|
|
@ -74,6 +82,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/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 v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.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/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/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||||
|
|
@ -205,6 +215,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-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/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/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 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I=
|
||||||
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
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=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
|
@ -215,6 +226,10 @@ 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/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 h1:sezaKhEfPFg8W0Enm61B9Gs911H8iesGY5R8NDPtd1M=
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
||||||
|
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-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.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.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 h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||||
|
|
@ -224,10 +239,14 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU
|
||||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
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/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/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 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI=
|
||||||
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
|
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/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/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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=
|
github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=
|
||||||
github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8=
|
github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8=
|
||||||
|
|
@ -295,6 +314,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-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 h1:oNAwILwmgWKFpuU+dXvI6dl9jG2mAWAZLX3r9s0PPiw=
|
||||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
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.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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
|
|
@ -306,6 +326,14 @@ 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-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/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/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/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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
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=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
|
|
@ -345,6 +373,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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
|
@ -364,6 +394,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
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/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/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.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||||
github.com/segmentio/kafka-go v0.2.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/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
|
@ -387,6 +419,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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
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.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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
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=
|
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue