github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/internal/cli/server/config.go (about) 1 package server 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "math" 7 "math/big" 8 "os" 9 "path/filepath" 10 "runtime" 11 "strconv" 12 "strings" 13 "time" 14 15 godebug "runtime/debug" 16 17 "github.com/ethereum/go-ethereum/accounts" 18 "github.com/ethereum/go-ethereum/accounts/keystore" 19 "github.com/ethereum/go-ethereum/common" 20 "github.com/ethereum/go-ethereum/common/fdlimit" 21 "github.com/ethereum/go-ethereum/eth/downloader" 22 "github.com/ethereum/go-ethereum/eth/ethconfig" 23 "github.com/ethereum/go-ethereum/eth/gasprice" 24 "github.com/ethereum/go-ethereum/internal/cli/server/chains" 25 "github.com/ethereum/go-ethereum/log" 26 "github.com/ethereum/go-ethereum/node" 27 "github.com/ethereum/go-ethereum/p2p" 28 "github.com/ethereum/go-ethereum/p2p/enode" 29 "github.com/ethereum/go-ethereum/p2p/nat" 30 "github.com/ethereum/go-ethereum/params" 31 "github.com/hashicorp/hcl/v2/hclsimple" 32 "github.com/imdario/mergo" 33 "github.com/mitchellh/go-homedir" 34 gopsutil "github.com/shirou/gopsutil/mem" 35 ) 36 37 type Config struct { 38 chain *chains.Chain 39 40 // Chain is the chain to sync with 41 Chain string `hcl:"chain,optional"` 42 43 // Name, or identity of the node 44 Name string `hcl:"name,optional"` 45 46 // Whitelist is a list of required (block number, hash) pairs to accept 47 Whitelist map[string]string `hcl:"whitelist,optional"` 48 49 // LogLevel is the level of the logs to put out 50 LogLevel string `hcl:"log-level,optional"` 51 52 // DataDir is the directory to store the state in 53 DataDir string `hcl:"data-dir,optional"` 54 55 // SyncMode selects the sync protocol 56 SyncMode string `hcl:"sync-mode,optional"` 57 58 // GcMode selects the garbage collection mode for the trie 59 GcMode string `hcl:"gc-mode,optional"` 60 61 // XXX 62 Snapshot bool `hcl:"snapshot,optional"` 63 64 // Ethstats is the address of the ethstats server to send telemetry 65 Ethstats string `hcl:"ethstats,optional"` 66 67 // P2P has the p2p network related settings 68 P2P *P2PConfig `hcl:"p2p,block"` 69 70 // Heimdall has the heimdall connection related settings 71 Heimdall *HeimdallConfig `hcl:"heimdall,block"` 72 73 // TxPool has the transaction pool related settings 74 TxPool *TxPoolConfig `hcl:"txpool,block"` 75 76 // Sealer has the validator related settings 77 Sealer *SealerConfig `hcl:"sealer,block"` 78 79 // JsonRPC has the json-rpc related settings 80 JsonRPC *JsonRPCConfig `hcl:"jsonrpc,block"` 81 82 // Gpo has the gas price oracle related settings 83 Gpo *GpoConfig `hcl:"gpo,block"` 84 85 // Telemetry has the telemetry related settings 86 Telemetry *TelemetryConfig `hcl:"telemetry,block"` 87 88 // Cache has the cache related settings 89 Cache *CacheConfig `hcl:"cache,block"` 90 91 // Account has the validator account related settings 92 Accounts *AccountsConfig `hcl:"accounts,block"` 93 94 // GRPC has the grpc server related settings 95 GRPC *GRPCConfig 96 97 // Developer has the developer mode related settings 98 Developer *DeveloperConfig 99 } 100 101 type P2PConfig struct { 102 // MaxPeers sets the maximum number of connected peers 103 MaxPeers uint64 `hcl:"max-peers,optional"` 104 105 // MaxPendPeers sets the maximum number of pending connected peers 106 MaxPendPeers uint64 `hcl:"max-pend-peers,optional"` 107 108 // Bind is the bind address 109 Bind string `hcl:"bind,optional"` 110 111 // Port is the port number 112 Port uint64 `hcl:"port,optional"` 113 114 // NoDiscover is used to disable discovery 115 NoDiscover bool `hcl:"no-discover,optional"` 116 117 // NAT it used to set NAT options 118 NAT string `hcl:"nat,optional"` 119 120 // Discovery has the p2p discovery related settings 121 Discovery *P2PDiscovery `hcl:"discovery,block"` 122 } 123 124 type P2PDiscovery struct { 125 // V5Enabled is used to enable disc v5 discovery mode 126 V5Enabled bool `hcl:"v5-enabled,optional"` 127 128 // Bootnodes is the list of initial bootnodes 129 Bootnodes []string `hcl:"bootnodes,optional"` 130 131 // BootnodesV4 is the list of initial v4 bootnodes 132 BootnodesV4 []string `hcl:"bootnodesv4,optional"` 133 134 // BootnodesV5 is the list of initial v5 bootnodes 135 BootnodesV5 []string `hcl:"bootnodesv5,optional"` 136 137 // StaticNodes is the list of static nodes 138 StaticNodes []string `hcl:"static-nodes,optional"` 139 140 // TrustedNodes is the list of trusted nodes 141 TrustedNodes []string `hcl:"trusted-nodes,optional"` 142 143 // DNS is the list of enrtree:// URLs which will be queried for nodes to connect to 144 DNS []string `hcl:"dns,optional"` 145 } 146 147 type HeimdallConfig struct { 148 // URL is the url of the heimdall server 149 URL string `hcl:"url,optional"` 150 151 // Without is used to disable remote heimdall during testing 152 Without bool `hcl:"without,optional"` 153 } 154 155 type TxPoolConfig struct { 156 // Locals are the addresses that should be treated by default as local 157 Locals []string `hcl:"locals,optional"` 158 159 // NoLocals enables whether local transaction handling should be disabled 160 NoLocals bool `hcl:"no-locals,optional"` 161 162 // Journal is the path to store local transactions to survive node restarts 163 Journal string `hcl:"journal,optional"` 164 165 // Rejournal is the time interval to regenerate the local transaction journal 166 Rejournal time.Duration 167 RejournalRaw string `hcl:"rejournal,optional"` 168 169 // PriceLimit is the minimum gas price to enforce for acceptance into the pool 170 PriceLimit uint64 `hcl:"price-limit,optional"` 171 172 // PriceBump is the minimum price bump percentage to replace an already existing transaction (nonce) 173 PriceBump uint64 `hcl:"price-bump,optional"` 174 175 // AccountSlots is the number of executable transaction slots guaranteed per account 176 AccountSlots uint64 `hcl:"account-slots,optional"` 177 178 // GlobalSlots is the maximum number of executable transaction slots for all accounts 179 GlobalSlots uint64 `hcl:"global-slots,optional"` 180 181 // AccountQueue is the maximum number of non-executable transaction slots permitted per account 182 AccountQueue uint64 `hcl:"account-queue,optional"` 183 184 // GlobalQueueis the maximum number of non-executable transaction slots for all accounts 185 GlobalQueue uint64 `hcl:"global-queue,optional"` 186 187 // Lifetime is the maximum amount of time non-executable transaction are queued 188 LifeTime time.Duration 189 LifeTimeRaw string `hcl:"lifetime,optional"` 190 } 191 192 type SealerConfig struct { 193 // Enabled is used to enable validator mode 194 Enabled bool `hcl:"enabled,optional"` 195 196 // Etherbase is the address of the validator 197 Etherbase string `hcl:"etherbase,optional"` 198 199 // ExtraData is the block extra data set by the miner 200 ExtraData string `hcl:"extra-data,optional"` 201 202 // GasCeil is the target gas ceiling for mined blocks. 203 GasCeil uint64 `hcl:"gas-ceil,optional"` 204 205 // GasPrice is the minimum gas price for mining a transaction 206 GasPrice *big.Int 207 GasPriceRaw string `hcl:"gas-price,optional"` 208 } 209 210 type JsonRPCConfig struct { 211 // IPCDisable enables whether ipc is enabled or not 212 IPCDisable bool `hcl:"ipc-disable,optional"` 213 214 // IPCPath is the path of the ipc endpoint 215 IPCPath string `hcl:"ipc-path,optional"` 216 217 // VHost is the list of valid virtual hosts 218 VHost []string `hcl:"vhost,optional"` 219 220 // Cors is the list of Cors endpoints 221 Cors []string `hcl:"cors,optional"` 222 223 // GasCap is the global gas cap for eth-call variants. 224 GasCap uint64 `hcl:"gas-cap,optional"` 225 226 // TxFeeCap is the global transaction fee cap for send-transaction variants 227 TxFeeCap float64 `hcl:"tx-fee-cap,optional"` 228 229 // Http has the json-rpc http related settings 230 Http *APIConfig `hcl:"http,block"` 231 232 // Http has the json-rpc websocket related settings 233 Ws *APIConfig `hcl:"ws,block"` 234 235 // Http has the json-rpc graphql related settings 236 Graphql *APIConfig `hcl:"graphql,block"` 237 } 238 239 type GRPCConfig struct { 240 // Addr is the bind address for the grpc rpc server 241 Addr string 242 } 243 244 type APIConfig struct { 245 // Enabled selects whether the api is enabled 246 Enabled bool `hcl:"enabled,optional"` 247 248 // Port is the port number for this api 249 Port uint64 `hcl:"port,optional"` 250 251 // Prefix is the http prefix to expose this api 252 Prefix string `hcl:"prefix,optional"` 253 254 // Host is the address to bind the api 255 Host string `hcl:"host,optional"` 256 257 // Modules is the list of enabled api modules 258 Modules []string `hcl:"modules,optional"` 259 } 260 261 type GpoConfig struct { 262 // Blocks is the number of blocks to track to compute the price oracle 263 Blocks uint64 `hcl:"blocks,optional"` 264 265 // Percentile sets the weights to new blocks 266 Percentile uint64 `hcl:"percentile,optional"` 267 268 // MaxPrice is an upper bound gas price 269 MaxPrice *big.Int 270 MaxPriceRaw string `hcl:"max-price,optional"` 271 272 // IgnorePrice is a lower bound gas price 273 IgnorePrice *big.Int 274 IgnorePriceRaw string `hcl:"ignore-price,optional"` 275 } 276 277 type TelemetryConfig struct { 278 // Enabled enables metrics 279 Enabled bool `hcl:"enabled,optional"` 280 281 // Expensive enables expensive metrics 282 Expensive bool `hcl:"expensive,optional"` 283 284 // InfluxDB has the influxdb related settings 285 InfluxDB *InfluxDBConfig `hcl:"influx,block"` 286 287 // Prometheus Address 288 PrometheusAddr string `hcl:"prometheus-addr,optional"` 289 290 // Open collector endpoint 291 OpenCollectorEndpoint string `hcl:"opencollector-endpoint,optional"` 292 } 293 294 type InfluxDBConfig struct { 295 // V1Enabled enables influx v1 mode 296 V1Enabled bool `hcl:"v1-enabled,optional"` 297 298 // Endpoint is the url endpoint of the influxdb service 299 Endpoint string `hcl:"endpoint,optional"` 300 301 // Database is the name of the database in Influxdb to store the metrics. 302 Database string `hcl:"database,optional"` 303 304 // Enabled is the username to authorize access to Influxdb 305 Username string `hcl:"username,optional"` 306 307 // Password is the password to authorize access to Influxdb 308 Password string `hcl:"password,optional"` 309 310 // Tags are tags attaches to all generated metrics 311 Tags map[string]string `hcl:"tags,optional"` 312 313 // Enabled enables influx v2 mode 314 V2Enabled bool `hcl:"v2-enabled,optional"` 315 316 // Token is the token to authorize access to Influxdb V2. 317 Token string `hcl:"token,optional"` 318 319 // Bucket is the bucket to store metrics in Influxdb V2. 320 Bucket string `hcl:"bucket,optional"` 321 322 // Organization is the name of the organization for Influxdb V2. 323 Organization string `hcl:"organization,optional"` 324 } 325 326 type CacheConfig struct { 327 // Cache is the amount of cache of the node 328 Cache uint64 `hcl:"cache,optional"` 329 330 // PercGc is percentage of cache used for garbage collection 331 PercGc uint64 `hcl:"perc-gc,optional"` 332 333 // PercSnapshot is percentage of cache used for snapshots 334 PercSnapshot uint64 `hcl:"perc-snapshot,optional"` 335 336 // PercDatabase is percentage of cache used for the database 337 PercDatabase uint64 `hcl:"perc-database,optional"` 338 339 // PercTrie is percentage of cache used for the trie 340 PercTrie uint64 `hcl:"perc-trie,optional"` 341 342 // Journal is the disk journal directory for trie cache to survive node restarts 343 Journal string `hcl:"journal,optional"` 344 345 // Rejournal is the time interval to regenerate the journal for clean cache 346 Rejournal time.Duration 347 RejournalRaw string `hcl:"rejournal,optional"` 348 349 // NoPrefetch is used to disable prefetch of tries 350 NoPrefetch bool `hcl:"no-prefetch,optional"` 351 352 // Preimages is used to enable the track of hash preimages 353 Preimages bool `hcl:"preimages,optional"` 354 355 // TxLookupLimit sets the maximum number of blocks from head whose tx indices are reserved. 356 TxLookupLimit uint64 `hcl:"tx-lookup-limit,optional"` 357 } 358 359 type AccountsConfig struct { 360 // Unlock is the list of addresses to unlock in the node 361 Unlock []string `hcl:"unlock,optional"` 362 363 // PasswordFile is the file where the account passwords are stored 364 PasswordFile string `hcl:"password-file,optional"` 365 366 // AllowInsecureUnlock allows user to unlock accounts in unsafe http environment. 367 AllowInsecureUnlock bool `hcl:"allow-insecure-unlock,optional"` 368 369 // UseLightweightKDF enables a faster but less secure encryption of accounts 370 UseLightweightKDF bool `hcl:"use-lightweight-kdf,optional"` 371 } 372 373 type DeveloperConfig struct { 374 // Enabled enables the developer mode 375 Enabled bool `hcl:"dev,optional"` 376 377 // Period is the block period to use in developer mode 378 Period uint64 `hcl:"period,optional"` 379 } 380 381 func DefaultConfig() *Config { 382 return &Config{ 383 Chain: "mainnet", 384 Name: Hostname(), 385 Whitelist: map[string]string{}, 386 LogLevel: "INFO", 387 DataDir: defaultDataDir(), 388 P2P: &P2PConfig{ 389 MaxPeers: 30, 390 MaxPendPeers: 50, 391 Bind: "0.0.0.0", 392 Port: 30303, 393 NoDiscover: false, 394 NAT: "any", 395 Discovery: &P2PDiscovery{ 396 V5Enabled: false, 397 Bootnodes: []string{}, 398 BootnodesV4: []string{}, 399 BootnodesV5: []string{}, 400 StaticNodes: []string{}, 401 TrustedNodes: []string{}, 402 DNS: []string{}, 403 }, 404 }, 405 Heimdall: &HeimdallConfig{ 406 URL: "http://localhost:1317", 407 Without: false, 408 }, 409 SyncMode: "full", 410 GcMode: "full", 411 Snapshot: true, 412 TxPool: &TxPoolConfig{ 413 Locals: []string{}, 414 NoLocals: false, 415 Journal: "", 416 Rejournal: time.Duration(1 * time.Hour), 417 PriceLimit: 1, 418 PriceBump: 10, 419 AccountSlots: 16, 420 GlobalSlots: 4096, 421 AccountQueue: 64, 422 GlobalQueue: 1024, 423 LifeTime: time.Duration(3 * time.Hour), 424 }, 425 Sealer: &SealerConfig{ 426 Enabled: false, 427 Etherbase: "", 428 GasCeil: 8000000, 429 GasPrice: big.NewInt(params.GWei), 430 ExtraData: "", 431 }, 432 Gpo: &GpoConfig{ 433 Blocks: 20, 434 Percentile: 60, 435 MaxPrice: gasprice.DefaultMaxPrice, 436 IgnorePrice: gasprice.DefaultIgnorePrice, 437 }, 438 JsonRPC: &JsonRPCConfig{ 439 IPCDisable: false, 440 IPCPath: "", 441 Cors: []string{"*"}, 442 VHost: []string{"*"}, 443 GasCap: ethconfig.Defaults.RPCGasCap, 444 TxFeeCap: ethconfig.Defaults.RPCTxFeeCap, 445 Http: &APIConfig{ 446 Enabled: false, 447 Port: 8545, 448 Prefix: "", 449 Host: "localhost", 450 Modules: []string{"web3", "net"}, 451 }, 452 Ws: &APIConfig{ 453 Enabled: false, 454 Port: 8546, 455 Prefix: "", 456 Host: "localhost", 457 Modules: []string{"web3", "net"}, 458 }, 459 Graphql: &APIConfig{ 460 Enabled: false, 461 }, 462 }, 463 Ethstats: "", 464 Telemetry: &TelemetryConfig{ 465 Enabled: false, 466 Expensive: false, 467 PrometheusAddr: "", 468 OpenCollectorEndpoint: "", 469 InfluxDB: &InfluxDBConfig{ 470 V1Enabled: false, 471 Endpoint: "", 472 Database: "", 473 Username: "", 474 Password: "", 475 Tags: map[string]string{}, 476 V2Enabled: false, 477 Token: "", 478 Bucket: "", 479 Organization: "", 480 }, 481 }, 482 Cache: &CacheConfig{ 483 Cache: 1024, 484 PercDatabase: 50, 485 PercTrie: 15, 486 PercGc: 25, 487 PercSnapshot: 10, 488 Journal: "triecache", 489 Rejournal: 60 * time.Minute, 490 NoPrefetch: false, 491 Preimages: false, 492 TxLookupLimit: 2350000, 493 }, 494 Accounts: &AccountsConfig{ 495 Unlock: []string{}, 496 PasswordFile: "", 497 AllowInsecureUnlock: false, 498 UseLightweightKDF: false, 499 }, 500 GRPC: &GRPCConfig{ 501 Addr: ":3131", 502 }, 503 Developer: &DeveloperConfig{ 504 Enabled: false, 505 Period: 0, 506 }, 507 } 508 } 509 510 func (c *Config) fillBigInt() error { 511 tds := []struct { 512 path string 513 td **big.Int 514 str *string 515 }{ 516 {"gpo.maxprice", &c.Gpo.MaxPrice, &c.Gpo.MaxPriceRaw}, 517 {"gpo.ignoreprice", &c.Gpo.IgnorePrice, &c.Gpo.IgnorePriceRaw}, 518 {"sealer.gasprice", &c.Sealer.GasPrice, &c.Sealer.GasPriceRaw}, 519 } 520 521 for _, x := range tds { 522 if *x.str != "" { 523 b := new(big.Int) 524 525 var ok bool 526 if strings.HasPrefix(*x.str, "0x") { 527 b, ok = b.SetString((*x.str)[2:], 16) 528 } else { 529 b, ok = b.SetString(*x.str, 10) 530 } 531 if !ok { 532 return fmt.Errorf("%s can't parse big int %s", x.path, *x.str) 533 } 534 *x.str = "" 535 *x.td = b 536 } 537 } 538 return nil 539 } 540 541 func (c *Config) fillTimeDurations() error { 542 tds := []struct { 543 path string 544 td *time.Duration 545 str *string 546 }{ 547 {"txpool.lifetime", &c.TxPool.LifeTime, &c.TxPool.LifeTimeRaw}, 548 {"txpool.rejournal", &c.TxPool.Rejournal, &c.TxPool.RejournalRaw}, 549 {"cache.rejournal", &c.Cache.Rejournal, &c.Cache.RejournalRaw}, 550 } 551 552 for _, x := range tds { 553 if x.td != nil && x.str != nil && *x.str != "" { 554 d, err := time.ParseDuration(*x.str) 555 if err != nil { 556 return fmt.Errorf("%s can't parse time duration %s", x.path, *x.str) 557 } 558 *x.str = "" 559 *x.td = d 560 } 561 } 562 return nil 563 } 564 565 func readConfigFile(path string) (*Config, error) { 566 ext := filepath.Ext(path) 567 if ext == ".toml" { 568 // read file and apply the legacy config 569 data, err := ioutil.ReadFile(path) 570 if err != nil { 571 return nil, err 572 } 573 return readLegacyConfig(data) 574 } 575 576 config := &Config{ 577 TxPool: &TxPoolConfig{}, 578 Cache: &CacheConfig{}, 579 Sealer: &SealerConfig{}, 580 } 581 if err := hclsimple.DecodeFile(path, nil, config); err != nil { 582 return nil, fmt.Errorf("failed to decode config file '%s': %v", path, err) 583 } 584 if err := config.fillBigInt(); err != nil { 585 return nil, err 586 } 587 if err := config.fillTimeDurations(); err != nil { 588 return nil, err 589 } 590 return config, nil 591 } 592 593 func (c *Config) loadChain() error { 594 if c.Developer.Enabled { 595 return nil 596 } 597 chain, ok := chains.GetChain(c.Chain) 598 if !ok { 599 return fmt.Errorf("chain '%s' not found", c.Chain) 600 } 601 c.chain = chain 602 603 // preload some default values that depend on the chain file 604 if c.P2P.Discovery.DNS == nil { 605 c.P2P.Discovery.DNS = c.chain.DNS 606 } 607 608 // depending on the chain we have different cache values 609 if c.Chain == "mainnet" { 610 c.Cache.Cache = 4096 611 } else { 612 c.Cache.Cache = 1024 613 } 614 return nil 615 } 616 617 func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { 618 dbHandles, err := makeDatabaseHandles() 619 if err != nil { 620 return nil, err 621 } 622 n := ethconfig.Defaults 623 624 // only update for non-developer mode as we don't yet 625 // have the chain object for it. 626 if !c.Developer.Enabled { 627 n.NetworkId = c.chain.NetworkId 628 n.Genesis = c.chain.Genesis 629 } 630 n.HeimdallURL = c.Heimdall.URL 631 n.WithoutHeimdall = c.Heimdall.Without 632 633 // gas price oracle 634 { 635 n.GPO.Blocks = int(c.Gpo.Blocks) 636 n.GPO.Percentile = int(c.Gpo.Percentile) 637 n.GPO.MaxPrice = c.Gpo.MaxPrice 638 n.GPO.IgnorePrice = c.Gpo.IgnorePrice 639 } 640 641 // txpool options 642 { 643 n.TxPool.NoLocals = c.TxPool.NoLocals 644 n.TxPool.Journal = c.TxPool.Journal 645 n.TxPool.Rejournal = c.TxPool.Rejournal 646 n.TxPool.PriceLimit = c.TxPool.PriceLimit 647 n.TxPool.PriceBump = c.TxPool.PriceBump 648 n.TxPool.AccountSlots = c.TxPool.AccountSlots 649 n.TxPool.GlobalSlots = c.TxPool.GlobalSlots 650 n.TxPool.AccountQueue = c.TxPool.AccountQueue 651 n.TxPool.GlobalQueue = c.TxPool.GlobalQueue 652 n.TxPool.Lifetime = c.TxPool.LifeTime 653 } 654 655 // miner options 656 { 657 n.Miner.GasPrice = c.Sealer.GasPrice 658 n.Miner.GasCeil = c.Sealer.GasCeil 659 n.Miner.ExtraData = []byte(c.Sealer.ExtraData) 660 661 if etherbase := c.Sealer.Etherbase; etherbase != "" { 662 if !common.IsHexAddress(etherbase) { 663 return nil, fmt.Errorf("etherbase is not an address: %s", etherbase) 664 } 665 n.Miner.Etherbase = common.HexToAddress(etherbase) 666 } 667 } 668 669 // update for developer mode 670 if c.Developer.Enabled { 671 // Get a keystore 672 var ks *keystore.KeyStore 673 if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { 674 ks = keystores[0].(*keystore.KeyStore) 675 } 676 677 // Create new developer account or reuse existing one 678 var ( 679 developer accounts.Account 680 passphrase string 681 err error 682 ) 683 // etherbase has been set above, configuring the miner address from command line flags. 684 if n.Miner.Etherbase != (common.Address{}) { 685 developer = accounts.Account{Address: n.Miner.Etherbase} 686 } else if accs := ks.Accounts(); len(accs) > 0 { 687 developer = ks.Accounts()[0] 688 } else { 689 developer, err = ks.NewAccount(passphrase) 690 if err != nil { 691 return nil, fmt.Errorf("failed to create developer account: %v", err) 692 } 693 } 694 if err := ks.Unlock(developer, passphrase); err != nil { 695 return nil, fmt.Errorf("failed to unlock developer account: %v", err) 696 } 697 log.Info("Using developer account", "address", developer.Address) 698 699 // get developer mode chain config 700 c.chain = chains.GetDeveloperChain(c.Developer.Period, developer.Address) 701 702 // update the parameters 703 n.NetworkId = c.chain.NetworkId 704 n.Genesis = c.chain.Genesis 705 706 // Update cache 707 c.Cache.Cache = 1024 708 709 // Update sync mode 710 c.SyncMode = "full" 711 712 // update miner gas price 713 if n.Miner.GasPrice == nil { 714 n.Miner.GasPrice = big.NewInt(1) 715 } 716 } 717 718 // discovery (this params should be in node.Config) 719 { 720 n.EthDiscoveryURLs = c.P2P.Discovery.DNS 721 n.SnapDiscoveryURLs = c.P2P.Discovery.DNS 722 } 723 724 // whitelist 725 { 726 n.Whitelist = map[uint64]common.Hash{} 727 for k, v := range c.Whitelist { 728 number, err := strconv.ParseUint(k, 0, 64) 729 if err != nil { 730 return nil, fmt.Errorf("invalid whitelist block number %s: %v", k, err) 731 } 732 var hash common.Hash 733 if err = hash.UnmarshalText([]byte(v)); err != nil { 734 return nil, fmt.Errorf("invalid whitelist hash %s: %v", v, err) 735 } 736 n.Whitelist[number] = hash 737 } 738 } 739 740 // cache 741 { 742 cache := c.Cache.Cache 743 calcPerc := func(val uint64) int { 744 return int(cache * (val) / 100) 745 } 746 747 // Cap the cache allowance 748 mem, err := gopsutil.VirtualMemory() 749 if err == nil { 750 if 32<<(^uintptr(0)>>63) == 32 && mem.Total > 2*1024*1024*1024 { 751 log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024) 752 mem.Total = 2 * 1024 * 1024 * 1024 753 } 754 allowance := uint64(mem.Total / 1024 / 1024 / 3) 755 if cache > allowance { 756 log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) 757 cache = allowance 758 } 759 } 760 // Tune the garbage collector 761 gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) 762 763 log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) 764 godebug.SetGCPercent(int(gogc)) 765 766 n.TrieCleanCacheJournal = c.Cache.Journal 767 n.TrieCleanCacheRejournal = c.Cache.Rejournal 768 n.DatabaseCache = calcPerc(c.Cache.PercDatabase) 769 n.SnapshotCache = calcPerc(c.Cache.PercSnapshot) 770 n.TrieCleanCache = calcPerc(c.Cache.PercTrie) 771 n.TrieDirtyCache = calcPerc(c.Cache.PercGc) 772 n.NoPrefetch = c.Cache.NoPrefetch 773 n.Preimages = c.Cache.Preimages 774 n.TxLookupLimit = c.Cache.TxLookupLimit 775 } 776 777 n.RPCGasCap = c.JsonRPC.GasCap 778 if n.RPCGasCap != 0 { 779 log.Info("Set global gas cap", "cap", n.RPCGasCap) 780 } else { 781 log.Info("Global gas cap disabled") 782 } 783 n.RPCTxFeeCap = c.JsonRPC.TxFeeCap 784 785 // sync mode. It can either be "fast", "full" or "snap". We disable 786 // for now the "light" mode. 787 switch c.SyncMode { 788 case "fast": 789 n.SyncMode = downloader.FastSync 790 case "full": 791 n.SyncMode = downloader.FullSync 792 case "snap": 793 n.SyncMode = downloader.SnapSync 794 default: 795 return nil, fmt.Errorf("sync mode '%s' not found", c.SyncMode) 796 } 797 798 // archive mode. It can either be "archive" or "full". 799 switch c.GcMode { 800 case "full": 801 n.NoPruning = false 802 case "archive": 803 n.NoPruning = true 804 if !n.Preimages { 805 n.Preimages = true 806 log.Info("Enabling recording of key preimages since archive mode is used") 807 } 808 default: 809 return nil, fmt.Errorf("gcmode '%s' not found", c.GcMode) 810 } 811 812 // snapshot disable check 813 if c.Snapshot { 814 if n.SyncMode == downloader.SnapSync { 815 log.Info("Snap sync requested, enabling --snapshot") 816 } else { 817 // disable snapshot 818 n.TrieCleanCache += n.SnapshotCache 819 n.SnapshotCache = 0 820 } 821 } 822 823 n.DatabaseHandles = dbHandles 824 return &n, nil 825 } 826 827 var ( 828 clientIdentifier = "bor" 829 gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) 830 gitDate = "" // Git commit date YYYYMMDD of the release (set via linker flags) 831 ) 832 833 func (c *Config) buildNode() (*node.Config, error) { 834 ipcPath := "" 835 if !c.JsonRPC.IPCDisable { 836 ipcPath = clientIdentifier + ".ipc" 837 if c.JsonRPC.IPCPath != "" { 838 ipcPath = c.JsonRPC.IPCPath 839 } 840 } 841 842 cfg := &node.Config{ 843 Name: clientIdentifier, 844 DataDir: c.DataDir, 845 UseLightweightKDF: c.Accounts.UseLightweightKDF, 846 InsecureUnlockAllowed: c.Accounts.AllowInsecureUnlock, 847 Version: params.VersionWithCommit(gitCommit, gitDate), 848 IPCPath: ipcPath, 849 P2P: p2p.Config{ 850 MaxPeers: int(c.P2P.MaxPeers), 851 MaxPendingPeers: int(c.P2P.MaxPendPeers), 852 ListenAddr: c.P2P.Bind + ":" + strconv.Itoa(int(c.P2P.Port)), 853 DiscoveryV5: c.P2P.Discovery.V5Enabled, 854 }, 855 HTTPModules: c.JsonRPC.Http.Modules, 856 HTTPCors: c.JsonRPC.Cors, 857 HTTPVirtualHosts: c.JsonRPC.VHost, 858 HTTPPathPrefix: c.JsonRPC.Http.Prefix, 859 WSModules: c.JsonRPC.Ws.Modules, 860 WSOrigins: c.JsonRPC.Cors, 861 WSPathPrefix: c.JsonRPC.Ws.Prefix, 862 GraphQLCors: c.JsonRPC.Cors, 863 GraphQLVirtualHosts: c.JsonRPC.VHost, 864 } 865 866 // dev mode 867 if c.Developer.Enabled { 868 cfg.UseLightweightKDF = true 869 870 // disable p2p networking 871 c.P2P.NoDiscover = true 872 cfg.P2P.ListenAddr = "" 873 cfg.P2P.NoDial = true 874 cfg.P2P.DiscoveryV5 = false 875 } 876 877 // enable jsonrpc endpoints 878 { 879 if c.JsonRPC.Http.Enabled { 880 cfg.HTTPHost = c.JsonRPC.Http.Host 881 cfg.HTTPPort = int(c.JsonRPC.Http.Port) 882 } 883 if c.JsonRPC.Ws.Enabled { 884 cfg.WSHost = c.JsonRPC.Ws.Host 885 cfg.WSPort = int(c.JsonRPC.Ws.Port) 886 } 887 } 888 889 natif, err := nat.Parse(c.P2P.NAT) 890 if err != nil { 891 return nil, fmt.Errorf("wrong 'nat' flag: %v", err) 892 } 893 cfg.P2P.NAT = natif 894 895 // only check for non-developer modes 896 if !c.Developer.Enabled { 897 // Discovery 898 // if no bootnodes are defined, use the ones from the chain file. 899 bootnodes := c.P2P.Discovery.Bootnodes 900 if len(bootnodes) == 0 { 901 bootnodes = c.chain.Bootnodes 902 } 903 if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil { 904 return nil, err 905 } 906 if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil { 907 return nil, err 908 } 909 if cfg.P2P.StaticNodes, err = parseBootnodes(c.P2P.Discovery.StaticNodes); err != nil { 910 return nil, err 911 } 912 if cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil { 913 return nil, err 914 } 915 } 916 917 if c.P2P.NoDiscover { 918 // Disable networking, for now, we will not even allow incomming connections 919 cfg.P2P.MaxPeers = 0 920 cfg.P2P.NoDiscovery = true 921 } 922 return cfg, nil 923 } 924 925 func (c *Config) Merge(cc ...*Config) error { 926 for _, elem := range cc { 927 if err := mergo.Merge(c, elem, mergo.WithOverride, mergo.WithAppendSlice); err != nil { 928 return fmt.Errorf("failed to merge configurations: %v", err) 929 } 930 } 931 return nil 932 } 933 934 func makeDatabaseHandles() (int, error) { 935 limit, err := fdlimit.Maximum() 936 if err != nil { 937 return -1, err 938 } 939 raised, err := fdlimit.Raise(uint64(limit)) 940 if err != nil { 941 return -1, err 942 } 943 return int(raised / 2), nil 944 } 945 946 func parseBootnodes(urls []string) ([]*enode.Node, error) { 947 dst := []*enode.Node{} 948 for _, url := range urls { 949 if url != "" { 950 node, err := enode.Parse(enode.ValidSchemes, url) 951 if err != nil { 952 return nil, fmt.Errorf("invalid bootstrap url '%s': %v", url, err) 953 } 954 dst = append(dst, node) 955 } 956 } 957 return dst, nil 958 } 959 960 func defaultDataDir() string { 961 // Try to place the data folder in the user's home dir 962 home, _ := homedir.Dir() 963 if home == "" { 964 // we cannot guess a stable location 965 return "" 966 } 967 switch runtime.GOOS { 968 case "darwin": 969 return filepath.Join(home, "Library", "Bor") 970 case "windows": 971 appdata := os.Getenv("LOCALAPPDATA") 972 if appdata == "" { 973 // Windows XP and below don't have LocalAppData. 974 panic("environment variable LocalAppData is undefined") 975 } 976 return filepath.Join(appdata, "Bor") 977 default: 978 return filepath.Join(home, ".bor") 979 } 980 } 981 982 func Hostname() string { 983 hostname, err := os.Hostname() 984 if err != nil { 985 return "bor" 986 } 987 return hostname 988 }