Merge branch 'develop' into POS-648

This commit is contained in:
Krishna Upadhyaya 2022-07-27 19:09:04 +05:30
commit 75bb3bdeb1
27 changed files with 616 additions and 338 deletions

View file

@ -90,6 +90,9 @@ nfpms:
- src: builder/files/genesis-testnet-v4.json - src: builder/files/genesis-testnet-v4.json
dst: /etc/bor/genesis-testnet-v4.json dst: /etc/bor/genesis-testnet-v4.json
type: config type: config
- src: builder/files/config.toml
dst: /var/lib/bor/config.toml
type: config
overrides: overrides:
rpm: rpm:

View file

@ -6,34 +6,7 @@
[Service] [Service]
Restart=on-failure Restart=on-failure
RestartSec=5s RestartSec=5s
ExecStart=/usr/local/bin/bor server \ ExecStart=/usr/local/bin/bor server -config="/var/lib/bor/config.toml"
--chain=mumbai \
# --chain=mainnet \
--datadir /var/lib/bor/data \
--metrics \
--metrics.prometheus-addr="127.0.0.1:7071" \
--syncmode 'full' \
--miner.gasprice '30000000000' \
--miner.gaslimit '20000000' \
--miner.gastarget '20000000' \
--txpool.nolocals \
--txpool.accountslots 16 \
--txpool.globalslots 32768 \
--txpool.accountqueue 16 \
--txpool.globalqueue 32768 \
--txpool.pricelimit '30000000000' \
--txpool.lifetime '1h30m0s' \
--bootnodes "enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303,enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303"
# Validator params
# Uncomment and configure the following lines in case you run a validator. Don't forget to add backslash (\)
# to previous command line.
# --keystore /var/lib/bor/keystore \
# --unlock [VALIDATOR ADDRESS] \
# --password /var/lib/bor/password.txt \
# --allow-insecure-unlock \
# --nodiscover --maxpeers 1 \
# --miner.etherbase [VALIDATOR ADDRESS] \
# --mine
Type=simple Type=simple
User=ubuntu User=ubuntu
KillSignal=SIGINT KillSignal=SIGINT

44
builder/files/config.toml Normal file
View file

@ -0,0 +1,44 @@
# chain = "mumbai"
chain = "mainnet"
datadir = "/var/lib/bor/data"
syncmode = "full"
[telemetry]
metrics = true
prometheus-addr = "127.0.0.1:7071"
[miner]
# *** Validator params
# *** Uncomment and configure the following lines in case you run a validator.
# mine = true
# etherbase = "VALIDATOR ADDRESS"
gasprice = "30000000000"
gasceil = 20000000
[txpool]
accountqueue = 16
accountslots = 16
globalqueue = 32768
globalslots = 32768
lifetime = "1h30m0s"
nolocals = true
pricelimit = 30000000000
[p2p]
# *** Validator params
# *** Uncomment and configure the following lines in case you run a validator.
# nodiscover = true
# maxpeers = 1
[p2p.discovery]
bootnodes = ["enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303", "enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303"]
# *** Validator params
# *** Uncomment and configure the following lines in case you run a validator.
# keystore = "/var/lib/bor/keystore"
# [accounts]
# allow-insecure-unlock = true
# password = "/var/lib/bor/password.txt"
# unlock = ["VALIDATOR ADDRESS"]

View file

@ -59,6 +59,8 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
return nil, err return nil, err
} }
snap.ValidatorSet.UpdateValidatorMap()
snap.config = config snap.config = config
snap.sigcache = sigcache snap.sigcache = sigcache

View file

