package config
import (
+ "io"
+ "io/ioutil"
+ "os"
+ "os/user"
"path/filepath"
- "time"
+ "runtime"
+
+ log "github.com/sirupsen/logrus"
+
+ "github.com/bytom/bytom/crypto/ed25519"
+)
+
+var (
+ // CommonConfig means config object
+ CommonConfig *Config
)
type Config struct {
// Top level options use an anonymous struct
BaseConfig `mapstructure:",squash"`
// Options for services
- RPC *RPCConfig `mapstructure:"rpc"`
- P2P *P2PConfig `mapstructure:"p2p"`
- Wallet *WalletConfig `mapstructure:"wallet"`
+ P2P *P2PConfig `mapstructure:"p2p"`
+ Wallet *WalletConfig `mapstructure:"wallet"`
+ Auth *RPCAuthConfig `mapstructure:"auth"`
+ Web *WebConfig `mapstructure:"web"`
+ Simd *SimdConfig `mapstructure:"simd"`
+ Websocket *WebsocketConfig `mapstructure:"ws"`
}
+// Default configurable parameters.
func DefaultConfig() *Config {
return &Config{
BaseConfig: DefaultBaseConfig(),
- RPC: DefaultRPCConfig(),
P2P: DefaultP2PConfig(),
Wallet: DefaultWalletConfig(),
- }
-}
-
-func TestConfig() *Config {
- return &Config{
- BaseConfig: TestBaseConfig(),
- RPC: TestRPCConfig(),
- P2P: TestP2PConfig(),
- Wallet: TestWalletConfig(),
+ Auth: DefaultRPCAuthConfig(),
+ Web: DefaultWebConfig(),
+ Simd: DefaultSimdConfig(),
+ Websocket: DefaultWebsocketConfig(),
}
}
// Set the RootDir for all Config structs
func (cfg *Config) SetRoot(root string) *Config {
cfg.BaseConfig.RootDir = root
- cfg.RPC.RootDir = root
- cfg.P2P.RootDir = root
return cfg
}
+// NodeKey retrieves the currently configured private key of the node, checking
+// first any manually set key, falling back to the one found in the configured
+// data folder. If no key can be found, a new one is generated.
+func (cfg *Config) NodeKey() (string, error) {
+ // Use any specifically configured key.
+ if cfg.P2P.PrivateKey != "" {
+ return cfg.P2P.PrivateKey, nil
+ }
+
+ keyFile := rootify(cfg.P2P.NodeKeyFile, cfg.BaseConfig.RootDir)
+ buf := make([]byte, ed25519.PrivateKeySize*2)
+ fd, err := os.Open(keyFile)
+ defer fd.Close()
+ if err == nil {
+ if _, err = io.ReadFull(fd, buf); err == nil {
+ return string(buf), nil
+ }
+ }
+
+ log.WithField("err", err).Warning("key file access failed")
+ _, privKey, err := ed25519.GenerateKey(nil)
+ if err != nil {
+ return "", err
+ }
+
+ if err = ioutil.WriteFile(keyFile, []byte(privKey.String()), 0600); err != nil {
+ return "", err
+ }
+ return privKey.String(), nil
+}
+
//-----------------------------------------------------------------------------
// BaseConfig
-
type BaseConfig struct {
// The root directory for all data.
// This should be set in viper so it can unmarshal into this struct
RootDir string `mapstructure:"home"`
- // A JSON file containing the initial validator set and other meta data
- Genesis string `mapstructure:"genesis_file"`
+ //The alias of the node
+ NodeAlias string `mapstructure:"node_alias"`
//The ID of the network to json
ChainID string `mapstructure:"chain_id"`
- // A JSON file containing the private key to use as a validator in the consensus protocol
- PrivateKey string `mapstructure:"private_key"`
+ //log level to set
+ LogLevel string `mapstructure:"log_level"`
// A custom human readable name for this node
Moniker string `mapstructure:"moniker"`
// TCP or UNIX socket address for the profiling server to listen on
ProfListenAddress string `mapstructure:"prof_laddr"`
- // If this node is many blocks behind the tip of the chain, FastSync
- // allows them to catchup quickly by downloading blocks in parallel
- // and verifying their commits
- FastSync bool `mapstructure:"fast_sync"`
-
- FilterPeers bool `mapstructure:"filter_peers"` // false
-
- // What indexer to use for transactions
- TxIndex string `mapstructure:"tx_index"`
+ Mining bool `mapstructure:"mining"`
// Database backend: leveldb | memdb
DBBackend string `mapstructure:"db_backend"`
// Keystore directory
KeysPath string `mapstructure:"keys_dir"`
- // remote HSM url
- HsmUrl string `mapstructure:"hsm_url"`
-
ApiAddress string `mapstructure:"api_addr"`
- Time time.Time
+ VaultMode bool `mapstructure:"vault_mode"`
+
+ // log file name
+ LogFile string `mapstructure:"log_file"`
}
+// Default configurable base parameters.
func DefaultBaseConfig() BaseConfig {
return BaseConfig{
- Genesis: "genesis.json",
Moniker: "anonymous",
ProfListenAddress: "",
- FastSync: true,
- FilterPeers: false,
- TxIndex: "kv",
+ Mining: false,
DBBackend: "leveldb",
DBPath: "data",
KeysPath: "keystore",
- HsmUrl: "",
+ NodeAlias: "",
+ LogFile: "log",
}
}
-func TestBaseConfig() BaseConfig {
- conf := DefaultBaseConfig()
- conf.ChainID = "bytom_test"
- conf.FastSync = false
- conf.DBBackend = "memdb"
- return conf
-}
-
-func (b BaseConfig) GenesisFile() string {
- return rootify(b.Genesis, b.RootDir)
-}
-
func (b BaseConfig) DBDir() string {
return rootify(b.DBPath, b.RootDir)
}
-func (b BaseConfig) KeysDir() string {
- return rootify(b.KeysPath, b.RootDir)
-}
-
-func DefaultLogLevel() string {
- return "info"
+func (b BaseConfig) LogDir() string {
+ return rootify(b.LogFile, b.RootDir)
}
-// RPCConfig
-
-type RPCConfig struct {
- RootDir string `mapstructure:"home"`
-
- // TCP or UNIX socket address for the RPC server to listen on
- ListenAddress string `mapstructure:"laddr"`
-
- // TCP or UNIX socket address for the gRPC server to listen on
- // NOTE: This server only supports /broadcast_tx_commit
- GRPCListenAddress string `mapstructure:"grpc_laddr"`
-
- // Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
- Unsafe bool `mapstructure:"unsafe"`
-}
-
-func DefaultRPCConfig() *RPCConfig {
- return &RPCConfig{
- ListenAddress: "tcp://0.0.0.0:46657",
- GRPCListenAddress: "",
- Unsafe: false,
- }
-}
-
-func TestRPCConfig() *RPCConfig {
- conf := DefaultRPCConfig()
- conf.ListenAddress = "tcp://0.0.0.0:36657"
- conf.GRPCListenAddress = "tcp://0.0.0.0:36658"
- conf.Unsafe = true
- return conf
+func (b BaseConfig) KeysDir() string {
+ return rootify(b.KeysPath, b.RootDir)
}
-//-----------------------------------------------------------------------------
// P2PConfig
-
type P2PConfig struct {
- RootDir string `mapstructure:"home"`
- ListenAddress string `mapstructure:"laddr"`
- Seeds string `mapstructure:"seeds"`
- SkipUPNP bool `mapstructure:"skip_upnp"`
- AddrBook string `mapstructure:"addr_book_file"`
- AddrBookStrict bool `mapstructure:"addr_book_strict"`
- PexReactor bool `mapstructure:"pex"`
- MaxNumPeers int `mapstructure:"max_num_peers"`
- HandshakeTimeout int `mapstructure:"handshake_timeout"`
- DialTimeout int `mapstructure:"dial_timeout"`
+ ListenAddress string `mapstructure:"laddr"`
+ Seeds string `mapstructure:"seeds"`
+ PrivateKey string `mapstructure:"node_key"`
+ NodeKeyFile string `mapstructure:"node_key_file"`
+ SkipUPNP bool `mapstructure:"skip_upnp"`
+ LANDiscover bool `mapstructure:"lan_discoverable"`
+ MaxNumPeers int `mapstructure:"max_num_peers"`
+ HandshakeTimeout int `mapstructure:"handshake_timeout"`
+ DialTimeout int `mapstructure:"dial_timeout"`
+ ProxyAddress string `mapstructure:"proxy_address"`
+ ProxyUsername string `mapstructure:"proxy_username"`
+ ProxyPassword string `mapstructure:"proxy_password"`
+ KeepDial string `mapstructure:"keep_dial"`
}
+// Default configurable p2p parameters.
func DefaultP2PConfig() *P2PConfig {
return &P2PConfig{
- ListenAddress: "tcp://0.0.0.0:46656",
- AddrBook: "addrbook.json",
- AddrBookStrict: true,
- SkipUPNP: false,
- MaxNumPeers: 50,
+ ListenAddress: "tcp://0.0.0.0:46656",
+ NodeKeyFile: "nodekey",
+ SkipUPNP: false,
+ LANDiscover: true,
+ MaxNumPeers: 50,
HandshakeTimeout: 30,
DialTimeout: 3,
+ ProxyAddress: "",
+ ProxyUsername: "",
+ ProxyPassword: "",
}
}
-func TestP2PConfig() *P2PConfig {
- conf := DefaultP2PConfig()
- conf.ListenAddress = "tcp://0.0.0.0:36656"
- conf.SkipUPNP = true
- return conf
+//-----------------------------------------------------------------------------
+type WalletConfig struct {
+ Disable bool `mapstructure:"disable"`
+ Rescan bool `mapstructure:"rescan"`
+ TxIndex bool `mapstructure:"txindex"`
+ MaxTxFee uint64 `mapstructure:"max_tx_fee"`
}
-func (p *P2PConfig) AddrBookFile() string {
- return rootify(p.AddrBook, p.RootDir)
+type RPCAuthConfig struct {
+ Disable bool `mapstructure:"disable"`
}
-//-----------------------------------------------------------------------------
-// WalletConfig
+type WebConfig struct {
+ Closed bool `mapstructure:"closed"`
+}
-type WalletConfig struct {
+type SimdConfig struct {
Enable bool `mapstructure:"enable"`
}
+type WebsocketConfig struct {
+ MaxNumWebsockets int `mapstructure:"max_num_websockets"`
+ MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
+}
+
+// Default configurable rpc's auth parameters.
+func DefaultRPCAuthConfig() *RPCAuthConfig {
+ return &RPCAuthConfig{
+ Disable: false,
+ }
+}
+
+// Default configurable web parameters.
+func DefaultWebConfig() *WebConfig {
+ return &WebConfig{
+ Closed: false,
+ }
+}
+
+// Default configurable wallet parameters.
func DefaultWalletConfig() *WalletConfig {
return &WalletConfig{
+ Disable: false,
+ Rescan: false,
+ TxIndex: false,
+ MaxTxFee: uint64(1000000000),
+ }
+}
+
+// Default configurable web parameters.
+func DefaultSimdConfig() *SimdConfig {
+ return &SimdConfig{
Enable: false,
}
}
-func TestWalletConfig() *WalletConfig {
- conf := DefaultWalletConfig()
- return conf
+func DefaultWebsocketConfig() *WebsocketConfig {
+ return &WebsocketConfig{
+ MaxNumWebsockets: 25,
+ MaxNumConcurrentReqs: 20,
+ }
}
//-----------------------------------------------------------------------------
}
return filepath.Join(root, path)
}
+
+// DefaultDataDir is the default data directory to use for the databases and other
+// persistence requirements.
+func DefaultDataDir() string {
+ // Try to place the data folder in the user's home dir
+ home := homeDir()
+ if home == "" {
+ return "./.bytom"
+ }
+ switch runtime.GOOS {
+ case "darwin":
+ // In order to be compatible with old data path,
+ // copy the data from the old path to the new path
+ oldPath := filepath.Join(home, "Library", "Bytom")
+ newPath := filepath.Join(home, "Library", "Application Support", "Bytom")
+ if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) {
+ if err := os.Rename(oldPath, newPath); err != nil {
+ log.Errorf("DefaultDataDir: %v", err)
+ return oldPath
+ }
+ }
+ return newPath
+ case "windows":
+ return filepath.Join(home, "AppData", "Roaming", "Bytom")
+ default:
+ return filepath.Join(home, ".bytom")
+ }
+}
+
+func isFolderNotExists(path string) bool {
+ _, err := os.Stat(path)
+ return os.IsNotExist(err)
+}
+
+func homeDir() string {
+ if home := os.Getenv("HOME"); home != "" {
+ return home
+ }
+ if usr, err := user.Current(); err == nil {
+ return usr.HomeDir
+ }
+ return ""
+}