11 log "github.com/sirupsen/logrus"
13 "github.com/bytom/crypto/ed25519"
17 // CommonConfig means config object
22 // Top level options use an anonymous struct
23 BaseConfig `mapstructure:",squash"`
24 // Options for services
25 P2P *P2PConfig `mapstructure:"p2p"`
26 Wallet *WalletConfig `mapstructure:"wallet"`
27 Auth *RPCAuthConfig `mapstructure:"auth"`
28 Web *WebConfig `mapstructure:"web"`
29 Simd *SimdConfig `mapstructure:"simd"`
30 Mining *MiningConfig `mapstructure:"mining"`
31 Websocket *WebsocketConfig `mapstructure:"ws"`
34 // Default configurable parameters.
35 func DefaultConfig() *Config {
37 BaseConfig: DefaultBaseConfig(),
38 P2P: DefaultP2PConfig(),
39 Wallet: DefaultWalletConfig(),
40 Auth: DefaultRPCAuthConfig(),
41 Web: DefaultWebConfig(),
42 Simd: DefaultSimdConfig(),
43 Mining: DefaultMiningConfig(),
44 Websocket: DefaultWebsocketConfig(),
48 // Set the RootDir for all Config structs
49 func (cfg *Config) SetRoot(root string) *Config {
50 cfg.BaseConfig.RootDir = root
54 // NodeKey retrieves the currently configured private key of the node, checking
55 // first any manually set key, falling back to the one found in the configured
56 // data folder. If no key can be found, a new one is generated.
57 func (cfg *Config) NodeKey() (string, error) {
58 // Use any specifically configured key.
59 if cfg.P2P.PrivateKey != "" {
60 return cfg.P2P.PrivateKey, nil
63 keyFile := rootify(cfg.P2P.NodeKeyFile, cfg.BaseConfig.RootDir)
64 buf := make([]byte, ed25519.PrivateKeySize*2)
65 fd, err := os.Open(keyFile)
68 if _, err = io.ReadFull(fd, buf); err == nil {
69 return string(buf), nil
73 log.WithField("err", err).Warning("key file access failed")
74 _, privKey, err := ed25519.GenerateKey(nil)
79 if err = ioutil.WriteFile(keyFile, []byte(privKey.String()), 0600); err != nil {
82 return privKey.String(), nil
85 //-----------------------------------------------------------------------------
87 type BaseConfig struct {
88 // The root directory for all data.
89 // This should be set in viper so it can unmarshal into this struct
90 RootDir string `mapstructure:"home"`
92 //The ID of the network to json
93 ChainID string `mapstructure:"chain_id"`
96 LogLevel string `mapstructure:"log_level"`
98 // A custom human readable name for this node
99 Moniker string `mapstructure:"moniker"`
101 // TCP or UNIX socket address for the profiling server to listen on
102 ProfListenAddress string `mapstructure:"prof_laddr"`
104 // Database backend: leveldb | memdb
105 DBBackend string `mapstructure:"db_backend"`
107 // Database directory
108 DBPath string `mapstructure:"db_dir"`
110 // Keystore directory
111 KeysPath string `mapstructure:"keys_dir"`
113 ApiAddress string `mapstructure:"api_addr"`
115 VaultMode bool `mapstructure:"vault_mode"`
118 LogFile string `mapstructure:"log_file"`
121 // Default configurable base parameters.
122 func DefaultBaseConfig() BaseConfig {
124 Moniker: "anonymous",
125 ProfListenAddress: "",
126 DBBackend: "leveldb",
128 KeysPath: "keystore",
132 func (b BaseConfig) DBDir() string {
133 return rootify(b.DBPath, b.RootDir)
136 func (b BaseConfig) KeysDir() string {
137 return rootify(b.KeysPath, b.RootDir)
141 type P2PConfig struct {
142 ListenAddress string `mapstructure:"laddr"`
143 Seeds string `mapstructure:"seeds"`
144 PrivateKey string `mapstructure:"node_key"`
145 NodeKeyFile string `mapstructure:"node_key_file"`
146 SkipUPNP bool `mapstructure:"skip_upnp"`
147 MaxNumPeers int `mapstructure:"max_num_peers"`
148 HandshakeTimeout int `mapstructure:"handshake_timeout"`
149 DialTimeout int `mapstructure:"dial_timeout"`
150 ProxyAddress string `mapstructure:"proxy_address"`
151 ProxyUsername string `mapstructure:"proxy_username"`
152 ProxyPassword string `mapstructure:"proxy_password"`
155 // Default configurable p2p parameters.
156 func DefaultP2PConfig() *P2PConfig {
158 ListenAddress: "tcp://0.0.0.0:46656",
159 NodeKeyFile: "nodekey",
162 HandshakeTimeout: 30,
170 //-----------------------------------------------------------------------------
171 type WalletConfig struct {
172 Disable bool `mapstructure:"disable"`
173 Rescan bool `mapstructure:"rescan"`
174 MaxTxFee uint64 `mapstructure:"max_tx_fee"`
177 type RPCAuthConfig struct {
178 Disable bool `mapstructure:"disable"`
181 type WebConfig struct {
182 Closed bool `mapstructure:"closed"`
185 type SimdConfig struct {
186 Enable bool `mapstructure:"enable"`
189 type MiningConfig struct {
190 Enable bool `mapstructure:"enable"`
191 RecommitInterval uint64 `mapstructure:"recommit_interval"`
194 type WebsocketConfig struct {
195 MaxNumWebsockets int `mapstructure:"max_num_websockets"`
196 MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
199 // Default configurable rpc's auth parameters.
200 func DefaultRPCAuthConfig() *RPCAuthConfig {
201 return &RPCAuthConfig{
206 // Default configurable web parameters.
207 func DefaultWebConfig() *WebConfig {
213 // Default configurable wallet parameters.
214 func DefaultWalletConfig() *WalletConfig {
215 return &WalletConfig{
218 MaxTxFee: uint64(1000000000),
222 // Default configurable blockheader verification parameters.
223 func DefaultSimdConfig() *SimdConfig {
229 // Default configurable mining parameters.
230 func DefaultMiningConfig() *MiningConfig {
231 return &MiningConfig{
233 RecommitInterval: 15,
237 func DefaultWebsocketConfig() *WebsocketConfig {
238 return &WebsocketConfig{
239 MaxNumWebsockets: 25,
240 MaxNumConcurrentReqs: 20,
244 //-----------------------------------------------------------------------------
247 // helper function to make config creation independent of root dir
248 func rootify(path, root string) string {
249 if filepath.IsAbs(path) {
252 return filepath.Join(root, path)
255 // DefaultDataDir is the default data directory to use for the databases and other
256 // persistence requirements.
257 func DefaultDataDir() string {
258 // Try to place the data folder in the user's home dir
263 switch runtime.GOOS {
265 // In order to be compatible with old data path,
266 // copy the data from the old path to the new path
267 oldPath := filepath.Join(home, "Library", "Bytom")
268 newPath := filepath.Join(home, "Library", "Application Support", "Bytom")
269 if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) {
270 if err := os.Rename(oldPath, newPath); err != nil {
271 log.Errorf("DefaultDataDir: %v", err)
277 return filepath.Join(home, "AppData", "Roaming", "Bytom")
279 return filepath.Join(home, ".bytom")
283 func isFolderNotExists(path string) bool {
284 _, err := os.Stat(path)
285 return os.IsNotExist(err)
288 func homeDir() string {
289 if home := os.Getenv("HOME"); home != "" {
292 if usr, err := user.Current(); err == nil {