@ -628,6 +628,10 @@ func (vals *ValidatorSet) updateValidators(updates []*Validator, deletes []*Vali
vals.applyUpdates(updates) vals.applyUpdates(updates)
vals.applyRemovals(deletes) vals.applyRemovals(deletes)
vals.UpdateValidatorMap()
}
func (vals *ValidatorSet) UpdateValidatorMap() {
vals.validatorsMap = make(map[common.Address]int, len(vals.Validators)) vals.validatorsMap = make(map[common.Address]int, len(vals.Validators))
for i, val := range vals.Validators { for i, val := range vals.Validators {

View file

@ -26,6 +26,8 @@
- [```debug pprof```](./debug_pprof.md) - [```debug pprof```](./debug_pprof.md)
- [```dumpconfig```](./dumpconfig.md)
- [```fingerprint```](./fingerprint.md) - [```fingerprint```](./fingerprint.md)
- [```peers```](./peers.md) - [```peers```](./peers.md)

3
docs/cli/dumpconfig.md Normal file
View file

@ -0,0 +1,3 @@
# Dumpconfig
The ```bor dumpconfig <your-favourite-flags>``` command will export the user provided flags into a configuration file

View file

@ -1,133 +1,144 @@
# Config # Config
Toml files format used in geth are being deprecated. - The `bor dumpconfig` command prints the default configurations, in the TOML format, on the terminal.
- One can `pipe (>)` this to a file (say `config.toml`) and use it to start bor.
Bor uses uses JSON and [HCL](https://github.com/hashicorp/hcl) formats to create configuration files. This is the format in HCL alongside the default values: - Command to provide a config file: `bor server -config config.toml`
- Bor uses TOML, HCL, and JSON format config files.
- This is the format of the config file in TOML:
- **NOTE: The values of these following flags are just for reference**
- `config.toml` file:
``` ```
chain = "mainnet" chain = "mainnet"
log-level = "info" identity = "myIdentity"
data-dir = "" log-level = "INFO"
sync-mode = "fast" datadir = "/var/lib/bor/data"
gc-mode = "full" keystore = "path/to/keystore"
syncmode = "full"
gcmode = "full"
snapshot = true snapshot = true
ethstats = "" ethstats = ""
whitelist = {}
p2p { [p2p]
max-peers = 30 maxpeers = 30
max-pend-peers = 50 maxpendpeers = 50
bind = "0.0.0.0" bind = "0.0.0.0"
port = 30303 port = 30303
no-discover = false nodiscover = false
nat = "any" nat = "any"
discovery {
v5-enabled = false
bootnodes = []
bootnodesv4 = []
bootnodesv5 = []
staticNodes = []
trustedNodes = []
dns = []
}
}
heimdall { [p2p.discovery]
url = "http://localhost:1317" v5disc = false
without = false bootnodes = ["enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303"]
} bootnodesv4 = []
bootnodesv5 = ["enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2Gxb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNlY3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA", "enr:-KG4QDyytgmE4f7AnvW-ZaUOIi9i79qX4JwjRAiXBZCU65wOfBu-3Nb5I7b_Rmg3KCOcZM_C3y5pg7EBU5XGrcLTduQEhGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQ2_DUbiXNlY3AyNTZrMaEDKnz_-ps3UUOfHWVYaskI5kWYO_vtYMGYCQRAR3gHDouDdGNwgiMog3VkcIIjKA"]
static-nodes = ["enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303"]
trusted-nodes = ["enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303"]
dns = []
txpool { [heimdall]
locals = [] url = "http://localhost:1317"
no-locals = false "bor.without" = false
journal = ""
rejournal = "1h"
price-limit = 1
price-bump = 10
account-slots = 16
global-slots = 4096
account-queue = 64
global-queue = 1024
lifetime = "3h"
}
sealer { [txpool]
enabled = false locals = ["$ADDRESS1", "$ADDRESS2"]
etherbase = "" nolocals = false
gas-ceil = 8000000 journal = ""
extra-data = "" rejournal = "1h0m0s"
} pricelimit = 30000000000
pricebump = 10
accountslots = 16
globalslots = 32768
accountqueue = 16
globalqueue = 32768
lifetime = "3h0m0s"
gpo { [miner]
blocks = 20 mine = false
percentile = 60 etherbase = ""
} extradata = ""
gaslimit = 20000000
gasprice = "30000000000"
jsonrpc { [jsonrpc]
ipc-disable = false ipcdisable = false
ipc-path = "" ipcpath = "/var/lib/bor/bor.ipc"
modules = ["web3", "net"] gascap = 50000000
cors = ["*"] txfeecap = 5e+00
vhost = ["*"]
http {
enabled = false
port = 8545
prefix = ""
host = "localhost"
}
ws { [jsonrpc.http]
enabled = false enabled = false
port = 8546 port = 8545
prefix = "" prefix = ""
host = "localhost" host = "localhost"
} api = ["eth", "net", "web3", "txpool", "bor"]
vhosts = ["*"]
corsdomain = ["*"]
graphqh { [jsonrpc.ws]
enabled = false enabled = false
} port = 8546
} prefix = ""
host = "localhost"
api = ["web3", "net"]
vhosts = ["*"]
corsdomain = ["*"]
telemetry { [jsonrpc.graphql]
enabled = false enabled = false
expensive = false port = 0
prefix = ""
host = ""
api = []
vhosts = ["*"]
corsdomain = ["*"]
influxdb { [gpo]
v1-enabled = false blocks = 20
endpoint = "" percentile = 60
database = "" maxprice = "5000000000000"
username = "" ignoreprice = "2"
password = ""
v2-enabled = false
token = ""
bucket = ""
organization = ""
}
}
cache { [telemetry]
cache = 1024 metrics = false
perc-database = 50 expensive = false
perc-trie = 15 prometheus-addr = ""
perc-gc = 25 opencollector-endpoint = ""
perc-snapshot = 10
journal = "triecache"
rejournal = "60m"
no-prefetch = false
preimages = false
tx-lookup-limit = 2350000
}
accounts { [telemetry.influx]
unlock = [] influxdb = false
password-file = "" endpoint = ""
allow-insecure-unlock = false database = ""
use-lightweight-kdf = false username = ""
} password = ""
influxdbv2 = false
token = ""
bucket = ""
organization = ""
grpc { [cache]
addr = ":3131" cache = 1024
} gc = 25
snapshot = 10
database = 50
trie = 15
journal = "triecache"
rejournal = "1h0m0s"
noprefetch = false
preimages = false
txlookuplimit = 2350000
[accounts]
unlock = ["$ADDRESS1", "$ADDRESS2"]
password = "path/to/password.txt"
allow-insecure-unlock = false
lightkdf = false
disable-bor-wallet = false
[grpc]
addr = ":3131"
[developer]
dev = false
period = 0
``` ```

1
go.mod
View file

@ -84,6 +84,7 @@ require (
require ( require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
github.com/BurntSushi/toml v1.1.0 // indirect
github.com/Masterminds/goutils v1.1.0 // indirect github.com/Masterminds/goutils v1.1.0 // indirect
github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect

3
go.sum
View file

@ -25,6 +25,8 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
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/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d h1:RO27lgfZF8s9lZ3pWyzc0gCE0RZC+6/PXbRjAa0CNp8= github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d h1:RO27lgfZF8s9lZ3pWyzc0gCE0RZC+6/PXbRjAa0CNp8=
@ -461,6 +463,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
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=

View file

@ -82,6 +82,11 @@ func Commands() map[string]MarkDownCommandFactory {
UI: ui, UI: ui,
}, nil }, nil
}, },
"dumpconfig": func() (MarkDownCommand, error) {
return &DumpconfigCommand{
Meta2: meta2,
}, nil
},
"debug": func() (MarkDownCommand, error) { "debug": func() (MarkDownCommand, error) {
return &DebugCommand{ return &DebugCommand{
UI: ui, UI: ui,

View file

@ -0,0 +1,82 @@
package cli
import (
"reflect"
"strings"
"github.com/naoina/toml"
"github.com/ethereum/go-ethereum/internal/cli/server"
)
// These settings ensure that TOML keys use the same names as Go struct fields.
var tomlSettings = toml.Config{
NormFieldName: func(rt reflect.Type, key string) string {
return key
},
FieldToKey: func(rt reflect.Type, field string) string {
return field
},
}
// DumpconfigCommand is for exporting user provided flags into a config file
type DumpconfigCommand struct {
*Meta2
}
// MarkDown implements cli.MarkDown interface
func (p *DumpconfigCommand) MarkDown() string {
items := []string{
"# Dumpconfig",
"The ```bor dumpconfig <your-favourite-flags>``` command will export the user provided flags into a configuration file",
}
return strings.Join(items, "\n\n")
}
// Help implements the cli.Command interface
func (c *DumpconfigCommand) Help() string {
return `Usage: bor dumpconfig <your-favourite-flags>
This command will will export the user provided flags into a configuration file`
}
// Synopsis implements the cli.Command interface
func (c *DumpconfigCommand) Synopsis() string {
return "Export configuration file"
}
// TODO: add flags for file location and format (toml, json, hcl) of the configuration file.
// Run implements the cli.Command interface
func (c *DumpconfigCommand) Run(args []string) int {
// Initialize an empty command instance to get flags
command := server.Command{}
flags := command.Flags()
if err := flags.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
userConfig := command.GetConfig()
// convert the big.Int and time.Duration fields to their corresponding Raw fields
userConfig.TxPool.RejournalRaw = userConfig.TxPool.Rejournal.String()
userConfig.TxPool.LifeTimeRaw = userConfig.TxPool.LifeTime.String()
userConfig.Sealer.GasPriceRaw = userConfig.Sealer.GasPrice.String()
userConfig.Gpo.MaxPriceRaw = userConfig.Gpo.MaxPrice.String()
userConfig.Gpo.IgnorePriceRaw = userConfig.Gpo.IgnorePrice.String()
userConfig.Cache.RejournalRaw = userConfig.Cache.Rejournal.String()
// Currently, the configurations (userConfig) is exported into `toml` file format.
out, err := tomlSettings.Marshal(&userConfig)
if err != nil {
c.UI.Error(err.Error())
return 1
}
c.UI.Output(string(out))
return 0
}

View file

@ -180,14 +180,15 @@ func (b *BigIntFlag) Set(value string) error {
var ok bool var ok bool
if strings.HasPrefix(value, "0x") { if strings.HasPrefix(value, "0x") {
num, ok = num.SetString(value[2:], 16) num, ok = num.SetString(value[2:], 16)
*b.Value = *num
} else { } else {
num, ok = num.SetString(value, 10) num, ok = num.SetString(value, 10)
*b.Value = *num
} }
if !ok { if !ok {
return fmt.Errorf("failed to set big int") return fmt.Errorf("failed to set big int")
} }
b.Value = num
return nil return nil
} }
@ -209,6 +210,19 @@ type SliceStringFlag struct {
Group string Group string
} }
// SplitAndTrim splits input separated by a comma
// and trims excessive white space from the substrings.
func SplitAndTrim(input string) (ret []string) {
l := strings.Split(input, ",")
for _, r := range l {
if r = strings.TrimSpace(r); r != "" {
ret = append(ret, r)
}
}
return ret
}
func (i *SliceStringFlag) String() string { func (i *SliceStringFlag) String() string {
if i.Value == nil { if i.Value == nil {
return "" return ""
@ -219,7 +233,7 @@ func (i *SliceStringFlag) String() string {
func (i *SliceStringFlag) Set(value string) error { func (i *SliceStringFlag) Set(value string) error {
// overwritting insted of appending // overwritting insted of appending
*i.Value = strings.Split(value, ",") *i.Value = SplitAndTrim(value)
return nil return nil
} }

View file

@ -7,8 +7,9 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/ethereum/go-ethereum/log"
"github.com/mitchellh/cli" "github.com/mitchellh/cli"
"github.com/ethereum/go-ethereum/log"
) )
// Command is the command to start the sever // Command is the command to start the sever
@ -21,7 +22,7 @@ type Command struct {
// final configuration // final configuration
config *Config config *Config
configFile []string configFile string
srv *Server srv *Server
} }
@ -50,34 +51,57 @@ func (c *Command) Synopsis() string {
return "Run the Bor server" return "Run the Bor server"
} }
// Run implements the cli.Command interface func (c *Command) extractFlags(args []string) error {
func (c *Command) Run(args []string) int { config := *DefaultConfig()
flags := c.Flags() flags := c.Flags()
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {
c.UI.Error(err.Error()) c.UI.Error(err.Error())
return 1 c.config = &config
return err
} }
// read config file // TODO: Check if this can be removed or not
config := DefaultConfig() // read cli flags
for _, configFile := range c.configFile { if err := config.Merge(c.cliConfig); err != nil {
cfg, err := readConfigFile(configFile) c.UI.Error(err.Error())
c.config = &config
return err
}
// read if config file is provided, this will overwrite the cli flags, if provided
if c.configFile != "" {
log.Warn("Config File provided, this will overwrite the cli flags.", "configFile:", c.configFile)
cfg, err := readConfigFile(c.configFile)
if err != nil { if err != nil {
c.UI.Error(err.Error()) c.UI.Error(err.Error())
return 1 c.config = &config
return err
} }
if err := config.Merge(cfg); err != nil { if err := config.Merge(cfg); err != nil {
c.UI.Error(err.Error()) c.UI.Error(err.Error())
return 1 c.config = &config
return err
} }
} }
if err := config.Merge(c.cliConfig); err != nil {
c.config = &config
return nil
}
// Run implements the cli.Command interface
func (c *Command) Run(args []string) int {
err := c.extractFlags(args)
if err != nil {
c.UI.Error(err.Error()) c.UI.Error(err.Error())
return 1 return 1
} }
c.config = config
srv, err := NewServer(config) srv, err := NewServer(c.config)
if err != nil { if err != nil {
c.UI.Error(err.Error()) c.UI.Error(err.Error())
return 1 return 1
@ -112,3 +136,8 @@ func (c *Command) handleSignals() int {
} }
return 1 return 1
} }
// GetConfig returns the user specified config
func (c *Command) GetConfig() *Config {
return c.cliConfig
}

View file

@ -0,0 +1,50 @@
package server
import (
"math/big"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestFlags(t *testing.T) {
t.Parallel()
var c Command
args := []string{
"--txpool.rejournal", "30m0s",
"--txpool.lifetime", "30m0s",
"--miner.gasprice", "20000000000",
"--gpo.maxprice", "70000000000",
"--gpo.ignoreprice", "1",
"--cache.trie.rejournal", "40m0s",
"--dev",
"--dev.period", "2",
"--datadir", "./data",
"--maxpeers", "30",
"--requiredblocks", "a=b",
"--http.api", "eth,web3,bor",
}
err := c.extractFlags(args)
require.NoError(t, err)
txRe, _ := time.ParseDuration("30m0s")
txLt, _ := time.ParseDuration("30m0s")
caRe, _ := time.ParseDuration("40m0s")
require.Equal(t, c.config.DataDir, "./data")
require.Equal(t, c.config.Developer.Enabled, true)
require.Equal(t, c.config.Developer.Period, uint64(2))
require.Equal(t, c.config.TxPool.Rejournal, txRe)
require.Equal(t, c.config.TxPool.LifeTime, txLt)
require.Equal(t, c.config.Sealer.GasPrice, big.NewInt(20000000000))
require.Equal(t, c.config.Gpo.MaxPrice, big.NewInt(70000000000))
require.Equal(t, c.config.Gpo.IgnorePrice, big.NewInt(1))
require.Equal(t, c.config.Cache.Rejournal, caRe)
require.Equal(t, c.config.P2P.MaxPeers, uint64(30))
require.Equal(t, c.config.RequiredBlocks, map[string]string{"a": "b"})
require.Equal(t, c.config.JsonRPC.Http.API, []string{"eth", "web3", "bor"})
}

View file

@ -14,6 +14,11 @@ import (
godebug "runtime/debug" godebug "runtime/debug"
"github.com/hashicorp/hcl/v2/hclsimple"
"github.com/imdario/mergo"
"github.com/mitchellh/go-homedir"
gopsutil "github.com/shirou/gopsutil/mem"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -28,363 +33,359 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/hashicorp/hcl/v2/hclsimple"
"github.com/imdario/mergo"
"github.com/mitchellh/go-homedir"
gopsutil "github.com/shirou/gopsutil/mem"
) )
type Config struct { type Config struct {
chain *chains.Chain chain *chains.Chain
// Chain is the chain to sync with // Chain is the chain to sync with
Chain string `hcl:"chain,optional"` Chain string `hcl:"chain,optional" toml:"chain,optional"`
// Identity of the node // Identity of the node
Identity string `hcl:"identity,optional"` Identity string `hcl:"identity,optional" toml:"identity,optional"`
// RequiredBlocks is a list of required (block number, hash) pairs to accept // RequiredBlocks is a list of required (block number, hash) pairs to accept
RequiredBlocks map[string]string `hcl:"requiredblocks,optional"` RequiredBlocks map[string]string `hcl:"requiredblocks,optional" toml:"requiredblocks,optional"`
// LogLevel is the level of the logs to put out // LogLevel is the level of the logs to put out
LogLevel string `hcl:"log-level,optional"` LogLevel string `hcl:"log-level,optional" toml:"log-level,optional"`
// DataDir is the directory to store the state in // DataDir is the directory to store the state in
DataDir string `hcl:"data-dir,optional"` DataDir string `hcl:"datadir,optional" toml:"datadir,optional"`
// KeyStoreDir is the directory to store keystores // KeyStoreDir is the directory to store keystores
KeyStoreDir string `hcl:"keystore-dir,optional"` KeyStoreDir string `hcl:"keystore,optional" toml:"keystore,optional"`
// SyncMode selects the sync protocol // SyncMode selects the sync protocol
SyncMode string `hcl:"sync-mode,optional"` SyncMode string `hcl:"syncmode,optional" toml:"syncmode,optional"`
// GcMode selects the garbage collection mode for the trie // GcMode selects the garbage collection mode for the trie
GcMode string `hcl:"gc-mode,optional"` GcMode string `hcl:"gcmode,optional" toml:"gcmode,optional"`
// Snapshot disables/enables the snapshot database mode // Snapshot disables/enables the snapshot database mode
Snapshot bool `hcl:"snapshot,optional"` Snapshot bool `hcl:"snapshot,optional" toml:"snapshot,optional"`
// Ethstats is the address of the ethstats server to send telemetry // Ethstats is the address of the ethstats server to send telemetry
Ethstats string `hcl:"ethstats,optional"` Ethstats string `hcl:"ethstats,optional" toml:"ethstats,optional"`
// P2P has the p2p network related settings // P2P has the p2p network related settings
P2P *P2PConfig `hcl:"p2p,block"` P2P *P2PConfig `hcl:"p2p,block" toml:"p2p,block"`
// Heimdall has the heimdall connection related settings // Heimdall has the heimdall connection related settings
Heimdall *HeimdallConfig `hcl:"heimdall,block"` Heimdall *HeimdallConfig `hcl:"heimdall,block" toml:"heimdall,block"`
// TxPool has the transaction pool related settings // TxPool has the transaction pool related settings
TxPool *TxPoolConfig `hcl:"txpool,block"` TxPool *TxPoolConfig `hcl:"txpool,block" toml:"txpool,block"`
// Sealer has the validator related settings // Sealer has the validator related settings
Sealer *SealerConfig `hcl:"sealer,block"` Sealer *SealerConfig `hcl:"miner,block" toml:"miner,block"`
// JsonRPC has the json-rpc related settings // JsonRPC has the json-rpc related settings
JsonRPC *JsonRPCConfig `hcl:"jsonrpc,block"` JsonRPC *JsonRPCConfig `hcl:"jsonrpc,block" toml:"jsonrpc,block"`
// Gpo has the gas price oracle related settings // Gpo has the gas price oracle related settings
Gpo *GpoConfig `hcl:"gpo,block"` Gpo *GpoConfig `hcl:"gpo,block" toml:"gpo,block"`
// Telemetry has the telemetry related settings // Telemetry has the telemetry related settings
Telemetry *TelemetryConfig `hcl:"telemetry,block"` Telemetry *TelemetryConfig `hcl:"telemetry,block" toml:"telemetry,block"`
// Cache has the cache related settings // Cache has the cache related settings
Cache *CacheConfig `hcl:"cache,block"` Cache *CacheConfig `hcl:"cache,block" toml:"cache,block"`
// Account has the validator account related settings // Account has the validator account related settings
Accounts *AccountsConfig `hcl:"accounts,block"` Accounts *AccountsConfig `hcl:"accounts,block" toml:"accounts,block"`
// GRPC has the grpc server related settings // GRPC has the grpc server related settings
GRPC *GRPCConfig GRPC *GRPCConfig `hcl:"grpc,block" toml:"grpc,block"`
// Developer has the developer mode related settings // Developer has the developer mode related settings
Developer *DeveloperConfig Developer *DeveloperConfig `hcl:"developer,block" toml:"developer,block"`
} }
type P2PConfig struct { type P2PConfig struct {
// MaxPeers sets the maximum number of connected peers // MaxPeers sets the maximum number of connected peers
MaxPeers uint64 `hcl:"max-peers,optional"` MaxPeers uint64 `hcl:"maxpeers,optional" toml:"maxpeers,optional"`
// MaxPendPeers sets the maximum number of pending connected peers // MaxPendPeers sets the maximum number of pending connected peers
MaxPendPeers uint64 `hcl:"max-pend-peers,optional"` MaxPendPeers uint64 `hcl:"maxpendpeers,optional" toml:"maxpendpeers,optional"`
// Bind is the bind address // Bind is the bind address
Bind string `hcl:"bind,optional"` Bind string `hcl:"bind,optional" toml:"bind,optional"`
// Port is the port number // Port is the port number
Port uint64 `hcl:"port,optional"` Port uint64 `hcl:"port,optional" toml:"port,optional"`
// NoDiscover is used to disable discovery // NoDiscover is used to disable discovery
NoDiscover bool `hcl:"no-discover,optional"` NoDiscover bool `hcl:"nodiscover,optional" toml:"nodiscover,optional"`
// NAT it used to set NAT options // NAT it used to set NAT options
NAT string `hcl:"nat,optional"` NAT string `hcl:"nat,optional" toml:"nat,optional"`
// Discovery has the p2p discovery related settings // Discovery has the p2p discovery related settings
Discovery *P2PDiscovery `hcl:"discovery,block"` Discovery *P2PDiscovery `hcl:"discovery,block" toml:"discovery,block"`
} }
type P2PDiscovery struct { type P2PDiscovery struct {
// V5Enabled is used to enable disc v5 discovery mode // V5Enabled is used to enable disc v5 discovery mode
V5Enabled bool `hcl:"v5-enabled,optional"` V5Enabled bool `hcl:"v5disc,optional" toml:"v5disc,optional"`
// Bootnodes is the list of initial bootnodes // Bootnodes is the list of initial bootnodes
Bootnodes []string `hcl:"bootnodes,optional"` Bootnodes []string `hcl:"bootnodes,optional" toml:"bootnodes,optional"`
// BootnodesV4 is the list of initial v4 bootnodes // BootnodesV4 is the list of initial v4 bootnodes
BootnodesV4 []string `hcl:"bootnodesv4,optional"` BootnodesV4 []string `hcl:"bootnodesv4,optional" toml:"bootnodesv4,optional"`
// BootnodesV5 is the list of initial v5 bootnodes // BootnodesV5 is the list of initial v5 bootnodes
BootnodesV5 []string `hcl:"bootnodesv5,optional"` BootnodesV5 []string `hcl:"bootnodesv5,optional" toml:"bootnodesv5,optional"`
// StaticNodes is the list of static nodes // StaticNodes is the list of static nodes
StaticNodes []string `hcl:"static-nodes,optional"` StaticNodes []string `hcl:"static-nodes,optional" toml:"static-nodes,optional"`
// TrustedNodes is the list of trusted nodes // TrustedNodes is the list of trusted nodes
TrustedNodes []string `hcl:"trusted-nodes,optional"` TrustedNodes []string `hcl:"trusted-nodes,optional" toml:"trusted-nodes,optional"`
// DNS is the list of enrtree:// URLs which will be queried for nodes to connect to // DNS is the list of enrtree:// URLs which will be queried for nodes to connect to
DNS []string `hcl:"dns,optional"` DNS []string `hcl:"dns,optional" toml:"dns,optional"`
} }
type HeimdallConfig struct { type HeimdallConfig struct {
// URL is the url of the heimdall server // URL is the url of the heimdall server
URL string `hcl:"url,optional"` URL string `hcl:"url,optional" toml:"url,optional"`
// Without is used to disable remote heimdall during testing // Without is used to disable remote heimdall during testing
Without bool `hcl:"without,optional"` Without bool `hcl:"bor.without,optional" toml:"bor.without,optional"`
// GRPCAddress is the address of the heimdall grpc server // GRPCAddress is the address of the heimdall grpc server
GRPCAddress string `hcl:"grpc-address,optional"` GRPCAddress string `hcl:"grpc-address,optional" toml:"grpc-address,optional"`
} }
type TxPoolConfig struct { type TxPoolConfig struct {
// Locals are the addresses that should be treated by default as local // Locals are the addresses that should be treated by default as local
Locals []string `hcl:"locals,optional"` Locals []string `hcl:"locals,optional" toml:"locals,optional"`
// NoLocals enables whether local transaction handling should be disabled // NoLocals enables whether local transaction handling should be disabled
NoLocals bool `hcl:"no-locals,optional"` NoLocals bool `hcl:"nolocals,optional" toml:"nolocals,optional"`
// Journal is the path to store local transactions to survive node restarts // Journal is the path to store local transactions to survive node restarts
Journal string `hcl:"journal,optional"` Journal string `hcl:"journal,optional" toml:"journal,optional"`
// Rejournal is the time interval to regenerate the local transaction journal // Rejournal is the time interval to regenerate the local transaction journal
Rejournal time.Duration Rejournal time.Duration `hcl:"-,optional" toml:"-,optional"`
RejournalRaw string `hcl:"rejournal,optional"` RejournalRaw string `hcl:"rejournal,optional" toml:"rejournal,optional"`
// PriceLimit is the minimum gas price to enforce for acceptance into the pool // PriceLimit is the minimum gas price to enforce for acceptance into the pool
PriceLimit uint64 `hcl:"price-limit,optional"` PriceLimit uint64 `hcl:"pricelimit,optional" toml:"pricelimit,optional"`
// PriceBump is the minimum price bump percentage to replace an already existing transaction (nonce) // PriceBump is the minimum price bump percentage to replace an already existing transaction (nonce)
PriceBump uint64 `hcl:"price-bump,optional"` PriceBump uint64 `hcl:"pricebump,optional" toml:"pricebump,optional"`
// AccountSlots is the number of executable transaction slots guaranteed per account // AccountSlots is the number of executable transaction slots guaranteed per account
AccountSlots uint64 `hcl:"account-slots,optional"` AccountSlots uint64 `hcl:"accountslots,optional" toml:"accountslots,optional"`
// GlobalSlots is the maximum number of executable transaction slots for all accounts // GlobalSlots is the maximum number of executable transaction slots for all accounts
GlobalSlots uint64 `hcl:"global-slots,optional"` GlobalSlots uint64 `hcl:"globalslots,optional" toml:"globalslots,optional"`
// AccountQueue is the maximum number of non-executable transaction slots permitted per account // AccountQueue is the maximum number of non-executable transaction slots permitted per account
AccountQueue uint64 `hcl:"account-queue,optional"` AccountQueue uint64 `hcl:"accountqueue,optional" toml:"accountqueue,optional"`
// GlobalQueueis the maximum number of non-executable transaction slots for all accounts // GlobalQueueis the maximum number of non-executable transaction slots for all accounts
GlobalQueue uint64 `hcl:"global-queue,optional"` GlobalQueue uint64 `hcl:"globalqueue,optional" toml:"globalqueue,optional"`
// Lifetime is the maximum amount of time non-executable transaction are queued // lifetime is the maximum amount of time non-executable transaction are queued
LifeTime time.Duration LifeTime time.Duration `hcl:"-,optional" toml:"-,optional"`
LifeTimeRaw string `hcl:"lifetime,optional"` LifeTimeRaw string `hcl:"lifetime,optional" toml:"lifetime,optional"`
} }
type SealerConfig struct { type SealerConfig struct {
// Enabled is used to enable validator mode // Enabled is used to enable validator mode
Enabled bool `hcl:"enabled,optional"` Enabled bool `hcl:"mine,optional" toml:"mine,optional"`
// Etherbase is the address of the validator // Etherbase is the address of the validator
Etherbase string `hcl:"etherbase,optional"` Etherbase string `hcl:"etherbase,optional" toml:"etherbase,optional"`
// ExtraData is the block extra data set by the miner // ExtraData is the block extra data set by the miner
ExtraData string `hcl:"extra-data,optional"` ExtraData string `hcl:"extradata,optional" toml:"extradata,optional"`
// GasCeil is the target gas ceiling for mined blocks. // GasCeil is the target gas ceiling for mined blocks.
GasCeil uint64 `hcl:"gas-ceil,optional"` GasCeil uint64 `hcl:"gaslimit,optional" toml:"gaslimit,optional"`
// GasPrice is the minimum gas price for mining a transaction // GasPrice is the minimum gas price for mining a transaction
GasPrice *big.Int GasPrice *big.Int `hcl:"-,optional" toml:"-,optional"`
GasPriceRaw string `hcl:"gas-price,optional"` GasPriceRaw string `hcl:"gasprice,optional" toml:"gasprice,optional"`
} }
type JsonRPCConfig struct { type JsonRPCConfig struct {
// IPCDisable enables whether ipc is enabled or not // IPCDisable enables whether ipc is enabled or not
IPCDisable bool `hcl:"ipc-disable,optional"` IPCDisable bool `hcl:"ipcdisable,optional" toml:"ipcdisable,optional"`
// IPCPath is the path of the ipc endpoint // IPCPath is the path of the ipc endpoint
IPCPath string `hcl:"ipc-path,optional"` IPCPath string `hcl:"ipcpath,optional" toml:"ipcpath,optional"`
// GasCap is the global gas cap for eth-call variants. // GasCap is the global gas cap for eth-call variants.
GasCap uint64 `hcl:"gas-cap,optional"` GasCap uint64 `hcl:"gascap,optional" toml:"gascap,optional"`
// TxFeeCap is the global transaction fee cap for send-transaction variants // TxFeeCap is the global transaction fee cap for send-transaction variants
TxFeeCap float64 `hcl:"tx-fee-cap,optional"` TxFeeCap float64 `hcl:"txfeecap,optional" toml:"txfeecap,optional"`
// Http has the json-rpc http related settings // Http has the json-rpc http related settings
Http *APIConfig `hcl:"http,block"` Http *APIConfig `hcl:"http,block" toml:"http,block"`
// Ws has the json-rpc websocket related settings // Ws has the json-rpc websocket related settings
Ws *APIConfig `hcl:"ws,block"` Ws *APIConfig `hcl:"ws,block" toml:"ws,block"`
// Graphql has the json-rpc graphql related settings // Graphql has the json-rpc graphql related settings
Graphql *APIConfig `hcl:"graphql,block"` Graphql *APIConfig `hcl:"graphql,block" toml:"graphql,block"`
} }
type GRPCConfig struct { type GRPCConfig struct {
// Addr is the bind address for the grpc rpc server // Addr is the bind address for the grpc rpc server
Addr string Addr string `hcl:"addr,optional" toml:"addr,optional"`
} }
type APIConfig struct { type APIConfig struct {
// Enabled selects whether the api is enabled // Enabled selects whether the api is enabled
Enabled bool `hcl:"enabled,optional"` Enabled bool `hcl:"enabled,optional" toml:"enabled,optional"`
// Port is the port number for this api // Port is the port number for this api
Port uint64 `hcl:"port,optional"` Port uint64 `hcl:"port,optional" toml:"port,optional"`
// Prefix is the http prefix to expose this api // Prefix is the http prefix to expose this api
Prefix string `hcl:"prefix,optional"` Prefix string `hcl:"prefix,optional" toml:"prefix,optional"`
// Host is the address to bind the api // Host is the address to bind the api
Host string `hcl:"host,optional"` Host string `hcl:"host,optional" toml:"host,optional"`
// Modules is the list of enabled api modules // API is the list of enabled api modules
API []string `hcl:"modules,optional"` API []string `hcl:"api,optional" toml:"api,optional"`
// VHost is the list of valid virtual hosts // VHost is the list of valid virtual hosts
VHost []string `hcl:"vhost,optional"` VHost []string `hcl:"vhosts,optional" toml:"vhosts,optional"`
// Cors is the list of Cors endpoints // Cors is the list of Cors endpoints
Cors []string `hcl:"cors,optional"` Cors []string `hcl:"corsdomain,optional" toml:"corsdomain,optional"`
} }
type GpoConfig struct { type GpoConfig struct {
// Blocks is the number of blocks to track to compute the price oracle // Blocks is the number of blocks to track to compute the price oracle
Blocks uint64 `hcl:"blocks,optional"` Blocks uint64 `hcl:"blocks,optional" toml:"blocks,optional"`
// Percentile sets the weights to new blocks // Percentile sets the weights to new blocks
Percentile uint64 `hcl:"percentile,optional"` Percentile uint64 `hcl:"percentile,optional" toml:"percentile,optional"`
// MaxPrice is an upper bound gas price // MaxPrice is an upper bound gas price
MaxPrice *big.Int MaxPrice *big.Int `hcl:"-,optional" toml:"-,optional"`
MaxPriceRaw string `hcl:"max-price,optional"` MaxPriceRaw string `hcl:"maxprice,optional" toml:"maxprice,optional"`
// IgnorePrice is a lower bound gas price // IgnorePrice is a lower bound gas price
IgnorePrice *big.Int IgnorePrice *big.Int `hcl:"-,optional" toml:"-,optional"`
IgnorePriceRaw string `hcl:"ignore-price,optional"` IgnorePriceRaw string `hcl:"ignoreprice,optional" toml:"ignoreprice,optional"`
} }
type TelemetryConfig struct { type TelemetryConfig struct {
// Enabled enables metrics // Enabled enables metrics
Enabled bool `hcl:"enabled,optional"` Enabled bool `hcl:"metrics,optional" toml:"metrics,optional"`
// Expensive enables expensive metrics // Expensive enables expensive metrics
Expensive bool `hcl:"expensive,optional"` Expensive bool `hcl:"expensive,optional" toml:"expensive,optional"`
// InfluxDB has the influxdb related settings // InfluxDB has the influxdb related settings
InfluxDB *InfluxDBConfig `hcl:"influx,block"` InfluxDB *InfluxDBConfig `hcl:"influx,block" toml:"influx,block"`
// Prometheus Address // Prometheus Address
PrometheusAddr string `hcl:"prometheus-addr,optional"` PrometheusAddr string `hcl:"prometheus-addr,optional" toml:"prometheus-addr,optional"`
// Open collector endpoint // Open collector endpoint
OpenCollectorEndpoint string `hcl:"opencollector-endpoint,optional"` OpenCollectorEndpoint string `hcl:"opencollector-endpoint,optional" toml:"opencollector-endpoint,optional"`
} }
type InfluxDBConfig struct { type InfluxDBConfig struct {
// V1Enabled enables influx v1 mode // V1Enabled enables influx v1 mode
V1Enabled bool `hcl:"v1-enabled,optional"` V1Enabled bool `hcl:"influxdb,optional" toml:"influxdb,optional"`
// Endpoint is the url endpoint of the influxdb service // Endpoint is the url endpoint of the influxdb service
Endpoint string `hcl:"endpoint,optional"` Endpoint string `hcl:"endpoint,optional" toml:"endpoint,optional"`
// Database is the name of the database in Influxdb to store the metrics. // Database is the name of the database in Influxdb to store the metrics.
Database string `hcl:"database,optional"` Database string `hcl:"database,optional" toml:"database,optional"`
// Enabled is the username to authorize access to Influxdb // Enabled is the username to authorize access to Influxdb
Username string `hcl:"username,optional"` Username string `hcl:"username,optional" toml:"username,optional"`
// Password is the password to authorize access to Influxdb // Password is the password to authorize access to Influxdb
Password string `hcl:"password,optional"` Password string `hcl:"password,optional" toml:"password,optional"`
// Tags are tags attaches to all generated metrics // Tags are tags attaches to all generated metrics
Tags map[string]string `hcl:"tags,optional"` Tags map[string]string `hcl:"tags,optional" toml:"tags,optional"`
// Enabled enables influx v2 mode // Enabled enables influx v2 mode
V2Enabled bool `hcl:"v2-enabled,optional"` V2Enabled bool `hcl:"influxdbv2,optional" toml:"influxdbv2,optional"`
// Token is the token to authorize access to Influxdb V2. // Token is the token to authorize access to Influxdb V2.
Token string `hcl:"token,optional"` Token string `hcl:"token,optional" toml:"token,optional"`
// Bucket is the bucket to store metrics in Influxdb V2. // Bucket is the bucket to store metrics in Influxdb V2.
Bucket string `hcl:"bucket,optional"` Bucket string `hcl:"bucket,optional" toml:"bucket,optional"`
// Organization is the name of the organization for Influxdb V2. // Organization is the name of the organization for Influxdb V2.
Organization string `hcl:"organization,optional"` Organization string `hcl:"organization,optional" toml:"organization,optional"`
} }
type CacheConfig struct { type CacheConfig struct {
// Cache is the amount of cache of the node // Cache is the amount of cache of the node
Cache uint64 `hcl:"cache,optional"` Cache uint64 `hcl:"cache,optional" toml:"cache,optional"`
// PercGc is percentage of cache used for garbage collection // PercGc is percentage of cache used for garbage collection
PercGc uint64 `hcl:"perc-gc,optional"` PercGc uint64 `hcl:"gc,optional" toml:"gc,optional"`
// PercSnapshot is percentage of cache used for snapshots // PercSnapshot is percentage of cache used for snapshots
PercSnapshot uint64 `hcl:"perc-snapshot,optional"` PercSnapshot uint64 `hcl:"snapshot,optional" toml:"snapshot,optional"`
// PercDatabase is percentage of cache used for the database // PercDatabase is percentage of cache used for the database
PercDatabase uint64 `hcl:"perc-database,optional"` PercDatabase uint64 `hcl:"database,optional" toml:"database,optional"`
// PercTrie is percentage of cache used for the trie // PercTrie is percentage of cache used for the trie
PercTrie uint64 `hcl:"perc-trie,optional"` PercTrie uint64 `hcl:"trie,optional" toml:"trie,optional"`
// Journal is the disk journal directory for trie cache to survive node restarts // Journal is the disk journal directory for trie cache to survive node restarts
Journal string `hcl:"journal,optional"` Journal string `hcl:"journal,optional" toml:"journal,optional"`
// Rejournal is the time interval to regenerate the journal for clean cache // Rejournal is the time interval to regenerate the journal for clean cache
Rejournal time.Duration Rejournal time.Duration `hcl:"-,optional" toml:"-,optional"`
RejournalRaw string `hcl:"rejournal,optional"` RejournalRaw string `hcl:"rejournal,optional" toml:"rejournal,optional"`
// NoPrefetch is used to disable prefetch of tries // NoPrefetch is used to disable prefetch of tries
NoPrefetch bool `hcl:"no-prefetch,optional"` NoPrefetch bool `hcl:"noprefetch,optional" toml:"noprefetch,optional"`
// Preimages is used to enable the track of hash preimages // Preimages is used to enable the track of hash preimages
Preimages bool `hcl:"preimages,optional"` Preimages bool `hcl:"preimages,optional" toml:"preimages,optional"`
// TxLookupLimit sets the maximum number of blocks from head whose tx indices are reserved. // TxLookupLimit sets the maximum number of blocks from head whose tx indices are reserved.
TxLookupLimit uint64 `hcl:"tx-lookup-limit,optional"` TxLookupLimit uint64 `hcl:"txlookuplimit,optional" toml:"txlookuplimit,optional"`
} }
type AccountsConfig struct { type AccountsConfig struct {
// Unlock is the list of addresses to unlock in the node // Unlock is the list of addresses to unlock in the node
Unlock []string `hcl:"unlock,optional"` Unlock []string `hcl:"unlock,optional" toml:"unlock,optional"`
// PasswordFile is the file where the account passwords are stored // PasswordFile is the file where the account passwords are stored
PasswordFile string `hcl:"password-file,optional"` PasswordFile string `hcl:"password,optional" toml:"password,optional"`
// AllowInsecureUnlock allows user to unlock accounts in unsafe http environment. // AllowInsecureUnlock allows user to unlock accounts in unsafe http environment.
AllowInsecureUnlock bool `hcl:"allow-insecure-unlock,optional"` AllowInsecureUnlock bool `hcl:"allow-insecure-unlock,optional" toml:"allow-insecure-unlock,optional"`
// UseLightweightKDF enables a faster but less secure encryption of accounts // UseLightweightKDF enables a faster but less secure encryption of accounts
UseLightweightKDF bool `hcl:"use-lightweight-kdf,optional"` UseLightweightKDF bool `hcl:"lightkdf,optional" toml:"lightkdf,optional"`
// DisableBorWallet disables the personal wallet endpoints // DisableBorWallet disables the personal wallet endpoints
DisableBorWallet bool `hcl:"disable-bor-wallet,optional"` DisableBorWallet bool `hcl:"disable-bor-wallet,optional" toml:"disable-bor-wallet,optional"`
} }
type DeveloperConfig struct { type DeveloperConfig struct {
// Enabled enables the developer mode // Enabled enables the developer mode
Enabled bool `hcl:"dev,optional"` Enabled bool `hcl:"dev,optional" toml:"dev,optional"`
// Period is the block period to use in developer mode // Period is the block period to use in developer mode
Period uint64 `hcl:"period,optional"` Period uint64 `hcl:"period,optional" toml:"period,optional"`
} }
func DefaultConfig() *Config { func DefaultConfig() *Config {
@ -423,14 +424,14 @@ func DefaultConfig() *Config {
Locals: []string{}, Locals: []string{},
NoLocals: false, NoLocals: false,
Journal: "", Journal: "",
Rejournal: time.Duration(1 * time.Hour), Rejournal: 1 * time.Hour,
PriceLimit: 30000000000, PriceLimit: 30000000000,
PriceBump: 10, PriceBump: 10,
AccountSlots: 16, AccountSlots: 16,
GlobalSlots: 32768, GlobalSlots: 32768,
AccountQueue: 16, AccountQueue: 16,
GlobalQueue: 32768, GlobalQueue: 32768,
LifeTime: time.Duration(3 * time.Hour), LifeTime: 3 * time.Hour,
}, },
Sealer: &SealerConfig{ Sealer: &SealerConfig{
Enabled: false, Enabled: false,
@ -530,7 +531,7 @@ func (c *Config) fillBigInt() error {
}{ }{
{"gpo.maxprice", &c.Gpo.MaxPrice, &c.Gpo.MaxPriceRaw}, {"gpo.maxprice", &c.Gpo.MaxPrice, &c.Gpo.MaxPriceRaw},
{"gpo.ignoreprice", &c.Gpo.IgnorePrice, &c.Gpo.IgnorePriceRaw}, {"gpo.ignoreprice", &c.Gpo.IgnorePrice, &c.Gpo.IgnorePriceRaw},
{"sealer.gasprice", &c.Sealer.GasPrice, &c.Sealer.GasPriceRaw}, {"miner.gasprice", &c.Sealer.GasPrice, &c.Sealer.GasPriceRaw},
} }
for _, x := range tds { for _, x := range tds {
@ -586,13 +587,7 @@ func (c *Config) fillTimeDurations() error {
func readConfigFile(path string) (*Config, error) { func readConfigFile(path string) (*Config, error) {
ext := filepath.Ext(path) ext := filepath.Ext(path)
if ext == ".toml" { if ext == ".toml" {
// read file and apply the legacy config return readLegacyConfig(path)
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return readLegacyConfig(data)
} }
config := &Config{ config := &Config{
@ -1081,7 +1076,7 @@ func Hostname() string {
func MakePasswordListFromFile(path string) ([]string, error) { func MakePasswordListFromFile(path string) ([]string, error) {
text, err := ioutil.ReadFile(path) text, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to read password file: %v", err) return nil, fmt.Errorf("failed to read password file: %v", err)
} }
lines := strings.Split(string(text), "\n") lines := strings.Split(string(text), "\n")

View file

@ -1,33 +1,33 @@
package server package server
import ( import (
"bytes" "fmt"
"io/ioutil"
"github.com/naoina/toml" "github.com/BurntSushi/toml"
) )
type legacyConfig struct { func readLegacyConfig(path string) (*Config, error) {
Node struct { data, err := ioutil.ReadFile(path)
P2P struct { tomlData := string(data)
StaticNodes []string
TrustedNodes []string if err != nil {
} return nil, fmt.Errorf("failed to read toml config file: %v", err)
} }
}
func (l *legacyConfig) Config() *Config { var conf 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) { if _, err := toml.Decode(tomlData, &conf); err != nil {
var legacy legacyConfig return nil, fmt.Errorf("failed to decode toml config file: %v", err)
}
r := toml.NewDecoder(bytes.NewReader(data)) if err := conf.fillBigInt(); err != nil {
if err := r.Decode(&legacy); err != nil {
return nil, err return nil, err
} }
return legacy.Config(), nil
if err := conf.fillTimeDurations(); err != nil {
return nil, err
}
return &conf, nil
} }

View file

@ -1,21 +1,50 @@
package server package server
import ( import (
"math/big"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestConfigLegacy(t *testing.T) { func TestConfigLegacy(t *testing.T) {
toml := `[Node.P2P]
StaticNodes = ["node1"]
TrustedNodes = ["node2"]`
config, err := readLegacyConfig([]byte(toml)) readFile := func(path string) {
if err != nil { config, err := readLegacyConfig(path)
t.Fatal(err) assert.NoError(t, err)
assert.Equal(t, config, &Config{
DataDir: "./data",
RequiredBlocks: map[string]string{
"a": "b",
},
P2P: &P2PConfig{
MaxPeers: 30,
},
TxPool: &TxPoolConfig{
Locals: []string{},
Rejournal: 1 * time.Hour,
LifeTime: 1 * time.Second,
},
Gpo: &GpoConfig{
MaxPrice: big.NewInt(100),
IgnorePrice: big.NewInt(2),
},
Sealer: &SealerConfig{
Enabled: false,
GasCeil: 20000000,
GasPrice: big.NewInt(30000000000),
},
Cache: &CacheConfig{
Cache: 1024,
Rejournal: 1 * time.Hour,
},
})
} }
assert.Equal(t, config.P2P.Discovery.StaticNodes, []string{"node1"}) // read file in hcl format
assert.Equal(t, config.P2P.Discovery.TrustedNodes, []string{"node2"}) t.Run("toml", func(t *testing.T) {
readFile("./testdata/test.toml")
})
} }

View file

@ -115,7 +115,7 @@ func TestConfigLoadFile(t *testing.T) {
MaxPeers: 30, MaxPeers: 30,
}, },
TxPool: &TxPoolConfig{ TxPool: &TxPoolConfig{
LifeTime: time.Duration(1 * time.Second), LifeTime: 1 * time.Second,
}, },
Gpo: &GpoConfig{ Gpo: &GpoConfig{
MaxPrice: big.NewInt(100), MaxPrice: big.NewInt(100),
@ -127,12 +127,12 @@ func TestConfigLoadFile(t *testing.T) {
// read file in hcl format // read file in hcl format
t.Run("hcl", func(t *testing.T) { t.Run("hcl", func(t *testing.T) {
readFile("./testdata/simple.hcl") readFile("./testdata/test.hcl")
}) })
// read file in json format // read file in json format
t.Run("json", func(t *testing.T) { t.Run("json", func(t *testing.T) {
readFile("./testdata/simple.json") readFile("./testdata/test.json")
}) })
} }

View file

@ -38,7 +38,7 @@ func (c *Command) Flags() *flagset.Flagset {
Usage: "Path of the directory to store keystores", Usage: "Path of the directory to store keystores",
Value: &c.cliConfig.KeyStoreDir, Value: &c.cliConfig.KeyStoreDir,
}) })
f.SliceStringFlag(&flagset.SliceStringFlag{ f.StringFlag(&flagset.StringFlag{
Name: "config", Name: "config",
Usage: "File for the config file", Usage: "File for the config file",
Value: &c.configFile, Value: &c.configFile,

View file

@ -7,11 +7,12 @@
package proto package proto
import ( import (
reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb" emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
) )
const ( const (

View file

@ -8,6 +8,7 @@ package proto
import ( import (
context "context" context "context"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes" codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status" status "google.golang.org/grpc/status"

View file

@ -4,8 +4,9 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
) )
func TestGatherBlocks(t *testing.T) { func TestGatherBlocks(t *testing.T) {

View file

@ -1,15 +0,0 @@
{
"data-dir": "./data",
"requiredblocks": {
"a": "b"
},
"p2p": {
"max-peers": 30
},
"txpool": {
"lifetime": "1s"
},
"gpo": {
"max-price": "100"
}
}

View file

@ -1,11 +1,11 @@
data-dir = "./data" datadir = "./data"
requiredblocks = { requiredblocks = {
a = "b" a = "b"
} }
p2p { p2p {
max-peers = 30 maxpeers = 30
} }
txpool { txpool {
@ -13,5 +13,5 @@ txpool {
} }
gpo { gpo {
max-price = "100" maxprice = "100"
} }

15
internal/cli/server/testdata/test.json vendored Normal file
View file

@ -0,0 +1,15 @@
{
"datadir": "./data",
"requiredblocks": {
"a": "b"
},
"p2p": {
"maxpeers": 30
},
"txpool": {
"lifetime": "1s"
},
"gpo": {
"maxprice": "100"
}
}

25
internal/cli/server/testdata/test.toml vendored Normal file
View file

@ -0,0 +1,25 @@
datadir = "./data"
[requiredblocks]
a = "b"
[p2p]
maxpeers = 30
[txpool]
locals = []
rejournal = "1h0m0s"
lifetime = "1s"
[miner]
mine = false
gaslimit = 20000000
gasprice = "30000000000"
[gpo]
maxprice = "100"
ignoreprice = "2"
[cache]
cache = 1024
rejournal = "1h0m0s"