11 log "github.com/sirupsen/logrus"
13 "github.com/bytom/bytom/crypto/ed25519/chainkd"
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 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 Simd: DefaultSimdConfig(),
43 Websocket: DefaultWebsocketConfig(),
44 Federation: DefaultFederationConfig(),
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) PrivateKey() *chainkd.XPrv {
62 filePath := rootify(cfg.PrivateKeyFile, cfg.BaseConfig.RootDir)
63 fildReader, err := os.Open(filePath)
65 log.WithField("err", err).Panic("fail on open private key file")
68 defer fildReader.Close()
69 buf := make([]byte, 128)
70 if _, err = io.ReadFull(fildReader, buf); err != nil {
71 log.WithField("err", err).Panic("fail on read private key file")
75 if _, err := hex.Decode(xprv[:], buf); err != nil {
76 log.WithField("err", err).Panic("fail on decode private key")
80 xpub := cfg.XPrv.XPub()
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 alias of the node
93 NodeAlias string `mapstructure:"node_alias"`
95 // The ID of the network to json
96 ChainID string `mapstructure:"chain_id"`
99 LogLevel string `mapstructure:"log_level"`
101 // A custom human readable name for this node
102 Moniker string `mapstructure:"moniker"`
104 // TCP or UNIX socket address for the profiling server to listen on
105 ProfListenAddress string `mapstructure:"prof_laddr"`
107 Mining bool `mapstructure:"mining"`
109 // Database backend: leveldb | memdb
110 DBBackend string `mapstructure:"db_backend"`
112 // Database directory
113 DBPath string `mapstructure:"db_dir"`
115 // Keystore directory
116 KeysPath string `mapstructure:"keys_dir"`
118 ApiAddress string `mapstructure:"api_addr"`
120 VaultMode bool `mapstructure:"vault_mode"`
123 LogFile string `mapstructure:"log_file"`
125 PrivateKeyFile string `mapstructure:"private_key_file"`
129 FederationFileName string `mapstructure:"federation_file"`
132 // Default configurable base parameters.
133 func DefaultBaseConfig() BaseConfig {
135 Moniker: "anonymous",
136 ProfListenAddress: "",
138 DBBackend: "leveldb",
140 KeysPath: "keystore",
143 PrivateKeyFile: "node_key.txt",
144 FederationFileName: "federation.json",
148 func (b BaseConfig) DBDir() string {
149 return rootify(b.DBPath, b.RootDir)
152 func (b BaseConfig) LogDir() string {
153 return rootify(b.LogFile, b.RootDir)
156 func (b BaseConfig) KeysDir() string {
157 return rootify(b.KeysPath, b.RootDir)
160 func (b BaseConfig) FederationFile() string {
161 return rootify(b.FederationFileName, b.RootDir)
165 type P2PConfig struct {
166 ListenAddress string `mapstructure:"laddr"`
167 Seeds string `mapstructure:"seeds"`
168 SkipUPNP bool `mapstructure:"skip_upnp"`
169 LANDiscover bool `mapstructure:"lan_discoverable"`
170 MaxNumPeers int `mapstructure:"max_num_peers"`
171 HandshakeTimeout int `mapstructure:"handshake_timeout"`
172 DialTimeout int `mapstructure:"dial_timeout"`
173 ProxyAddress string `mapstructure:"proxy_address"`
174 ProxyUsername string `mapstructure:"proxy_username"`
175 ProxyPassword string `mapstructure:"proxy_password"`
176 KeepDial string `mapstructure:"keep_dial"`
179 // Default configurable p2p parameters.
180 func DefaultP2PConfig() *P2PConfig {
182 ListenAddress: "tcp://0.0.0.0:46656",
186 HandshakeTimeout: 30,
194 // -----------------------------------------------------------------------------
195 type WalletConfig struct {
196 Disable bool `mapstructure:"disable"`
197 Rescan bool `mapstructure:"rescan"`
198 TxIndex bool `mapstructure:"txindex"`
199 MaxTxFee uint64 `mapstructure:"max_tx_fee"`
202 type RPCAuthConfig struct {
203 Disable bool `mapstructure:"disable"`
206 type WebConfig struct {
207 Closed bool `mapstructure:"closed"`
210 type SimdConfig struct {
211 Enable bool `mapstructure:"enable"`
214 type WebsocketConfig struct {
215 MaxNumWebsockets int `mapstructure:"max_num_websockets"`
216 MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
219 type FederationConfig struct {
220 FederationScript string `json:"federation_script"`
221 Xpubs []chainkd.XPub `json:"xpubs"`
222 Quorum int `json:"quorum"`
225 // Default configurable rpc's auth parameters.
226 func DefaultRPCAuthConfig() *RPCAuthConfig {
227 return &RPCAuthConfig{
232 // Default configurable web parameters.
233 func DefaultWebConfig() *WebConfig {
239 // Default configurable wallet parameters.
240 func DefaultWalletConfig() *WalletConfig {
241 return &WalletConfig{
245 MaxTxFee: uint64(1000000000),
249 // Default configurable web parameters.
250 func DefaultSimdConfig() *SimdConfig {
256 func DefaultWebsocketConfig() *WebsocketConfig {
257 return &WebsocketConfig{
258 MaxNumWebsockets: 25,
259 MaxNumConcurrentReqs: 20,
263 // Default configurable federation parameters.
264 func DefaultFederationConfig() *FederationConfig {
265 return &FederationConfig{
266 Xpubs: []chainkd.XPub{
267 xpub("2e171e9aed46633f3560cf4d207c4edb92e5ad6b6f63daee44aa0ed4c58f76fd4d0081f225d2b119ac398749dbc7aa113603bc7710693c54852d33b6b082daab"),
268 xpub("896285b552bfe0647c0effaee41e5ce98a77981396455259792300cfbc0988bfb1a723488cedf0e73c3220e273fb6843abfbee025d7401b67bf81641b208dfc1"),
269 xpub("aa5cb0d5d193a141ce66dd3448e8d74d73bed1131ea05b130c14c95ad04b0295f2d4d3f421ae10a2517f7431e0eca119fea509e0650bd20b4a64b856b5473f35"),
270 xpub("98e6ab8c654bb31e0c432a2c9ff13a6e3419dcb8a1df94f2839f41d79e94b6ca7a68f60b793d947195f761187b37275fbeb345041d5ea3039c5d328b63e3d489"),
276 func xpub(str string) (xpub chainkd.XPub) {
277 if err := xpub.UnmarshalText([]byte(str)); err != nil {
278 log.Panicf("Fail converts a string to xpub")
283 // -----------------------------------------------------------------------------
286 // helper function to make config creation independent of root dir
287 func rootify(path, root string) string {
288 if filepath.IsAbs(path) {
291 return filepath.Join(root, path)
294 // DefaultDataDir is the default data directory to use for the databases and other
295 // persistence requirements.
296 func DefaultDataDir() string {
297 // Try to place the data folder in the user's home dir
302 switch runtime.GOOS {
304 // In order to be compatible with old data path,
305 // copy the data from the old path to the new path
306 oldPath := filepath.Join(home, "Library", "Bytom")
307 newPath := filepath.Join(home, "Library", "Application Support", "Bytom")
308 if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) {
309 if err := os.Rename(oldPath, newPath); err != nil {
310 log.Errorf("DefaultDataDir: %v", err)
316 return filepath.Join(home, "AppData", "Roaming", "Bytom")
318 return filepath.Join(home, ".bytom")
322 func isFolderNotExists(path string) bool {
323 _, err := os.Stat(path)
324 return os.IsNotExist(err)
327 func homeDir() string {
328 if home := os.Getenv("HOME"); home != "" {
331 if usr, err := user.Current(); err == nil {