11 log "github.com/sirupsen/logrus"
13 "github.com/vapor/crypto/ed25519"
14 "github.com/vapor/crypto/ed25519/chainkd"
18 // CommonConfig means config object
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"`
34 // Default configurable parameters.
35 func DefaultConfig() *Config {
37 BaseConfig: DefaultBaseConfig(),
38 P2P: DefaultP2PConfig(),
39 Wallet: DefaultWalletConfig(),
40 Auth: DefaultRPCAuthConfig(),
41 Web: DefaultWebConfig(),
42 Websocket: DefaultWebsocketConfig(),
43 Federation: DefaultFederationConfig(),
47 // Set the RootDir for all Config structs
48 func (cfg *Config) SetRoot(root string) *Config {
49 cfg.BaseConfig.RootDir = root
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
62 keyFile := rootify(cfg.P2P.NodeKeyFile, cfg.BaseConfig.RootDir)
63 buf := make([]byte, ed25519.PrivateKeySize*2)
64 fd, err := os.Open(keyFile)
67 if _, err = io.ReadFull(fd, buf); err == nil {
68 return string(buf), nil
72 log.WithField("err", err).Warning("key file access failed")
73 _, privKey, err := ed25519.GenerateKey(nil)
78 if err = ioutil.WriteFile(keyFile, []byte(privKey.String()), 0600); err != nil {
81 return privKey.String(), nil
84 //-----------------------------------------------------------------------------
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"`
91 //The ID of the network to json
92 ChainID string `mapstructure:"chain_id"`
95 LogLevel string `mapstructure:"log_level"`
97 // A custom human readable name for this node
98 Moniker string `mapstructure:"moniker"`
100 // TCP or UNIX socket address for the profiling server to listen on
101 ProfListenAddress string `mapstructure:"prof_laddr"`
103 Mining bool `mapstructure:"mining"`
105 // Database backend: leveldb | memdb
106 DBBackend string `mapstructure:"db_backend"`
108 // Database directory
109 DBPath string `mapstructure:"db_dir"`
111 // Keystore directory
112 KeysPath string `mapstructure:"keys_dir"`
114 ApiAddress string `mapstructure:"api_addr"`
116 VaultMode bool `mapstructure:"vault_mode"`
119 LogFile string `mapstructure:"log_file"`
121 // Cipher Service Provider
122 // CipherServiceProvider string `mapstructure:"csp"`
124 // Federation file name
125 FederationFileName string `mapstructure:"federation_file"`
128 // Default configurable base parameters.
129 func DefaultBaseConfig() BaseConfig {
131 Moniker: "anonymous",
132 ProfListenAddress: "",
134 DBBackend: "leveldb",
136 KeysPath: "keystore",
137 FederationFileName: "federation.json",
141 func (b BaseConfig) DBDir() string {
142 return rootify(b.DBPath, b.RootDir)
145 func (b BaseConfig) KeysDir() string {
146 return rootify(b.KeysPath, b.RootDir)
149 func (b BaseConfig) FederationFile() string {
150 return rootify(b.FederationFileName, b.RootDir)
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"`
170 // Default configurable p2p parameters.
171 func DefaultP2PConfig() *P2PConfig {
173 ListenAddress: "tcp://0.0.0.0:46656",
174 NodeKeyFile: "nodekey",
178 HandshakeTimeout: 30,
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"`
194 type RPCAuthConfig struct {
195 Disable bool `mapstructure:"disable"`
198 type WebConfig struct {
199 Closed bool `mapstructure:"closed"`
202 type WebsocketConfig struct {
203 MaxNumWebsockets int `mapstructure:"max_num_websockets"`
204 MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
207 type FederationConfig struct {
208 Xpubs []chainkd.XPub `json:"xpubs"`
209 Quorum int `json:"quorum"`
212 // Default configurable rpc's auth parameters.
213 func DefaultRPCAuthConfig() *RPCAuthConfig {
214 return &RPCAuthConfig{
219 // Default configurable web parameters.
220 func DefaultWebConfig() *WebConfig {
226 // Default configurable wallet parameters.
227 func DefaultWalletConfig() *WalletConfig {
228 return &WalletConfig{
232 MaxTxFee: uint64(1000000000),
236 func DefaultWebsocketConfig() *WebsocketConfig {
237 return &WebsocketConfig{
238 MaxNumWebsockets: 25,
239 MaxNumConcurrentReqs: 20,
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"),
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")
264 //-----------------------------------------------------------------------------
267 // helper function to make config creation independent of root dir
268 func rootify(path, root string) string {
269 if filepath.IsAbs(path) {
272 return filepath.Join(root, path)
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
283 switch runtime.GOOS {
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)
297 return filepath.Join(home, "AppData", "Roaming", "Vapor")
299 return filepath.Join(home, ".vapor")
303 func isFolderNotExists(path string) bool {
304 _, err := os.Stat(path)
305 return os.IsNotExist(err)
308 func homeDir() string {
309 if home := os.Getenv("HOME"); home != "" {
312 if usr, err := user.Current(); err == nil {