OSDN Git Service

V0.1 federation parse (#89)
[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         "github.com/vapor/crypto/ed25519/chainkd"
15 )
16
17 var (
18         // CommonConfig means config object
19         CommonConfig *Config
20 )
21
22 type Config struct {
23         // Top level options use an anonymous struct
24         BaseConfig `mapstructure:",squash"`
25         // Options for services
26         P2P        *P2PConfig        `mapstructure:"p2p"`
27         Wallet     *WalletConfig     `mapstructure:"wallet"`
28         Auth       *RPCAuthConfig    `mapstructure:"auth"`
29         Web        *WebConfig        `mapstructure:"web"`
30         Websocket  *WebsocketConfig  `mapstructure:"ws"`
31         Federation *FederationConfig `mapstructure:"federation"`
32 }
33
34 // Default configurable parameters.
35 func DefaultConfig() *Config {
36         return &Config{
37                 BaseConfig: DefaultBaseConfig(),
38                 P2P:        DefaultP2PConfig(),
39                 Wallet:     DefaultWalletConfig(),
40                 Auth:       DefaultRPCAuthConfig(),
41                 Web:        DefaultWebConfig(),
42                 Websocket:  DefaultWebsocketConfig(),
43                 Federation: DefaultFederationConfig(),
44         }
45 }
46
47 // Set the RootDir for all Config structs
48 func (cfg *Config) SetRoot(root string) *Config {
49         cfg.BaseConfig.RootDir = root
50         return cfg
51 }
52
53 // NodeKey retrieves the currently configured private key of the node, checking
54 // first any manually set key, falling back to the one found in the configured
55 // data folder. If no key can be found, a new one is generated.
56 func (cfg *Config) NodeKey() (string, error) {
57         // Use any specifically configured key.
58         if cfg.P2P.PrivateKey != "" {
59                 return cfg.P2P.PrivateKey, nil
60         }
61
62         keyFile := rootify(cfg.P2P.NodeKeyFile, cfg.BaseConfig.RootDir)
63         buf := make([]byte, ed25519.PrivateKeySize*2)
64         fd, err := os.Open(keyFile)
65         defer fd.Close()
66         if err == nil {
67                 if _, err = io.ReadFull(fd, buf); err == nil {
68                         return string(buf), nil
69                 }
70         }
71
72         log.WithField("err", err).Warning("key file access failed")
73         _, privKey, err := ed25519.GenerateKey(nil)
74         if err != nil {
75                 return "", err
76         }
77
78         if err = ioutil.WriteFile(keyFile, []byte(privKey.String()), 0600); err != nil {
79                 return "", err
80         }
81         return privKey.String(), nil
82 }
83
84 //-----------------------------------------------------------------------------
85 // BaseConfig
86 type BaseConfig struct {
87         // The root directory for all data.
88         // This should be set in viper so it can unmarshal into this struct
89         RootDir string `mapstructure:"home"`
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         // Cipher Service Provider
122         // CipherServiceProvider string `mapstructure:"csp"`
123
124         // Federation file name
125         FederationFileName string `mapstructure:"federation_file"`
126 }
127
128 // Default configurable base parameters.
129 func DefaultBaseConfig() BaseConfig {
130         return BaseConfig{
131                 Moniker:            "anonymous",
132                 ProfListenAddress:  "",
133                 Mining:             false,
134                 DBBackend:          "leveldb",
135                 DBPath:             "data",
136                 KeysPath:           "keystore",
137                 FederationFileName: "federation.json",
138         }
139 }
140
141 func (b BaseConfig) DBDir() string {
142         return rootify(b.DBPath, b.RootDir)
143 }
144
145 func (b BaseConfig) KeysDir() string {
146         return rootify(b.KeysPath, b.RootDir)
147 }
148
149 func (b BaseConfig) FederationFile() string {
150         return rootify(b.FederationFileName, b.RootDir)
151 }
152
153 // P2PConfig
154 type P2PConfig struct {
155         ListenAddress    string `mapstructure:"laddr"`
156         Seeds            string `mapstructure:"seeds"`
157         PrivateKey       string `mapstructure:"node_key"`
158         NodeKeyFile      string `mapstructure:"node_key_file"`
159         SkipUPNP         bool   `mapstructure:"skip_upnp"`
160         LANDiscover      bool   `mapstructure:"lan_discoverable"`
161         MaxNumPeers      int    `mapstructure:"max_num_peers"`
162         HandshakeTimeout int    `mapstructure:"handshake_timeout"`
163         DialTimeout      int    `mapstructure:"dial_timeout"`
164         ProxyAddress     string `mapstructure:"proxy_address"`
165         ProxyUsername    string `mapstructure:"proxy_username"`
166         ProxyPassword    string `mapstructure:"proxy_password"`
167         KeepDial         string `mapstructure:"keep_dial"`
168 }
169
170 // Default configurable p2p parameters.
171 func DefaultP2PConfig() *P2PConfig {
172         return &P2PConfig{
173                 ListenAddress:    "tcp://0.0.0.0:46656",
174                 NodeKeyFile:      "nodekey",
175                 SkipUPNP:         false,
176                 LANDiscover:      true,
177                 MaxNumPeers:      50,
178                 HandshakeTimeout: 30,
179                 DialTimeout:      3,
180                 ProxyAddress:     "",
181                 ProxyUsername:    "",
182                 ProxyPassword:    "",
183         }
184 }
185
186 //-----------------------------------------------------------------------------
187 type WalletConfig struct {
188         Disable  bool   `mapstructure:"disable"`
189         Rescan   bool   `mapstructure:"rescan"`
190         TxIndex  bool   `mapstructure:"txindex"`
191         MaxTxFee uint64 `mapstructure:"max_tx_fee"`
192 }
193
194 type RPCAuthConfig struct {
195         Disable bool `mapstructure:"disable"`
196 }
197
198 type WebConfig struct {
199         Closed bool `mapstructure:"closed"`
200 }
201
202 type WebsocketConfig struct {
203         MaxNumWebsockets     int `mapstructure:"max_num_websockets"`
204         MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
205 }
206
207 type FederationConfig struct {
208         Xpubs  []chainkd.XPub `json:"xpubs"`
209         Quorum int            `json:"quorum"`
210 }
211
212 // Default configurable rpc's auth parameters.
213 func DefaultRPCAuthConfig() *RPCAuthConfig {
214         return &RPCAuthConfig{
215                 Disable: false,
216         }
217 }
218
219 // Default configurable web parameters.
220 func DefaultWebConfig() *WebConfig {
221         return &WebConfig{
222                 Closed: false,
223         }
224 }
225
226 // Default configurable wallet parameters.
227 func DefaultWalletConfig() *WalletConfig {
228         return &WalletConfig{
229                 Disable:  false,
230                 Rescan:   false,
231                 TxIndex:  false,
232                 MaxTxFee: uint64(1000000000),
233         }
234 }
235
236 func DefaultWebsocketConfig() *WebsocketConfig {
237         return &WebsocketConfig{
238                 MaxNumWebsockets:     25,
239                 MaxNumConcurrentReqs: 20,
240         }
241 }
242
243 func DefaultFederationConfig() *FederationConfig {
244         return &FederationConfig{
245                 Xpubs: []chainkd.XPub{
246                         xpub("7f23aae65ee4307c38d342699e328f21834488e18191ebd66823d220b5a58303496c9d09731784372bade78d5e9a4a6249b2cfe2e3a85464e5a4017aa5611e47"),
247                         xpub("585e20143db413e45fbc82f03cb61f177e9916ef1df0012daa8cbf6dbb1025ce8f98e51ae319327b63505b64fdbbf6d36ef916d79e6dd67d51b0bfe76fe544c5"),
248                         xpub("b58170b51ca61604028ba1cb412377dfc2bc6567c0afc84c83aae1c0c297d0227ccf568561df70851f4144bbf069b525129f2434133c145e35949375b22a6c9d"),
249                         xpub("983705ae71949c1a5d0fcf953658dd9ecc549f02c63e197b4d087ae31148097ece816bbc60d9012c316139fc550fa0f4b00beb0887f6b152f7a69bc8f392b9fa"),
250                         xpub("d72fb92fa13bf3e0deb39de3a47c8d6eef5584719f7877c82a4c009f78fddf924d9706d48f15b2c782ec80b6bdd621a1f7ba2a0044b0e6f92245de9436885cb9"),
251                         xpub("6798460919e8dc7095ee8b9f9d65033ef3da8c2334813149da5a1e52e9c6da07ba7d0e7379baaa0c8bdcb21890a54e6b7290bee077c645ee4b74b0c1ae9da59a"),
252                 },
253                 Quorum: 4,
254         }
255 }
256
257 func xpub(str string) (xpub chainkd.XPub) {
258         if err := xpub.UnmarshalText([]byte(str)); err != nil {
259                 log.Panicf("Fail converts a string to xpub")
260         }
261         return xpub
262 }
263
264 //-----------------------------------------------------------------------------
265 // Utils
266
267 // helper function to make config creation independent of root dir
268 func rootify(path, root string) string {
269         if filepath.IsAbs(path) {
270                 return path
271         }
272         return filepath.Join(root, path)
273 }
274
275 // DefaultDataDir is the default data directory to use for the databases and other
276 // persistence requirements.
277 func DefaultDataDir() string {
278         // Try to place the data folder in the user's home dir
279         home := homeDir()
280         if home == "" {
281                 return "./.vapor"
282         }
283         switch runtime.GOOS {
284         case "darwin":
285                 // In order to be compatible with old data path,
286                 // copy the data from the old path to the new path
287                 oldPath := filepath.Join(home, "Library", "Vapor")
288                 newPath := filepath.Join(home, "Library", "Application Support", "Vapor")
289                 if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) {
290                         if err := os.Rename(oldPath, newPath); err != nil {
291                                 log.Errorf("DefaultDataDir: %v", err)
292                                 return oldPath
293                         }
294                 }
295                 return newPath
296         case "windows":
297                 return filepath.Join(home, "AppData", "Roaming", "Vapor")
298         default:
299                 return filepath.Join(home, ".vapor")
300         }
301 }
302
303 func isFolderNotExists(path string) bool {
304         _, err := os.Stat(path)
305         return os.IsNotExist(err)
306 }
307
308 func homeDir() string {
309         if home := os.Getenv("HOME"); home != "" {
310                 return home
311         }
312         if usr, err := user.Current(); err == nil {
313                 return usr.HomeDir
314         }
315         return ""
316 }