From c50ff82ab1495620eded53f4994960956d1a15cc Mon Sep 17 00:00:00 2001 From: Jerry Date: Mon, 25 Jul 2022 10:17:22 -0700 Subject: [PATCH 1/2] Fix "Signer 0x... is not a part of the producer set at block xxxx" The validator set json loaded from database will have an empty map. This change will recompute the validator map based on validator set. --- consensus/bor/snapshot.go | 2 ++ consensus/bor/valset/validator_set.go | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go index c95031e783..264436397f 100644 --- a/consensus/bor/snapshot.go +++ b/consensus/bor/snapshot.go @@ -59,6 +59,8 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat return nil, err } + snap.ValidatorSet.UpdateValidatorMap() + snap.config = config snap.sigcache = sigcache diff --git a/consensus/bor/valset/validator_set.go b/consensus/bor/valset/validator_set.go index 772d2c5ef8..0a6f7c4487 100644 --- a/consensus/bor/valset/validator_set.go +++ b/consensus/bor/valset/validator_set.go @@ -628,6 +628,10 @@ func (vals *ValidatorSet) updateValidators(updates []*Validator, deletes []*Vali vals.applyUpdates(updates) vals.applyRemovals(deletes) + vals.UpdateValidatorMap() +} + +func (vals *ValidatorSet) UpdateValidatorMap() { vals.validatorsMap = make(map[common.Address]int, len(vals.Validators)) for i, val := range vals.Validators { From 71980bf5b189ec4a4a992d093938a67214ea771b Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Wed, 27 Jul 2022 12:28:26 +0530 Subject: [PATCH 2/2] internal/cli: use config file for flags in new-cli, builder/files: update defaults (#457) * updated simple.json and simple.hcl * added annotations for developer and grpc block * added toml tags and simple.toml file * added support for toml config files * updated simple files toml, hcl, json * added config.toml in builder/files and updated bor.service * add dumpconfig command in cli for exporting configs * update docs * updated .goreleaser.yml (POS-651) * changed --config to -config * added test config for tests and fixed lint errors * made fields of type big.int and time.Duration private, removed merge from dumpconfig, setting up default values to the Raw fields in dumpconfig, and fixed one lint error * fixed lint errors (strange) * lint fix * private no-more, using '-' in name tags to ignore * updated name tags, made c.configFile as a stringFlag (only one config file supported) and updated the merge logic in command.go -> Run() * fix: set method for big.Int flags, added a TODO * handeled bigInt and timeDuration type, bug fix in config_legacy, lint fix * updated flags, consistent across flags.go and config.go * fixed config test and updated test hcl, json config files * updated config legacy test * added test to check values of cmd flags, restructured Run in command.go, linter fix * fix linters * lint again * changed 2 flags and assert -> require * changed the 2 flags back * updated correct congig.toml path and made mainnet default * updated config.toml with new flags * added sample config (toml) file * removed sample-config.toml and added it in docs/config.md Co-authored-by: Manav Darji --- .goreleaser.yml | 3 + builder/files/bor.service | 29 +- builder/files/config.toml | 44 ++++ docs/cli/README.md | 2 + docs/cli/dumpconfig.md | 3 + docs/config.md | 235 +++++++++-------- go.mod | 1 + go.sum | 3 + internal/cli/command.go | 5 + internal/cli/dumpconfig.go | 82 ++++++ internal/cli/flagset/flagset.go | 18 +- internal/cli/server/command.go | 57 +++- internal/cli/server/command_test.go | 50 ++++ internal/cli/server/config.go | 249 +++++++++--------- internal/cli/server/config_legacy.go | 40 +-- internal/cli/server/config_legacy_test.go | 45 +++- internal/cli/server/config_test.go | 6 +- internal/cli/server/flags.go | 2 +- internal/cli/server/proto/server.pb.go | 5 +- internal/cli/server/proto/server_grpc.pb.go | 1 + internal/cli/server/service_test.go | 3 +- internal/cli/server/testdata/simple.json | 15 -- .../server/testdata/{simple.hcl => test.hcl} | 8 +- internal/cli/server/testdata/test.json | 15 ++ internal/cli/server/testdata/test.toml | 25 ++ 25 files changed, 609 insertions(+), 337 deletions(-) create mode 100644 builder/files/config.toml create mode 100644 docs/cli/dumpconfig.md create mode 100644 internal/cli/dumpconfig.go create mode 100644 internal/cli/server/command_test.go delete mode 100644 internal/cli/server/testdata/simple.json rename internal/cli/server/testdata/{simple.hcl => test.hcl} (57%) create mode 100644 internal/cli/server/testdata/test.json create mode 100644 internal/cli/server/testdata/test.toml diff --git a/.goreleaser.yml b/.goreleaser.yml index d09cc43206..7fbc61ca4a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -90,6 +90,9 @@ nfpms: - src: builder/files/genesis-testnet-v4.json dst: /etc/bor/genesis-testnet-v4.json type: config + - src: builder/files/config.toml + dst: /var/lib/bor/config.toml + type: config overrides: rpm: diff --git a/builder/files/bor.service b/builder/files/bor.service index da0338368c..4b628cbf6e 100644 --- a/builder/files/bor.service +++ b/builder/files/bor.service @@ -6,34 +6,7 @@ [Service] Restart=on-failure RestartSec=5s - ExecStart=/usr/local/bin/bor server \ - --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 + ExecStart=/usr/local/bin/bor server -config="/var/lib/bor/config.toml" Type=simple User=ubuntu KillSignal=SIGINT diff --git a/builder/files/config.toml b/builder/files/config.toml new file mode 100644 index 0000000000..c55a143ed7 --- /dev/null +++ b/builder/files/config.toml @@ -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"] \ No newline at end of file diff --git a/docs/cli/README.md b/docs/cli/README.md index d92a7b5a05..3bc3daddc5 100644 --- a/docs/cli/README.md +++ b/docs/cli/README.md @@ -26,6 +26,8 @@ - [```debug pprof```](./debug_pprof.md) +- [```dumpconfig```](./dumpconfig.md) + - [```fingerprint```](./fingerprint.md) - [```peers```](./peers.md) diff --git a/docs/cli/dumpconfig.md b/docs/cli/dumpconfig.md new file mode 100644 index 0000000000..0383c47310 --- /dev/null +++ b/docs/cli/dumpconfig.md @@ -0,0 +1,3 @@ +# Dumpconfig + +The ```bor dumpconfig ``` command will export the user provided flags into a configuration file \ No newline at end of file diff --git a/docs/config.md b/docs/config.md index 4f4dec157b..196a0bf388 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,133 +1,144 @@ # Config -Toml files format used in geth are being deprecated. - -Bor uses uses JSON and [HCL](https://github.com/hashicorp/hcl) formats to create configuration files. This is the format in HCL alongside the default values: - +- 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. + - 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" -log-level = "info" -data-dir = "" -sync-mode = "fast" -gc-mode = "full" +identity = "myIdentity" +log-level = "INFO" +datadir = "/var/lib/bor/data" +keystore = "path/to/keystore" +syncmode = "full" +gcmode = "full" snapshot = true ethstats = "" -whitelist = {} -p2p { - max-peers = 30 - max-pend-peers = 50 - bind = "0.0.0.0" - port = 30303 - no-discover = false - nat = "any" - discovery { - v5-enabled = false - bootnodes = [] - bootnodesv4 = [] - bootnodesv5 = [] - staticNodes = [] - trustedNodes = [] - dns = [] - } -} +[p2p] +maxpeers = 30 +maxpendpeers = 50 +bind = "0.0.0.0" +port = 30303 +nodiscover = false +nat = "any" -heimdall { - url = "http://localhost:1317" - without = false -} +[p2p.discovery] +v5disc = 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 { - locals = [] - no-locals = false - journal = "" - rejournal = "1h" - price-limit = 1 - price-bump = 10 - account-slots = 16 - global-slots = 4096 - account-queue = 64 - global-queue = 1024 - lifetime = "3h" -} +[heimdall] +url = "http://localhost:1317" +"bor.without" = false -sealer { - enabled = false - etherbase = "" - gas-ceil = 8000000 - extra-data = "" -} +[txpool] +locals = ["$ADDRESS1", "$ADDRESS2"] +nolocals = false +journal = "" +rejournal = "1h0m0s" +pricelimit = 30000000000 +pricebump = 10 +accountslots = 16 +globalslots = 32768 +accountqueue = 16 +globalqueue = 32768 +lifetime = "3h0m0s" -gpo { - blocks = 20 - percentile = 60 -} +[miner] +mine = false +etherbase = "" +extradata = "" +gaslimit = 20000000 +gasprice = "30000000000" -jsonrpc { - ipc-disable = false - ipc-path = "" - modules = ["web3", "net"] - cors = ["*"] - vhost = ["*"] - - http { - enabled = false - port = 8545 - prefix = "" - host = "localhost" - } +[jsonrpc] +ipcdisable = false +ipcpath = "/var/lib/bor/bor.ipc" +gascap = 50000000 +txfeecap = 5e+00 - ws { - enabled = false - port = 8546 - prefix = "" - host = "localhost" - } +[jsonrpc.http] +enabled = false +port = 8545 +prefix = "" +host = "localhost" +api = ["eth", "net", "web3", "txpool", "bor"] +vhosts = ["*"] +corsdomain = ["*"] - graphqh { - enabled = false - } -} +[jsonrpc.ws] +enabled = false +port = 8546 +prefix = "" +host = "localhost" +api = ["web3", "net"] +vhosts = ["*"] +corsdomain = ["*"] -telemetry { - enabled = false - expensive = false +[jsonrpc.graphql] +enabled = false +port = 0 +prefix = "" +host = "" +api = [] +vhosts = ["*"] +corsdomain = ["*"] - influxdb { - v1-enabled = false - endpoint = "" - database = "" - username = "" - password = "" - v2-enabled = false - token = "" - bucket = "" - organization = "" - } -} +[gpo] +blocks = 20 +percentile = 60 +maxprice = "5000000000000" +ignoreprice = "2" -cache { - cache = 1024 - perc-database = 50 - perc-trie = 15 - perc-gc = 25 - perc-snapshot = 10 - journal = "triecache" - rejournal = "60m" - no-prefetch = false - preimages = false - tx-lookup-limit = 2350000 -} +[telemetry] +metrics = false +expensive = false +prometheus-addr = "" +opencollector-endpoint = "" -accounts { - unlock = [] - password-file = "" - allow-insecure-unlock = false - use-lightweight-kdf = false -} +[telemetry.influx] +influxdb = false +endpoint = "" +database = "" +username = "" +password = "" +influxdbv2 = false +token = "" +bucket = "" +organization = "" -grpc { - addr = ":3131" -} +[cache] +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 ``` diff --git a/go.mod b/go.mod index 8c5c18f8c7..736e385524 100644 --- a/go.mod +++ b/go.mod @@ -83,6 +83,7 @@ require ( require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect + github.com/BurntSushi/toml v1.1.0 // indirect github.com/Masterminds/goutils v1.1.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect diff --git a/go.sum b/go.sum index e20575ddaa..bff0f82101 100644 --- a/go.sum +++ b/go.sum @@ -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/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= 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/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= @@ -459,6 +461,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.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.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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= diff --git a/internal/cli/command.go b/internal/cli/command.go index 1ff95b410f..06127a9823 100644 --- a/internal/cli/command.go +++ b/internal/cli/command.go @@ -82,6 +82,11 @@ func Commands() map[string]MarkDownCommandFactory { UI: ui, }, nil }, + "dumpconfig": func() (MarkDownCommand, error) { + return &DumpconfigCommand{ + Meta2: meta2, + }, nil + }, "debug": func() (MarkDownCommand, error) { return &DebugCommand{ UI: ui, diff --git a/internal/cli/dumpconfig.go b/internal/cli/dumpconfig.go new file mode 100644 index 0000000000..3e4688fc24 --- /dev/null +++ b/internal/cli/dumpconfig.go @@ -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 ``` 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 + + 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 +} diff --git a/internal/cli/flagset/flagset.go b/internal/cli/flagset/flagset.go index 0c19fa9758..d9e204f0e4 100644 --- a/internal/cli/flagset/flagset.go +++ b/internal/cli/flagset/flagset.go @@ -180,14 +180,15 @@ func (b *BigIntFlag) Set(value string) error { var ok bool if strings.HasPrefix(value, "0x") { num, ok = num.SetString(value[2:], 16) + *b.Value = *num } else { num, ok = num.SetString(value, 10) + *b.Value = *num } if !ok { return fmt.Errorf("failed to set big int") } - b.Value = num return nil } @@ -209,6 +210,19 @@ type SliceStringFlag struct { 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 { if i.Value == nil { return "" @@ -219,7 +233,7 @@ func (i *SliceStringFlag) String() string { func (i *SliceStringFlag) Set(value string) error { // overwritting insted of appending - *i.Value = strings.Split(value, ",") + *i.Value = SplitAndTrim(value) return nil } diff --git a/internal/cli/server/command.go b/internal/cli/server/command.go index a0b8a6d87c..2995f10f69 100644 --- a/internal/cli/server/command.go +++ b/internal/cli/server/command.go @@ -7,8 +7,9 @@ import ( "strings" "syscall" - "github.com/ethereum/go-ethereum/log" "github.com/mitchellh/cli" + + "github.com/ethereum/go-ethereum/log" ) // Command is the command to start the sever @@ -21,7 +22,7 @@ type Command struct { // final configuration config *Config - configFile []string + configFile string srv *Server } @@ -50,34 +51,57 @@ func (c *Command) Synopsis() string { return "Run the Bor server" } -// Run implements the cli.Command interface -func (c *Command) Run(args []string) int { +func (c *Command) extractFlags(args []string) error { + config := *DefaultConfig() + flags := c.Flags() if err := flags.Parse(args); err != nil { c.UI.Error(err.Error()) - return 1 + c.config = &config + + return err } - // read config file - config := DefaultConfig() - for _, configFile := range c.configFile { - cfg, err := readConfigFile(configFile) + // TODO: Check if this can be removed or not + // read cli flags + if err := config.Merge(c.cliConfig); err != nil { + 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 { c.UI.Error(err.Error()) - return 1 + c.config = &config + + return err } if err := config.Merge(cfg); err != nil { 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()) return 1 } - c.config = config - srv, err := NewServer(config) + srv, err := NewServer(c.config) if err != nil { c.UI.Error(err.Error()) return 1 @@ -112,3 +136,8 @@ func (c *Command) handleSignals() int { } return 1 } + +// GetConfig returns the user specified config +func (c *Command) GetConfig() *Config { + return c.cliConfig +} diff --git a/internal/cli/server/command_test.go b/internal/cli/server/command_test.go new file mode 100644 index 0000000000..9006559d0f --- /dev/null +++ b/internal/cli/server/command_test.go @@ -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"}) +} diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index fdf253a37e..819ab1aca5 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -14,6 +14,11 @@ import ( 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/keystore" "github.com/ethereum/go-ethereum/common" @@ -28,360 +33,356 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/params" - "github.com/hashicorp/hcl/v2/hclsimple" - "github.com/imdario/mergo" - "github.com/mitchellh/go-homedir" - gopsutil "github.com/shirou/gopsutil/mem" ) type Config struct { chain *chains.Chain // Chain is the chain to sync with - Chain string `hcl:"chain,optional"` + Chain string `hcl:"chain,optional" toml:"chain,optional"` // 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 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 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 string `hcl:"data-dir,optional"` + DataDir string `hcl:"datadir,optional" toml:"datadir,optional"` // 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 string `hcl:"sync-mode,optional"` + SyncMode string `hcl:"syncmode,optional" toml:"syncmode,optional"` // 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 bool `hcl:"snapshot,optional"` + Snapshot bool `hcl:"snapshot,optional" toml:"snapshot,optional"` // 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 *P2PConfig `hcl:"p2p,block"` + P2P *P2PConfig `hcl:"p2p,block" toml:"p2p,block"` // 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 *TxPoolConfig `hcl:"txpool,block"` + TxPool *TxPoolConfig `hcl:"txpool,block" toml:"txpool,block"` // 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 *JsonRPCConfig `hcl:"jsonrpc,block"` + JsonRPC *JsonRPCConfig `hcl:"jsonrpc,block" toml:"jsonrpc,block"` // 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 *TelemetryConfig `hcl:"telemetry,block"` + Telemetry *TelemetryConfig `hcl:"telemetry,block" toml:"telemetry,block"` // 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 - Accounts *AccountsConfig `hcl:"accounts,block"` + Accounts *AccountsConfig `hcl:"accounts,block" toml:"accounts,block"` // 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 *DeveloperConfig + Developer *DeveloperConfig `hcl:"developer,block" toml:"developer,block"` } type P2PConfig struct { // 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 uint64 `hcl:"max-pend-peers,optional"` + MaxPendPeers uint64 `hcl:"maxpendpeers,optional" toml:"maxpendpeers,optional"` // Bind is the bind address - Bind string `hcl:"bind,optional"` + Bind string `hcl:"bind,optional" toml:"bind,optional"` // 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 bool `hcl:"no-discover,optional"` + NoDiscover bool `hcl:"nodiscover,optional" toml:"nodiscover,optional"` // 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 *P2PDiscovery `hcl:"discovery,block"` + Discovery *P2PDiscovery `hcl:"discovery,block" toml:"discovery,block"` } type P2PDiscovery struct { // 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 []string `hcl:"bootnodes,optional"` + Bootnodes []string `hcl:"bootnodes,optional" toml:"bootnodes,optional"` // 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 []string `hcl:"bootnodesv5,optional"` + BootnodesV5 []string `hcl:"bootnodesv5,optional" toml:"bootnodesv5,optional"` // 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 []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 []string `hcl:"dns,optional"` + DNS []string `hcl:"dns,optional" toml:"dns,optional"` } type HeimdallConfig struct { // 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 bool `hcl:"without,optional"` + Without bool `hcl:"bor.without,optional" toml:"bor.without,optional"` } type TxPoolConfig struct { // 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 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 string `hcl:"journal,optional"` + Journal string `hcl:"journal,optional" toml:"journal,optional"` // Rejournal is the time interval to regenerate the local transaction journal - Rejournal time.Duration - RejournalRaw string `hcl:"rejournal,optional"` + Rejournal time.Duration `hcl:"-,optional" toml:"-,optional"` + RejournalRaw string `hcl:"rejournal,optional" toml:"rejournal,optional"` // 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 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 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 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 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 - 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 time.Duration - LifeTimeRaw string `hcl:"lifetime,optional"` + // lifetime is the maximum amount of time non-executable transaction are queued + LifeTime time.Duration `hcl:"-,optional" toml:"-,optional"` + LifeTimeRaw string `hcl:"lifetime,optional" toml:"lifetime,optional"` } type SealerConfig struct { // 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 string `hcl:"etherbase,optional"` + Etherbase string `hcl:"etherbase,optional" toml:"etherbase,optional"` // 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 uint64 `hcl:"gas-ceil,optional"` + GasCeil uint64 `hcl:"gaslimit,optional" toml:"gaslimit,optional"` // GasPrice is the minimum gas price for mining a transaction - GasPrice *big.Int - GasPriceRaw string `hcl:"gas-price,optional"` + GasPrice *big.Int `hcl:"-,optional" toml:"-,optional"` + GasPriceRaw string `hcl:"gasprice,optional" toml:"gasprice,optional"` } type JsonRPCConfig struct { // 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 string `hcl:"ipc-path,optional"` + IPCPath string `hcl:"ipcpath,optional" toml:"ipcpath,optional"` // 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 float64 `hcl:"tx-fee-cap,optional"` + TxFeeCap float64 `hcl:"txfeecap,optional" toml:"txfeecap,optional"` // 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 *APIConfig `hcl:"ws,block"` + Ws *APIConfig `hcl:"ws,block" toml:"ws,block"` // Graphql has the json-rpc graphql related settings - Graphql *APIConfig `hcl:"graphql,block"` + Graphql *APIConfig `hcl:"graphql,block" toml:"graphql,block"` } type GRPCConfig struct { // Addr is the bind address for the grpc rpc server - Addr string + Addr string `hcl:"addr,optional" toml:"addr,optional"` } type APIConfig struct { // 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 uint64 `hcl:"port,optional"` + Port uint64 `hcl:"port,optional" toml:"port,optional"` // 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 string `hcl:"host,optional"` + Host string `hcl:"host,optional" toml:"host,optional"` - // Modules is the list of enabled api modules - API []string `hcl:"modules,optional"` + // API is the list of enabled api modules + API []string `hcl:"api,optional" toml:"api,optional"` // 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 []string `hcl:"cors,optional"` + Cors []string `hcl:"corsdomain,optional" toml:"corsdomain,optional"` } type GpoConfig struct { // 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 uint64 `hcl:"percentile,optional"` + Percentile uint64 `hcl:"percentile,optional" toml:"percentile,optional"` // MaxPrice is an upper bound gas price - MaxPrice *big.Int - MaxPriceRaw string `hcl:"max-price,optional"` + MaxPrice *big.Int `hcl:"-,optional" toml:"-,optional"` + MaxPriceRaw string `hcl:"maxprice,optional" toml:"maxprice,optional"` // IgnorePrice is a lower bound gas price - IgnorePrice *big.Int - IgnorePriceRaw string `hcl:"ignore-price,optional"` + IgnorePrice *big.Int `hcl:"-,optional" toml:"-,optional"` + IgnorePriceRaw string `hcl:"ignoreprice,optional" toml:"ignoreprice,optional"` } type TelemetryConfig struct { // Enabled enables metrics - Enabled bool `hcl:"enabled,optional"` + Enabled bool `hcl:"metrics,optional" toml:"metrics,optional"` // Expensive enables expensive metrics - Expensive bool `hcl:"expensive,optional"` + Expensive bool `hcl:"expensive,optional" toml:"expensive,optional"` // InfluxDB has the influxdb related settings - InfluxDB *InfluxDBConfig `hcl:"influx,block"` + InfluxDB *InfluxDBConfig `hcl:"influx,block" toml:"influx,block"` // Prometheus Address - PrometheusAddr string `hcl:"prometheus-addr,optional"` + PrometheusAddr string `hcl:"prometheus-addr,optional" toml:"prometheus-addr,optional"` // Open collector endpoint - OpenCollectorEndpoint string `hcl:"opencollector-endpoint,optional"` + OpenCollectorEndpoint string `hcl:"opencollector-endpoint,optional" toml:"opencollector-endpoint,optional"` } type InfluxDBConfig struct { // 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 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 string `hcl:"database,optional"` + Database string `hcl:"database,optional" toml:"database,optional"` // 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 string `hcl:"password,optional"` + Password string `hcl:"password,optional" toml:"password,optional"` // 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 - 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 string `hcl:"token,optional"` + Token string `hcl:"token,optional" toml:"token,optional"` // 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 string `hcl:"organization,optional"` + Organization string `hcl:"organization,optional" toml:"organization,optional"` } type CacheConfig struct { // 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 uint64 `hcl:"perc-gc,optional"` + PercGc uint64 `hcl:"gc,optional" toml:"gc,optional"` // 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 uint64 `hcl:"perc-database,optional"` + PercDatabase uint64 `hcl:"database,optional" toml:"database,optional"` // 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 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 time.Duration - RejournalRaw string `hcl:"rejournal,optional"` + Rejournal time.Duration `hcl:"-,optional" toml:"-,optional"` + RejournalRaw string `hcl:"rejournal,optional" toml:"rejournal,optional"` // 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 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 uint64 `hcl:"tx-lookup-limit,optional"` + TxLookupLimit uint64 `hcl:"txlookuplimit,optional" toml:"txlookuplimit,optional"` } type AccountsConfig struct { // 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 string `hcl:"password-file,optional"` + PasswordFile string `hcl:"password,optional" toml:"password,optional"` // 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 bool `hcl:"use-lightweight-kdf,optional"` + UseLightweightKDF bool `hcl:"lightkdf,optional" toml:"lightkdf,optional"` // 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 { // 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 uint64 `hcl:"period,optional"` + Period uint64 `hcl:"period,optional" toml:"period,optional"` } func DefaultConfig() *Config { @@ -419,14 +420,14 @@ func DefaultConfig() *Config { Locals: []string{}, NoLocals: false, Journal: "", - Rejournal: time.Duration(1 * time.Hour), + Rejournal: 1 * time.Hour, PriceLimit: 30000000000, PriceBump: 10, AccountSlots: 16, GlobalSlots: 32768, AccountQueue: 16, GlobalQueue: 32768, - LifeTime: time.Duration(3 * time.Hour), + LifeTime: 3 * time.Hour, }, Sealer: &SealerConfig{ Enabled: false, @@ -526,7 +527,7 @@ func (c *Config) fillBigInt() error { }{ {"gpo.maxprice", &c.Gpo.MaxPrice, &c.Gpo.MaxPriceRaw}, {"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 { @@ -582,13 +583,7 @@ func (c *Config) fillTimeDurations() error { func readConfigFile(path string) (*Config, error) { ext := filepath.Ext(path) if ext == ".toml" { - // read file and apply the legacy config - data, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - return readLegacyConfig(data) + return readLegacyConfig(path) } config := &Config{ @@ -1076,7 +1071,7 @@ func Hostname() string { func MakePasswordListFromFile(path string) ([]string, error) { text, err := ioutil.ReadFile(path) if err != nil { - return nil, fmt.Errorf("Failed to read password file: %v", err) + return nil, fmt.Errorf("failed to read password file: %v", err) } lines := strings.Split(string(text), "\n") diff --git a/internal/cli/server/config_legacy.go b/internal/cli/server/config_legacy.go index 0d96b2e023..50508a58b6 100644 --- a/internal/cli/server/config_legacy.go +++ b/internal/cli/server/config_legacy.go @@ -1,33 +1,33 @@ package server import ( - "bytes" + "fmt" + "io/ioutil" - "github.com/naoina/toml" + "github.com/BurntSushi/toml" ) -type legacyConfig struct { - Node struct { - P2P struct { - StaticNodes []string - TrustedNodes []string - } +func readLegacyConfig(path string) (*Config, error) { + data, err := ioutil.ReadFile(path) + tomlData := string(data) + + if err != nil { + return nil, fmt.Errorf("failed to read toml config file: %v", err) } -} -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 -} + var conf Config -func readLegacyConfig(data []byte) (*Config, error) { - var legacy legacyConfig + if _, err := toml.Decode(tomlData, &conf); err != nil { + return nil, fmt.Errorf("failed to decode toml config file: %v", err) + } - r := toml.NewDecoder(bytes.NewReader(data)) - if err := r.Decode(&legacy); err != nil { + if err := conf.fillBigInt(); err != nil { return nil, err } - return legacy.Config(), nil + + if err := conf.fillTimeDurations(); err != nil { + return nil, err + } + + return &conf, nil } diff --git a/internal/cli/server/config_legacy_test.go b/internal/cli/server/config_legacy_test.go index 399481fc9b..6fb662d62b 100644 --- a/internal/cli/server/config_legacy_test.go +++ b/internal/cli/server/config_legacy_test.go @@ -1,21 +1,50 @@ package server import ( + "math/big" "testing" + "time" "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) + readFile := func(path string) { + config, err := readLegacyConfig(path) + 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"}) - assert.Equal(t, config.P2P.Discovery.TrustedNodes, []string{"node2"}) + // read file in hcl format + t.Run("toml", func(t *testing.T) { + readFile("./testdata/test.toml") + }) } diff --git a/internal/cli/server/config_test.go b/internal/cli/server/config_test.go index c1c6c4ef4a..bf7787ac2e 100644 --- a/internal/cli/server/config_test.go +++ b/internal/cli/server/config_test.go @@ -115,7 +115,7 @@ func TestConfigLoadFile(t *testing.T) { MaxPeers: 30, }, TxPool: &TxPoolConfig{ - LifeTime: time.Duration(1 * time.Second), + LifeTime: 1 * time.Second, }, Gpo: &GpoConfig{ MaxPrice: big.NewInt(100), @@ -127,12 +127,12 @@ func TestConfigLoadFile(t *testing.T) { // read file in hcl format t.Run("hcl", func(t *testing.T) { - readFile("./testdata/simple.hcl") + readFile("./testdata/test.hcl") }) // read file in json format t.Run("json", func(t *testing.T) { - readFile("./testdata/simple.json") + readFile("./testdata/test.json") }) } diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index e85428b9ee..bbc7f44036 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -38,7 +38,7 @@ func (c *Command) Flags() *flagset.Flagset { Usage: "Path of the directory to store keystores", Value: &c.cliConfig.KeyStoreDir, }) - f.SliceStringFlag(&flagset.SliceStringFlag{ + f.StringFlag(&flagset.StringFlag{ Name: "config", Usage: "File for the config file", Value: &c.configFile, diff --git a/internal/cli/server/proto/server.pb.go b/internal/cli/server/proto/server.pb.go index 5512d83b72..3e928ac170 100644 --- a/internal/cli/server/proto/server.pb.go +++ b/internal/cli/server/proto/server.pb.go @@ -7,11 +7,12 @@ package proto import ( + reflect "reflect" + sync "sync" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" - reflect "reflect" - sync "sync" ) const ( diff --git a/internal/cli/server/proto/server_grpc.pb.go b/internal/cli/server/proto/server_grpc.pb.go index 63f1fa6187..bd4ecb660d 100644 --- a/internal/cli/server/proto/server_grpc.pb.go +++ b/internal/cli/server/proto/server_grpc.pb.go @@ -8,6 +8,7 @@ package proto import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" diff --git a/internal/cli/server/service_test.go b/internal/cli/server/service_test.go index 7850525686..86cf68e75e 100644 --- a/internal/cli/server/service_test.go +++ b/internal/cli/server/service_test.go @@ -4,8 +4,9 @@ import ( "math/big" "testing" - "github.com/ethereum/go-ethereum/internal/cli/server/proto" "github.com/stretchr/testify/assert" + + "github.com/ethereum/go-ethereum/internal/cli/server/proto" ) func TestGatherBlocks(t *testing.T) { diff --git a/internal/cli/server/testdata/simple.json b/internal/cli/server/testdata/simple.json deleted file mode 100644 index 6270ee6d13..0000000000 --- a/internal/cli/server/testdata/simple.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "data-dir": "./data", - "requiredblocks": { - "a": "b" - }, - "p2p": { - "max-peers": 30 - }, - "txpool": { - "lifetime": "1s" - }, - "gpo": { - "max-price": "100" - } -} \ No newline at end of file diff --git a/internal/cli/server/testdata/simple.hcl b/internal/cli/server/testdata/test.hcl similarity index 57% rename from internal/cli/server/testdata/simple.hcl rename to internal/cli/server/testdata/test.hcl index 5afc091859..208fdc51c1 100644 --- a/internal/cli/server/testdata/simple.hcl +++ b/internal/cli/server/testdata/test.hcl @@ -1,11 +1,11 @@ -data-dir = "./data" +datadir = "./data" requiredblocks = { a = "b" } p2p { - max-peers = 30 + maxpeers = 30 } txpool { @@ -13,5 +13,5 @@ txpool { } gpo { - max-price = "100" -} + maxprice = "100" +} \ No newline at end of file diff --git a/internal/cli/server/testdata/test.json b/internal/cli/server/testdata/test.json new file mode 100644 index 0000000000..467835e755 --- /dev/null +++ b/internal/cli/server/testdata/test.json @@ -0,0 +1,15 @@ +{ + "datadir": "./data", + "requiredblocks": { + "a": "b" + }, + "p2p": { + "maxpeers": 30 + }, + "txpool": { + "lifetime": "1s" + }, + "gpo": { + "maxprice": "100" + } +} \ No newline at end of file diff --git a/internal/cli/server/testdata/test.toml b/internal/cli/server/testdata/test.toml new file mode 100644 index 0000000000..81fc4c4630 --- /dev/null +++ b/internal/cli/server/testdata/test.toml @@ -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"