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"`
125 // Default configurable base parameters.
126 func DefaultBaseConfig() BaseConfig {
128 Moniker: "anonymous",
129 ProfListenAddress: "",
131 DBBackend: "leveldb",
133 KeysPath: "keystore",
137 func (b BaseConfig) DBDir() string {
138 return rootify(b.DBPath, b.RootDir)
141 func (b BaseConfig) KeysDir() string {
142 return rootify(b.KeysPath, b.RootDir)
146 type P2PConfig struct {
147 ListenAddress string `mapstructure:"laddr"`
148 Seeds string `mapstructure:"seeds"`
149 PrivateKey string `mapstructure:"node_key"`
150 NodeKeyFile string `mapstructure:"node_key_file"`
151 SkipUPNP bool `mapstructure:"skip_upnp"`
152 LANDiscover bool `mapstructure:"lan_discoverable"`
153 MaxNumPeers int `mapstructure:"max_num_peers"`
154 HandshakeTimeout int `mapstructure:"handshake_timeout"`
155 DialTimeout int `mapstructure:"dial_timeout"`
156 ProxyAddress string `mapstructure:"proxy_address"`
157 ProxyUsername string `mapstructure:"proxy_username"`
158 ProxyPassword string `mapstructure:"proxy_password"`
159 KeepDial string `mapstructure:"keep_dial"`
162 // Default configurable p2p parameters.
163 func DefaultP2PConfig() *P2PConfig {
165 ListenAddress: "tcp://0.0.0.0:46656",
166 NodeKeyFile: "nodekey",
170 HandshakeTimeout: 30,
178 //-----------------------------------------------------------------------------
179 type WalletConfig struct {
180 Disable bool `mapstructure:"disable"`
181 Rescan bool `mapstructure:"rescan"`
182 TxIndex bool `mapstructure:"txindex"`
183 MaxTxFee uint64 `mapstructure:"max_tx_fee"`
186 type RPCAuthConfig struct {
187 Disable bool `mapstructure:"disable"`
190 type WebConfig struct {
191 Closed bool `mapstructure:"closed"`
194 type WebsocketConfig struct {
195 MaxNumWebsockets int `mapstructure:"max_num_websockets"`
196 MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
199 type FederationConfig struct {
200 Xpubs []chainkd.XPub `json:"xpubs"`
201 Quorum int `json:"quorum"`
204 // Default configurable rpc's auth parameters.
205 func DefaultRPCAuthConfig() *RPCAuthConfig {
206 return &RPCAuthConfig{
211 // Default configurable web parameters.
212 func DefaultWebConfig() *WebConfig {
218 // Default configurable wallet parameters.
219 func DefaultWalletConfig() *WalletConfig {
220 return &WalletConfig{
224 MaxTxFee: uint64(1000000000),
228 func DefaultWebsocketConfig() *WebsocketConfig {
229 return &WebsocketConfig{
230 MaxNumWebsockets: 25,
231 MaxNumConcurrentReqs: 20,
235 func DefaultFederationConfig() *FederationConfig {
236 return &FederationConfig{
237 Xpubs: []chainkd.XPub{
238 xpub("7f23aae65ee4307c38d342699e328f21834488e18191ebd66823d220b5a58303496c9d09731784372bade78d5e9a4a6249b2cfe2e3a85464e5a4017aa5611e47"),
239 xpub("585e20143db413e45fbc82f03cb61f177e9916ef1df0012daa8cbf6dbb1025ce8f98e51ae319327b63505b64fdbbf6d36ef916d79e6dd67d51b0bfe76fe544c5"),
240 xpub("b58170b51ca61604028ba1cb412377dfc2bc6567c0afc84c83aae1c0c297d0227ccf568561df70851f4144bbf069b525129f2434133c145e35949375b22a6c9d"),
241 xpub("983705ae71949c1a5d0fcf953658dd9ecc549f02c63e197b4d087ae31148097ece816bbc60d9012c316139fc550fa0f4b00beb0887f6b152f7a69bc8f392b9fa"),
242 xpub("d72fb92fa13bf3e0deb39de3a47c8d6eef5584719f7877c82a4c009f78fddf924d9706d48f15b2c782ec80b6bdd621a1f7ba2a0044b0e6f92245de9436885cb9"),
243 xpub("6798460919e8dc7095ee8b9f9d65033ef3da8c2334813149da5a1e52e9c6da07ba7d0e7379baaa0c8bdcb21890a54e6b7290bee077c645ee4b74b0c1ae9da59a"),
249 func xpub(str string) (xpub chainkd.XPub) {
250 if err := xpub.UnmarshalText([]byte(str)); err != nil {
251 log.Panicf("Fail converts a string to xpub")
256 //-----------------------------------------------------------------------------
259 // helper function to make config creation independent of root dir
260 func rootify(path, root string) string {
261 if filepath.IsAbs(path) {
264 return filepath.Join(root, path)
267 // DefaultDataDir is the default data directory to use for the databases and other
268 // persistence requirements.
269 func DefaultDataDir() string {
270 // Try to place the data folder in the user's home dir
275 switch runtime.GOOS {
277 // In order to be compatible with old data path,
278 // copy the data from the old path to the new path
279 oldPath := filepath.Join(home, "Library", "Vapor")
280 newPath := filepath.Join(home, "Library", "Application Support", "Vapor")
281 if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) {
282 if err := os.Rename(oldPath, newPath); err != nil {
283 log.Errorf("DefaultDataDir: %v", err)
289 return filepath.Join(home, "AppData", "Roaming", "Vapor")
291 return filepath.Join(home, ".vapor")
295 func isFolderNotExists(path string) bool {
296 _, err := os.Stat(path)
297 return os.IsNotExist(err)
300 func homeDir() string {
301 if home := os.Getenv("HOME"); home != "" {
304 if usr, err := user.Current(); err == nil {