OSDN Git Service

Add BlockWitness (#54)
[bytom/vapor.git] / config / config.go
1 package config
2
3 import (
4         "io"
5         "io/ioutil"
6         "os"
7         "os/user"
8         "path/filepath"
9         "runtime"
10
11         log "github.com/sirupsen/logrus"
12
13         "github.com/vapor/crypto/ed25519"
14 )
15
16 var (
17         // CommonConfig means config object
18         CommonConfig *Config
19 )
20
21 type Config struct {
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         Websocket *WebsocketConfig `mapstructure:"ws"`
30 }
31
32 // Default configurable parameters.
33 func DefaultConfig() *Config {
34         return &Config{
35                 BaseConfig: DefaultBaseConfig(),
36                 P2P:        DefaultP2PConfig(),
37                 Wallet:     DefaultWalletConfig(),
38                 Auth:       DefaultRPCAuthConfig(),
39                 Web:        DefaultWebConfig(),
40                 Websocket:  DefaultWebsocketConfig(),
41         }
42 }
43
44 // Set the RootDir for all Config structs
45 func (cfg *Config) SetRoot(root string) *Config {
46         cfg.BaseConfig.RootDir = root
47         return cfg
48 }
49
50 // NodeKey retrieves the currently configured private key of the node, checking
51 // first any manually set key, falling back to the one found in the configured
52 // data folder. If no key can be found, a new one is generated.
53 func (cfg *Config) NodeKey() (string, error) {
54         // Use any specifically configured key.
55         if cfg.P2P.PrivateKey != "" {
56                 return cfg.P2P.PrivateKey, nil
57         }
58
59         keyFile := rootify(cfg.P2P.NodeKeyFile, cfg.BaseConfig.RootDir)
60         buf := make([]byte, ed25519.PrivateKeySize*2)
61         fd, err := os.Open(keyFile)
62         defer fd.Close()
63         if err == nil {
64                 if _, err = io.ReadFull(fd, buf); err == nil {
65                         return string(buf), nil
66                 }
67         }
68
69         log.WithField("err", err).Warning("key file access failed")
70         _, privKey, err := ed25519.GenerateKey(nil)
71         if err != nil {
72                 return "", err
73         }
74
75         if err = ioutil.WriteFile(keyFile, []byte(privKey.String()), 0600); err != nil {
76                 return "", err
77         }
78         return privKey.String(), nil
79 }
80
81 //-----------------------------------------------------------------------------
82 // BaseConfig
83 type BaseConfig struct {
84         // The root directory for all data.
85         // This should be set in viper so it can unmarshal into this struct
86         RootDir string `mapstructure:"home"`
87
88         //The alias of the node
89         NodeAlias string `mapstructure:"node_alias"`
90
91         //The ID of the network to json
92         ChainID string `mapstructure:"chain_id"`
93
94         //log level to set
95         LogLevel string `mapstructure:"log_level"`
96
97         // A custom human readable name for this node
98         Moniker string `mapstructure:"moniker"`
99
100         // TCP or UNIX socket address for the profiling server to listen on
101         ProfListenAddress string `mapstructure:"prof_laddr"`
102
103         Mining bool `mapstructure:"mining"`
104
105         // Database backend: leveldb | memdb
106         DBBackend string `mapstructure:"db_backend"`
107
108         // Database directory
109         DBPath string `mapstructure:"db_dir"`
110
111         // Keystore directory
112         KeysPath string `mapstructure:"keys_dir"`
113
114         ApiAddress string `mapstructure:"api_addr"`
115
116         VaultMode bool `mapstructure:"vault_mode"`
117
118         // log file name
119         LogFile string `mapstructure:"log_file"`
120 }
121
122 // Default configurable base parameters.
123 func DefaultBaseConfig() BaseConfig {
124         return BaseConfig{
125                 Moniker:           "anonymous",
126                 ProfListenAddress: "",
127                 Mining:            false,
128                 DBBackend:         "leveldb",
129                 DBPath:            "data",
130                 KeysPath:          "keystore",
131                 NodeAlias:         "",
132         }
133 }
134
135 func (b BaseConfig) DBDir() string {
136         return rootify(b.DBPath, b.RootDir)
137 }
138
139 func (b BaseConfig) KeysDir() string {
140         return rootify(b.KeysPath, b.RootDir)
141 }
142
143 // P2PConfig
144 type P2PConfig struct {
145         ListenAddress    string `mapstructure:"laddr"`
146         Seeds            string `mapstructure:"seeds"`
147         PrivateKey       string `mapstructure:"node_key"`
148         NodeKeyFile      string `mapstructure:"node_key_file"`
149         SkipUPNP         bool   `mapstructure:"skip_upnp"`
150         LANDiscover      bool   `mapstructure:"lan_discoverable"`
151         MaxNumPeers      int    `mapstructure:"max_num_peers"`
152         HandshakeTimeout int    `mapstructure:"handshake_timeout"`
153         DialTimeout      int    `mapstructure:"dial_timeout"`
154         ProxyAddress     string `mapstructure:"proxy_address"`
155         ProxyUsername    string `mapstructure:"proxy_username"`
156         ProxyPassword    string `mapstructure:"proxy_password"`
157         KeepDial         string `mapstructure:"keep_dial"`
158 }
159
160 // Default configurable p2p parameters.
161 func DefaultP2PConfig() *P2PConfig {
162         return &P2PConfig{
163                 ListenAddress:    "tcp://0.0.0.0:46656",
164                 NodeKeyFile:      "nodekey",
165                 SkipUPNP:         false,
166                 LANDiscover:      true,
167                 MaxNumPeers:      50,
168                 HandshakeTimeout: 30,
169                 DialTimeout:      3,
170                 ProxyAddress:     "",
171                 ProxyUsername:    "",
172                 ProxyPassword:    "",
173         }
174 }
175
176 //-----------------------------------------------------------------------------
177 type WalletConfig struct {
178         Disable  bool   `mapstructure:"disable"`
179         Rescan   bool   `mapstructure:"rescan"`
180         TxIndex  bool   `mapstructure:"txindex"`
181         MaxTxFee uint64 `mapstructure:"max_tx_fee"`
182 }
183
184 type RPCAuthConfig struct {
185         Disable bool `mapstructure:"disable"`
186 }
187
188 type WebConfig struct {
189         Closed bool `mapstructure:"closed"`
190 }
191
192 type WebsocketConfig struct {
193         MaxNumWebsockets     int `mapstructure:"max_num_websockets"`
194         MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
195 }
196
197 // Default configurable rpc's auth parameters.
198 func DefaultRPCAuthConfig() *RPCAuthConfig {
199         return &RPCAuthConfig{
200                 Disable: false,
201         }
202 }
203
204 // Default configurable web parameters.
205 func DefaultWebConfig() *WebConfig {
206         return &WebConfig{
207                 Closed: false,
208         }
209 }
210
211 // Default configurable wallet parameters.
212 func DefaultWalletConfig() *WalletConfig {
213         return &WalletConfig{
214                 Disable:  false,
215                 Rescan:   false,
216                 TxIndex:  false,
217                 MaxTxFee: uint64(1000000000),
218         }
219 }
220
221 func DefaultWebsocketConfig() *WebsocketConfig {
222         return &WebsocketConfig{
223                 MaxNumWebsockets:     25,
224                 MaxNumConcurrentReqs: 20,
225         }
226 }
227
228 //-----------------------------------------------------------------------------
229 // Utils
230
231 // helper function to make config creation independent of root dir
232 func rootify(path, root string) string {
233         if filepath.IsAbs(path) {
234                 return path
235         }
236         return filepath.Join(root, path)
237 }
238
239 // DefaultDataDir is the default data directory to use for the databases and other
240 // persistence requirements.
241 func DefaultDataDir() string {
242         // Try to place the data folder in the user's home dir
243         home := homeDir()
244         if home == "" {
245                 return "./.bytom"
246         }
247         switch runtime.GOOS {
248         case "darwin":
249                 // In order to be compatible with old data path,
250                 // copy the data from the old path to the new path
251                 oldPath := filepath.Join(home, "Library", "Bytom")
252                 newPath := filepath.Join(home, "Library", "Application Support", "Bytom")
253                 if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) {
254                         if err := os.Rename(oldPath, newPath); err != nil {
255                                 log.Errorf("DefaultDataDir: %v", err)
256                                 return oldPath
257                         }
258                 }
259                 return newPath
260         case "windows":
261                 return filepath.Join(home, "AppData", "Roaming", "Bytom")
262         default:
263                 return filepath.Join(home, ".bytom")
264         }
265 }
266
267 func isFolderNotExists(path string) bool {
268         _, err := os.Stat(path)
269         return os.IsNotExist(err)
270 }
271
272 func homeDir() string {
273         if home := os.Getenv("HOME"); home != "" {
274                 return home
275         }
276         if usr, err := user.Current(); err == nil {
277                 return usr.HomeDir
278         }
279         return ""
280 }