github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/node/config.go (about) 1 package node 2 3 import ( 4 "crypto/ecdsa" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "runtime" 10 "strings" 11 12 "github.com/neatlab/neatio/network/rpc" 13 14 "github.com/neatlab/neatio/chain/accounts" 15 "github.com/neatlab/neatio/chain/accounts/keystore" 16 "github.com/neatlab/neatio/chain/accounts/usbwallet" 17 "github.com/neatlab/neatio/chain/log" 18 "github.com/neatlab/neatio/network/p2p" 19 "github.com/neatlab/neatio/network/p2p/discover" 20 "github.com/neatlab/neatio/utilities/common" 21 "github.com/neatlab/neatio/utilities/crypto" 22 ) 23 24 const ( 25 datadirPrivateKey = "nodekey" 26 datadirDefaultKeyStore = "keystore" 27 datadirStaticNodes = "static-nodes.json" 28 datadirTrustedNodes = "trusted-nodes.json" 29 datadirNodeDatabase = "nodes" 30 ) 31 32 type Config struct { 33 Name string `toml:"-"` 34 35 ChainId string `toml:",omitempty"` 36 37 UserIdent string `toml:",omitempty"` 38 39 Version string `toml:"-"` 40 41 GeneralDataDir string 42 43 DataDir string 44 45 P2P p2p.Config 46 47 KeyStoreDir string `toml:",omitempty"` 48 49 UseLightweightKDF bool `toml:",omitempty"` 50 51 NoUSB bool `toml:",omitempty"` 52 53 IPCPath string `toml:",omitempty"` 54 55 HTTPHost string `toml:",omitempty"` 56 57 HTTPPort int `toml:",omitempty"` 58 59 HTTPCors []string `toml:",omitempty"` 60 61 HTTPVirtualHosts []string `toml:",omitempty"` 62 63 HTTPModules []string `toml:",omitempty"` 64 65 HTTPTimeouts rpc.HTTPTimeouts 66 67 WSHost string `toml:",omitempty"` 68 69 WSPort int `toml:",omitempty"` 70 71 WSOrigins []string `toml:",omitempty"` 72 73 WSModules []string `toml:",omitempty"` 74 75 WSExposeAll bool `toml:",omitempty"` 76 77 Logger log.Logger `toml:",omitempty"` 78 } 79 80 func (c *Config) IPCEndpoint() string { 81 82 if c.IPCPath == "" { 83 return "" 84 } 85 86 if runtime.GOOS == "windows" { 87 if strings.HasPrefix(c.IPCPath, `\\.\pipe\`) { 88 return c.IPCPath 89 } 90 return `\\.\pipe\` + c.ChainId + `\` + c.IPCPath 91 } 92 93 if filepath.Base(c.IPCPath) == c.IPCPath { 94 if c.DataDir == "" { 95 return filepath.Join(os.TempDir(), c.IPCPath) 96 } 97 return filepath.Join(c.DataDir, c.IPCPath) 98 } 99 return c.IPCPath 100 } 101 102 func (c *Config) NodeDB() string { 103 if c.GeneralDataDir == "" { 104 return "" 105 } 106 return c.ResolvePath(datadirNodeDatabase) 107 } 108 109 func DefaultIPCEndpoint(clientIdentifier string) string { 110 if clientIdentifier == "" { 111 clientIdentifier = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") 112 if clientIdentifier == "" { 113 panic("empty executable name") 114 } 115 } 116 config := &Config{DataDir: DefaultDataDir(), IPCPath: clientIdentifier + ".ipc"} 117 return config.IPCEndpoint() 118 } 119 120 func (c *Config) HTTPEndpoint() string { 121 if c.HTTPHost == "" { 122 return "" 123 } 124 return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort) 125 } 126 127 func DefaultHTTPEndpoint() string { 128 config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort} 129 return config.HTTPEndpoint() 130 } 131 132 func (c *Config) WSEndpoint() string { 133 if c.WSHost == "" { 134 return "" 135 } 136 return fmt.Sprintf("%s:%d", c.WSHost, c.WSPort) 137 } 138 139 func DefaultWSEndpoint() string { 140 config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort} 141 return config.WSEndpoint() 142 } 143 144 func (c *Config) NodeName() string { 145 name := c.name() 146 147 if c.UserIdent != "" { 148 name += "/" + c.UserIdent 149 } 150 if c.Version != "" { 151 name += "/v" + c.Version 152 } 153 name += "/" + runtime.GOOS + "-" + runtime.GOARCH 154 name += "/" + runtime.Version() 155 return name 156 } 157 158 func (c *Config) name() string { 159 if c.Name == "" { 160 progname := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") 161 if progname == "" { 162 panic("empty executable name, set Config.Name") 163 } 164 return progname 165 } 166 return c.Name 167 } 168 169 var isOldGethResource = map[string]bool{ 170 "chaindata": true, 171 "nodes": true, 172 "nodekey": true, 173 "static-nodes.json": true, 174 "trusted-nodes.json": true, 175 } 176 177 var isGeneralResource = map[string]bool{ 178 "nodes": true, 179 "nodekey": true, 180 "static-nodes.json": true, 181 "trusted-nodes.json": true, 182 } 183 184 func (c *Config) ResolvePath(path string) string { 185 if filepath.IsAbs(path) { 186 return path 187 } 188 if c.DataDir == "" { 189 return "" 190 } 191 192 if c.name() == "neatio" && isOldGethResource[path] { 193 oldpath := "" 194 if c.Name == "neatio" { 195 oldpath = filepath.Join(c.DataDir, path) 196 } 197 if oldpath != "" && common.FileExist(oldpath) { 198 199 return oldpath 200 } 201 } 202 203 if isGeneralResource[path] { 204 return filepath.Join(c.GeneralDataDir, path) 205 } 206 207 return filepath.Join(c.instanceDir(), path) 208 } 209 210 func (c *Config) instanceDir() string { 211 if c.DataDir == "" { 212 return "" 213 } 214 215 return filepath.Join(c.DataDir, c.name()) 216 } 217 218 func (c *Config) NodeKey() *ecdsa.PrivateKey { 219 220 if c.P2P.PrivateKey != nil { 221 return c.P2P.PrivateKey 222 } 223 224 if c.GeneralDataDir == "" { 225 key, err := crypto.GenerateKey() 226 if err != nil { 227 log.Crit(fmt.Sprintf("Failed to generate ephemeral node key: %v", err)) 228 } 229 return key 230 } 231 232 keyfile := c.ResolvePath(datadirPrivateKey) 233 if key, err := crypto.LoadECDSA(keyfile); err == nil { 234 return key 235 } 236 237 key, err := crypto.GenerateKey() 238 if err != nil { 239 log.Crit(fmt.Sprintf("Failed to generate node key: %v", err)) 240 } 241 242 if err := os.MkdirAll(c.GeneralDataDir, 0700); err != nil { 243 log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) 244 return key 245 } 246 keyfile = c.ResolvePath(datadirPrivateKey) 247 248 if err := crypto.SaveECDSA(keyfile, key); err != nil { 249 log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) 250 } 251 return key 252 } 253 254 func (c *Config) StaticNodes() []*discover.Node { 255 return c.parsePersistentNodes(c.ResolvePath(datadirStaticNodes)) 256 } 257 258 func (c *Config) TrustedNodes() []*discover.Node { 259 return c.parsePersistentNodes(c.ResolvePath(datadirTrustedNodes)) 260 } 261 262 func (c *Config) parsePersistentNodes(path string) []*discover.Node { 263 264 if c.DataDir == "" { 265 return nil 266 } 267 if _, err := os.Stat(path); err != nil { 268 return nil 269 } 270 271 var nodelist []string 272 if err := common.LoadJSON(path, &nodelist); err != nil { 273 log.Error(fmt.Sprintf("Can't load node file %s: %v", path, err)) 274 return nil 275 } 276 277 var nodes []*discover.Node 278 for _, url := range nodelist { 279 if url == "" { 280 continue 281 } 282 node, err := discover.ParseNode(url) 283 if err != nil { 284 log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) 285 continue 286 } 287 nodes = append(nodes, node) 288 } 289 return nodes 290 } 291 292 func (c *Config) AccountConfig() (int, int, string, error) { 293 scryptN := keystore.StandardScryptN 294 scryptP := keystore.StandardScryptP 295 if c.UseLightweightKDF { 296 scryptN = keystore.LightScryptN 297 scryptP = keystore.LightScryptP 298 } 299 300 var ( 301 keydir string 302 err error 303 ) 304 switch { 305 case filepath.IsAbs(c.KeyStoreDir): 306 keydir = c.KeyStoreDir 307 case c.DataDir != "": 308 if c.KeyStoreDir == "" { 309 keydir = filepath.Join(c.DataDir, datadirDefaultKeyStore) 310 } else { 311 keydir, err = filepath.Abs(c.KeyStoreDir) 312 } 313 case c.KeyStoreDir != "": 314 keydir, err = filepath.Abs(c.KeyStoreDir) 315 } 316 return scryptN, scryptP, keydir, err 317 } 318 319 func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { 320 scryptN, scryptP, keydir, err := conf.AccountConfig() 321 var ephemeral string 322 if keydir == "" { 323 324 keydir, err = ioutil.TempDir("", "neatio-keystore") 325 ephemeral = keydir 326 } 327 328 if err != nil { 329 return nil, "", err 330 } 331 if err := os.MkdirAll(keydir, 0700); err != nil { 332 return nil, "", err 333 } 334 335 backends := []accounts.Backend{ 336 keystore.NewKeyStore(keydir, scryptN, scryptP), 337 } 338 if !conf.NoUSB { 339 340 if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { 341 log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) 342 } else { 343 backends = append(backends, ledgerhub) 344 } 345 346 if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { 347 log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) 348 } else { 349 backends = append(backends, trezorhub) 350 } 351 } 352 return accounts.NewManager(backends...), ephemeral, nil 353 }