-
Notifications
You must be signed in to change notification settings - Fork 20.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
swarm: add config file #15548
swarm: add config file #15548
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,321 @@ | ||
// Copyright 2017 The go-ethereum Authors | ||
// This file is part of go-ethereum. | ||
// | ||
// go-ethereum is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// go-ethereum is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
"reflect" | ||
"strconv" | ||
"unicode" | ||
|
||
cli "gopkg.in/urfave/cli.v1" | ||
|
||
"github.com/ethereum/go-ethereum/cmd/utils" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/log" | ||
"github.com/ethereum/go-ethereum/node" | ||
"github.com/naoina/toml" | ||
|
||
bzzapi "github.com/ethereum/go-ethereum/swarm/api" | ||
) | ||
|
||
var ( | ||
//flag definition for the dumpconfig command | ||
DumpConfigCommand = cli.Command{ | ||
Action: utils.MigrateFlags(dumpConfig), | ||
Name: "dumpconfig", | ||
Usage: "Show configuration values", | ||
ArgsUsage: "", | ||
Flags: app.Flags, | ||
Category: "MISCELLANEOUS COMMANDS", | ||
Description: `The dumpconfig command shows configuration values.`, | ||
} | ||
|
||
//flag definition for the config file command | ||
SwarmTomlConfigPathFlag = cli.StringFlag{ | ||
Name: "config", | ||
Usage: "TOML configuration file", | ||
} | ||
) | ||
|
||
//constants for environment variables | ||
const ( | ||
SWARM_ENV_CHEQUEBOOK_ADDR = "SWARM_CHEQUEBOOK_ADDR" | ||
SWARM_ENV_ACCOUNT = "SWARM_ACCOUNT" | ||
SWARM_ENV_LISTEN_ADDR = "SWARM_LISTEN_ADDR" | ||
SWARM_ENV_PORT = "SWARM_PORT" | ||
SWARM_ENV_NETWORK_ID = "SWARM_NETWORK_ID" | ||
SWARM_ENV_SWAP_ENABLE = "SWARM_SWAP_ENABLE" | ||
SWARM_ENV_SWAP_API = "SWARM_SWAP_API" | ||
SWARM_ENV_SYNC_ENABLE = "SWARM_SYNC_ENABLE" | ||
SWARM_ENV_ENS_API = "SWARM_ENS_API" | ||
SWARM_ENV_ENS_ADDR = "SWARM_ENS_ADDR" | ||
SWARM_ENV_CORS = "SWARM_CORS" | ||
SWARM_ENV_BOOTNODES = "SWARM_BOOTNODES" | ||
GETH_ENV_DATADIR = "GETH_DATADIR" | ||
) | ||
|
||
// 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 | ||
}, | ||
MissingField: func(rt reflect.Type, field string) error { | ||
link := "" | ||
if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { | ||
link = fmt.Sprintf(", check github.com/ethereum/go-ethereum/swarm/api/config.go for available fields") | ||
} | ||
return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) | ||
}, | ||
} | ||
|
||
//before booting the swarm node, build the configuration | ||
func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) { | ||
//check for deprecated flags | ||
checkDeprecated(ctx) | ||
//start by creating a default config | ||
config = bzzapi.NewDefaultConfig() | ||
//first load settings from config file (if provided) | ||
config, err = configFileOverride(config, ctx) | ||
//override settings provided by environment variables | ||
config = envVarsOverride(config) | ||
//override settings provided by command line | ||
config = cmdLineOverride(config, ctx) | ||
|
||
return | ||
} | ||
|
||
//finally, after the configuration build phase is finished, initialize | ||
func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context) { | ||
//at this point, all vars should be set in the Config | ||
//get the account for the provided swarm account | ||
prvkey := getAccount(config.BzzAccount, ctx, stack) | ||
//set the resolved config path (geth --datadir) | ||
config.Path = stack.InstanceDir() | ||
//finally, initialize the configuration | ||
config.Init(prvkey) | ||
//configuration phase completed here | ||
log.Debug("Starting Swarm with the following parameters:") | ||
//after having created the config, print it to screen | ||
log.Debug(printConfig(config)) | ||
} | ||
|
||
//override the current config with whatever is in the config file, if a config file has been provided | ||
func configFileOverride(config *bzzapi.Config, ctx *cli.Context) (*bzzapi.Config, error) { | ||
var err error | ||
|
||
//only do something if the -config flag has been set | ||
if ctx.GlobalIsSet(SwarmTomlConfigPathFlag.Name) { | ||
var filepath string | ||
if filepath = ctx.GlobalString(SwarmTomlConfigPathFlag.Name); filepath == "" { | ||
utils.Fatalf("Config file flag provided with invalid file path") | ||
} | ||
f, err := os.Open(filepath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
|
||
//decode the TOML file into a Config struct | ||
//note that we are decoding into the existing defaultConfig; | ||
//if an entry is not present in the file, the default entry is kept | ||
err = tomlSettings.NewDecoder(f).Decode(&config) | ||
// Add file name to errors that have a line number. | ||
if _, ok := err.(*toml.LineError); ok { | ||
err = errors.New(filepath + ", " + err.Error()) | ||
} | ||
} | ||
return config, err | ||
} | ||
|
||
//override the current config with whatever is provided through the command line | ||
//most values are not allowed a zero value (empty string), if not otherwise noted | ||
func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Config { | ||
|
||
if keyid := ctx.GlobalString(SwarmAccountFlag.Name); keyid != "" { | ||
currentConfig.BzzAccount = keyid | ||
} | ||
|
||
if chbookaddr := ctx.GlobalString(ChequebookAddrFlag.Name); chbookaddr != "" { | ||
currentConfig.Contract = common.HexToAddress(chbookaddr) | ||
} | ||
|
||
if networkid := ctx.GlobalString(SwarmNetworkIdFlag.Name); networkid != "" { | ||
if id, _ := strconv.Atoi(networkid); id != 0 { | ||
currentConfig.NetworkId = uint64(id) | ||
} | ||
} | ||
|
||
if ctx.GlobalIsSet(utils.DataDirFlag.Name) { | ||
if datadir := ctx.GlobalString(utils.DataDirFlag.Name); datadir != "" { | ||
currentConfig.Path = datadir | ||
} | ||
} | ||
|
||
bzzport := ctx.GlobalString(SwarmPortFlag.Name) | ||
if len(bzzport) > 0 { | ||
currentConfig.Port = bzzport | ||
} | ||
|
||
if bzzaddr := ctx.GlobalString(SwarmListenAddrFlag.Name); bzzaddr != "" { | ||
currentConfig.ListenAddr = bzzaddr | ||
} | ||
|
||
if ctx.GlobalIsSet(SwarmSwapEnabledFlag.Name) { | ||
currentConfig.SwapEnabled = true | ||
} | ||
|
||
if ctx.GlobalIsSet(SwarmSyncEnabledFlag.Name) { | ||
currentConfig.SyncEnabled = true | ||
} | ||
|
||
currentConfig.SwapApi = ctx.GlobalString(SwarmSwapAPIFlag.Name) | ||
if currentConfig.SwapEnabled && currentConfig.SwapApi == "" { | ||
utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) | ||
} | ||
|
||
//EnsApi can be set to "", so can't check for empty string, as it is allowed! | ||
if ctx.GlobalIsSet(EnsAPIFlag.Name) { | ||
currentConfig.EnsApi = ctx.GlobalString(EnsAPIFlag.Name) | ||
} | ||
|
||
if ensaddr := ctx.GlobalString(EnsAddrFlag.Name); ensaddr != "" { | ||
currentConfig.EnsRoot = common.HexToAddress(ensaddr) | ||
} | ||
|
||
if cors := ctx.GlobalString(CorsStringFlag.Name); cors != "" { | ||
currentConfig.Cors = cors | ||
} | ||
|
||
if ctx.GlobalIsSet(utils.BootnodesFlag.Name) { | ||
currentConfig.BootNodes = ctx.GlobalString(utils.BootnodesFlag.Name) | ||
} | ||
|
||
return currentConfig | ||
|
||
} | ||
|
||
//override the current config with whatver is provided in environment variables | ||
//most values are not allowed a zero value (empty string), if not otherwise noted | ||
func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) { | ||
|
||
if keyid := os.Getenv(SWARM_ENV_ACCOUNT); keyid != "" { | ||
currentConfig.BzzAccount = keyid | ||
} | ||
|
||
if chbookaddr := os.Getenv(SWARM_ENV_CHEQUEBOOK_ADDR); chbookaddr != "" { | ||
currentConfig.Contract = common.HexToAddress(chbookaddr) | ||
} | ||
|
||
if networkid := os.Getenv(SWARM_ENV_NETWORK_ID); networkid != "" { | ||
if id, _ := strconv.Atoi(networkid); id != 0 { | ||
currentConfig.NetworkId = uint64(id) | ||
} | ||
} | ||
|
||
if datadir := os.Getenv(GETH_ENV_DATADIR); datadir != "" { | ||
currentConfig.Path = datadir | ||
} | ||
|
||
bzzport := os.Getenv(SWARM_ENV_PORT) | ||
if len(bzzport) > 0 { | ||
currentConfig.Port = bzzport | ||
} | ||
|
||
if bzzaddr := os.Getenv(SWARM_ENV_LISTEN_ADDR); bzzaddr != "" { | ||
currentConfig.ListenAddr = bzzaddr | ||
} | ||
|
||
if swapenable := os.Getenv(SWARM_ENV_SWAP_ENABLE); swapenable != "" { | ||
if swap, err := strconv.ParseBool(swapenable); err != nil { | ||
currentConfig.SwapEnabled = swap | ||
} | ||
} | ||
|
||
if syncenable := os.Getenv(SWARM_ENV_SYNC_ENABLE); syncenable != "" { | ||
if sync, err := strconv.ParseBool(syncenable); err != nil { | ||
currentConfig.SyncEnabled = sync | ||
} | ||
} | ||
|
||
if swapapi := os.Getenv(SWARM_ENV_SWAP_API); swapapi != "" { | ||
currentConfig.SwapApi = swapapi | ||
} | ||
|
||
if currentConfig.SwapEnabled && currentConfig.SwapApi == "" { | ||
utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) | ||
} | ||
|
||
//EnsApi can be set to "", so can't check for empty string, as it is allowed | ||
if ensapi, exists := os.LookupEnv(SWARM_ENV_ENS_API); exists == true { | ||
currentConfig.EnsApi = ensapi | ||
} | ||
|
||
if ensaddr := os.Getenv(SWARM_ENV_ENS_ADDR); ensaddr != "" { | ||
currentConfig.EnsRoot = common.HexToAddress(ensaddr) | ||
} | ||
|
||
if cors := os.Getenv(SWARM_ENV_CORS); cors != "" { | ||
currentConfig.Cors = cors | ||
} | ||
|
||
if bootnodes := os.Getenv(SWARM_ENV_BOOTNODES); bootnodes != "" { | ||
currentConfig.BootNodes = bootnodes | ||
} | ||
|
||
return currentConfig | ||
} | ||
|
||
// dumpConfig is the dumpconfig command. | ||
// writes a default config to STDOUT | ||
func dumpConfig(ctx *cli.Context) error { | ||
cfg, err := buildConfig(ctx) | ||
if err != nil { | ||
utils.Fatalf(fmt.Sprintf("Uh oh - dumpconfig triggered an error %v", err)) | ||
} | ||
comment := "" | ||
out, err := tomlSettings.Marshal(&cfg) | ||
if err != nil { | ||
return err | ||
} | ||
io.WriteString(os.Stdout, comment) | ||
os.Stdout.Write(out) | ||
return nil | ||
} | ||
|
||
//deprecated flags checked here | ||
func checkDeprecated(ctx *cli.Context) { | ||
// exit if the deprecated --ethapi flag is set | ||
if ctx.GlobalString(DeprecatedEthAPIFlag.Name) != "" { | ||
utils.Fatalf("--ethapi is no longer a valid command line flag, please use --ens-api and/or --swap-api.") | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why and/OR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error message is the same as currently on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should clear this up in the orange-lounge? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously --ethapi was used for all eth interactions. This has now been split up into ENS and SWAP allowing us to use mainnet ENS while testing SWAP on ropsten for example. |
||
} | ||
|
||
//print a Config as string | ||
func printConfig(config *bzzapi.Config) string { | ||
out, err := tomlSettings.Marshal(&config) | ||
if err != nil { | ||
return (fmt.Sprintf("Something is not right with the configuration: %v", err)) | ||
} | ||
return string(out) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are NormFieldName and FieldToKey just supposed to return the second param?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I literally copied this section from the
geth
code, which apparently is needed to matchgo
structures toTOML
, checkcmd/geth/config.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it works don't fix it :)