github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/config.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "encoding/csv" 21 hexlib "encoding/hex" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "io/ioutil" 26 "math/big" 27 "os" 28 "sort" 29 "sync" 30 31 "path/filepath" 32 "reflect" 33 34 "io" 35 "strings" 36 37 "github.com/ethereumproject/go-ethereum/common" 38 "github.com/ethereumproject/go-ethereum/core/state" 39 "github.com/ethereumproject/go-ethereum/core/types" 40 "github.com/ethereumproject/go-ethereum/core/vm" 41 "github.com/ethereumproject/go-ethereum/ethdb" 42 "github.com/ethereumproject/go-ethereum/logger" 43 "github.com/ethereumproject/go-ethereum/logger/glog" 44 "github.com/ethereumproject/go-ethereum/p2p/discover" 45 ) 46 47 var ( 48 ErrChainConfigNotFound = errors.New("chain config not found") 49 ErrChainConfigForkNotFound = errors.New("chain config fork not found") 50 51 ErrInvalidChainID = errors.New("invalid chainID") 52 53 ErrHashKnownBad = errors.New("known bad hash") 54 ErrHashKnownFork = validateError("known fork hash mismatch") 55 56 // Chain identities. 57 ChainIdentitiesBlacklist = map[string]bool{ 58 "chaindata": true, 59 "dapp": true, 60 "keystore": true, 61 "nodekey": true, 62 "nodes": true, 63 } 64 ChainIdentitiesMain = map[string]bool{ 65 "main": true, 66 "mainnet": true, 67 } 68 ChainIdentitiesMorden = map[string]bool{ 69 "morden": true, 70 "testnet": true, 71 } 72 73 cacheChainIdentity string 74 cacheChainConfig *SufficientChainConfig 75 ) 76 77 func SetCacheChainIdentity(s string) { 78 cacheChainIdentity = s 79 } 80 81 func GetCacheChainIdentity() string { 82 return cacheChainIdentity 83 } 84 85 func SetCacheChainConfig(c *SufficientChainConfig) *SufficientChainConfig { 86 cacheChainConfig = c 87 return cacheChainConfig 88 } 89 90 func GetCacheChainConfig() *SufficientChainConfig { 91 return cacheChainConfig 92 } 93 94 // SufficientChainConfig holds necessary data for externalizing a given blockchain configuration. 95 type SufficientChainConfig struct { 96 ID string `json:"id,omitempty"` // deprecated in favor of 'Identity', method decoding should id -> identity 97 Identity string `json:"identity"` 98 Name string `json:"name,omitempty"` 99 State *StateConfig `json:"state"` // don't omitempty for clarity of potential custom options 100 Network int `json:"network"` // eth.NetworkId (mainnet=1, morden=2) 101 Consensus string `json:"consensus"` // pow type (ethash OR ethash-test) 102 Genesis *GenesisDump `json:"genesis"` 103 ChainConfig *ChainConfig `json:"chainConfig"` 104 Bootstrap []string `json:"bootstrap"` 105 ParsedBootstrap []*discover.Node `json:"-"` 106 Include []string `json:"include"` // config files to include 107 } 108 109 // StateConfig hold variable data for statedb. 110 type StateConfig struct { 111 StartingNonce uint64 `json:"startingNonce,omitempty"` 112 } 113 114 // GenesisDump is the geth JSON format. 115 // https://github.com/ethereumproject/wiki/wiki/Ethereum-Chain-Spec-Format#subformat-genesis 116 type GenesisDump struct { 117 Nonce prefixedHex `json:"nonce"` 118 Timestamp prefixedHex `json:"timestamp"` 119 ParentHash prefixedHex `json:"parentHash"` 120 ExtraData prefixedHex `json:"extraData"` 121 GasLimit prefixedHex `json:"gasLimit"` 122 Difficulty prefixedHex `json:"difficulty"` 123 Mixhash prefixedHex `json:"mixhash"` 124 Coinbase prefixedHex `json:"coinbase"` 125 126 // Alloc maps accounts by their address. 127 Alloc map[hex]*GenesisDumpAlloc `json:"alloc"` 128 // Alloc file contains CSV representation of Alloc 129 AllocFile string `json:"alloc_file"` 130 } 131 132 // GenesisDumpAlloc is a GenesisDump.Alloc entry. 133 type GenesisDumpAlloc struct { 134 Code prefixedHex `json:"-"` // skip field for json encode 135 Storage map[hex]hex `json:"-"` 136 Balance string `json:"balance"` // decimal string 137 } 138 139 type GenesisAccount struct { 140 Address common.Address `json:"address"` 141 Balance *big.Int `json:"balance"` 142 } 143 144 // ChainConfig is stored in the database on a per block basis. This means 145 // that any network, identified by its genesis block, can have its own 146 // set of configuration options. 147 type ChainConfig struct { 148 // Forks holds fork block requirements. See ErrHashKnownFork. 149 Forks Forks `json:"forks"` 150 151 // BadHashes holds well known blocks with consensus issues. See ErrHashKnownBad. 152 BadHashes []*BadHash `json:"badHashes"` 153 } 154 155 type Fork struct { 156 Name string `json:"name"` 157 // Block is the block number where the hard-fork commences on 158 // the Ethereum network. 159 Block *big.Int `json:"block"` 160 // Used to improve sync for a known network split 161 RequiredHash common.Hash `json:"requiredHash"` 162 // Configurable features. 163 Features []*ForkFeature `json:"features"` 164 } 165 166 // Forks implements sort interface, sorting by block number 167 type Forks []*Fork 168 169 func (fs Forks) Len() int { return len(fs) } 170 func (fs Forks) Less(i, j int) bool { 171 iF := fs[i] 172 jF := fs[j] 173 return iF.Block.Cmp(jF.Block) < 0 174 } 175 func (fs Forks) Swap(i, j int) { 176 fs[i], fs[j] = fs[j], fs[i] 177 } 178 179 // ForkFeatures are designed to decouple the implementation feature upgrades from Forks themselves. 180 // For example, there are several 'set-gasprice' features, each using a different gastable, 181 // as well as protocol upgrades including 'eip155', 'ecip1010', ... etc. 182 type ForkFeature struct { 183 ID string `json:"id"` 184 Options ChainFeatureConfigOptions `json:"options"` // no * because they have to be iterable(?) 185 optionsLock sync.RWMutex 186 ParsedOptions map[string]interface{} `json:"-"` // don't include in JSON dumps, since its for holding parsed JSON in mem 187 parsedOptionsLock sync.RWMutex 188 // TODO Derive Oracle contracts from fork struct (Version, Registrar, Release) 189 } 190 191 // These are the raw key-value configuration options made available 192 // by an external JSON file. 193 type ChainFeatureConfigOptions map[string]interface{} 194 195 type BadHash struct { 196 Block *big.Int 197 Hash common.Hash 198 } 199 200 func (c *SufficientChainConfig) IsValid() (string, bool) { 201 // entirely empty 202 if reflect.DeepEqual(c, SufficientChainConfig{}) { 203 return "all empty", false 204 } 205 206 if c.Identity == "" { 207 return "identity/id", false 208 } 209 210 if c.Network == 0 { 211 return "networkId", false 212 } 213 214 if c := c.Consensus; c == "" || (c != "ethash" && c != "ethash-test") { 215 return "consensus", false 216 } 217 218 if c.Genesis == nil { 219 return "genesis", false 220 } 221 if len(c.Genesis.Nonce) == 0 { 222 return "genesis.nonce", false 223 } 224 if len(c.Genesis.GasLimit) == 0 { 225 return "genesis.gasLimit", false 226 } 227 if len(c.Genesis.Difficulty) == 0 { 228 return "genesis.difficulty", false 229 } 230 if _, e := c.Genesis.Header(); e != nil { 231 return "genesis.header(): " + e.Error(), false 232 } 233 234 if c.ChainConfig == nil { 235 return "chainConfig", false 236 } 237 238 if len(c.ChainConfig.Forks) == 0 { 239 return "forks", false 240 } 241 242 return "", true 243 } 244 245 // Header returns the mapping. 246 func (g *GenesisDump) Header() (*types.Header, error) { 247 var h types.Header 248 249 var err error 250 if err = g.Nonce.Decode(h.Nonce[:]); err != nil { 251 return nil, fmt.Errorf("malformed nonce: %s", err) 252 } 253 if h.Time, err = g.Timestamp.Int(); err != nil { 254 return nil, fmt.Errorf("malformed timestamp: %s", err) 255 } 256 if err = g.ParentHash.Decode(h.ParentHash[:]); err != nil { 257 return nil, fmt.Errorf("malformed parentHash: %s", err) 258 } 259 if h.Extra, err = g.ExtraData.Bytes(); err != nil { 260 return nil, fmt.Errorf("malformed extraData: %s", err) 261 } 262 if h.GasLimit, err = g.GasLimit.Int(); err != nil { 263 return nil, fmt.Errorf("malformed gasLimit: %s", err) 264 } 265 if h.Difficulty, err = g.Difficulty.Int(); err != nil { 266 return nil, fmt.Errorf("malformed difficulty: %s", err) 267 } 268 if err = g.Mixhash.Decode(h.MixDigest[:]); err != nil { 269 return nil, fmt.Errorf("malformed mixhash: %s", err) 270 } 271 if err := g.Coinbase.Decode(h.Coinbase[:]); err != nil { 272 return nil, fmt.Errorf("malformed coinbase: %s", err) 273 } 274 275 return &h, nil 276 } 277 278 // SortForks sorts a ChainConfiguration's forks by block number smallest to bigget (chronologically). 279 // This should need be called only once after construction 280 func (c *ChainConfig) SortForks() *ChainConfig { 281 sort.Sort(c.Forks) 282 return c 283 } 284 285 // GetChainID gets the chainID for a chainconfig. 286 // It returns big.Int zero-value if no chainID is ever set for eip155/chainID. 287 // It uses ChainConfig#HasFeature, so it will return the last chronological value 288 // if the value is set multiple times. 289 func (c *ChainConfig) GetChainID() *big.Int { 290 n := new(big.Int) 291 feat, _, ok := c.HasFeature("eip155") 292 if !ok { 293 return n 294 } 295 if val, ok := feat.GetBigInt("chainID"); ok { 296 n.Set(val) 297 } 298 return n 299 } 300 301 // IsHomestead returns whether num is either equal to the homestead block or greater. 302 func (c *ChainConfig) IsHomestead(num *big.Int) bool { 303 if c.ForkByName("Homestead").Block == nil || num == nil { 304 return false 305 } 306 return num.Cmp(c.ForkByName("Homestead").Block) >= 0 307 } 308 309 // IsDiehard returns whether num is greater than or equal to the Diehard block, but less than explosion. 310 func (c *ChainConfig) IsDiehard(num *big.Int) bool { 311 fork := c.ForkByName("Diehard") 312 if fork.Block == nil || num == nil { 313 return false 314 } 315 return num.Cmp(fork.Block) >= 0 316 } 317 318 // IsExplosion returns whether num is either equal to the explosion block or greater. 319 func (c *ChainConfig) IsExplosion(num *big.Int) bool { 320 feat, fork, configured := c.GetFeature(num, "difficulty") 321 322 if configured { 323 //name, exists := feat.GetString("type") 324 if name, exists := feat.GetString("type"); exists && name == "ecip1010" { 325 block := big.NewInt(0) 326 if length, ok := feat.GetBigInt("length"); ok { 327 block = block.Add(fork.Block, length) 328 } else { 329 panic("Fork feature ecip1010 requires length value.") 330 } 331 return num.Cmp(block) >= 0 332 } 333 } 334 return false 335 } 336 337 // ForkByName looks up a Fork by its name, assumed to be unique 338 func (c *ChainConfig) ForkByName(name string) *Fork { 339 for i := range c.Forks { 340 if c.Forks[i].Name == name { 341 return c.Forks[i] 342 } 343 } 344 return &Fork{} 345 } 346 347 // GetFeature looks up fork features by id, where id can (currently) be [difficulty, gastable, eip155]. 348 // GetFeature returns the feature|nil, the latest fork configuring a given id, and if the given feature id was found at all 349 // If queried feature is not found, returns ForkFeature{}, Fork{}, false. 350 // If queried block number and/or feature is a zero-value, returns ForkFeature{}, Fork{}, false. 351 func (c *ChainConfig) GetFeature(num *big.Int, id string) (*ForkFeature, *Fork, bool) { 352 var okForkFeature = &ForkFeature{} 353 var okFork = &Fork{} 354 var found = false 355 if num != nil && id != "" { 356 for _, f := range c.Forks { 357 if f.Block == nil { 358 continue 359 } 360 if f.Block.Cmp(num) > 0 { 361 continue 362 } 363 for _, ff := range f.Features { 364 if ff.ID == id { 365 okForkFeature = ff 366 okFork = f 367 found = true 368 } 369 } 370 } 371 } 372 return okForkFeature, okFork, found 373 } 374 375 // HasFeature looks up if fork feature exists on any fork at any block in the configuration. 376 // In case of multiple same-'id'd features, returns latest (assuming forks are sorted). 377 func (c *ChainConfig) HasFeature(id string) (*ForkFeature, *Fork, bool) { 378 var okForkFeature = &ForkFeature{} 379 var okFork = &Fork{} 380 var found = false 381 if id != "" { 382 for _, f := range c.Forks { 383 for _, ff := range f.Features { 384 if ff.ID == id { 385 okForkFeature = ff 386 okFork = f 387 found = true 388 } 389 } 390 } 391 } 392 return okForkFeature, okFork, found 393 } 394 395 func (c *ChainConfig) HeaderCheck(h *types.Header) error { 396 for _, fork := range c.Forks { 397 if fork.Block.Cmp(h.Number) != 0 { 398 continue 399 } 400 if !fork.RequiredHash.IsEmpty() && fork.RequiredHash != h.Hash() { 401 return ErrHashKnownFork 402 } 403 } 404 405 for _, bad := range c.BadHashes { 406 if bad.Block.Cmp(h.Number) != 0 { 407 continue 408 } 409 if bad.Hash == h.Hash() { 410 return ErrHashKnownBad 411 } 412 } 413 414 return nil 415 } 416 417 // GetLatestRequiredHash returns the latest requiredHash from chain config for a given blocknumber n (eg. bc head). 418 // It does NOT depend on forks being sorted. 419 func (c *ChainConfig) GetLatestRequiredHashFork(n *big.Int) (f *Fork) { 420 lastBlockN := new(big.Int) 421 for _, ff := range c.Forks { 422 if ff.RequiredHash.IsEmpty() { 423 continue 424 } 425 // If this fork is chronologically later than lastSet fork with required hash AND given block n is greater than 426 // the fork. 427 if ff.Block.Cmp(lastBlockN) > 0 && n.Cmp(ff.Block) >= 0 { 428 f = ff 429 lastBlockN = ff.Block 430 } 431 } 432 return 433 } 434 435 func (c *ChainConfig) GetSigner(blockNumber *big.Int) types.Signer { 436 feature, _, configured := c.GetFeature(blockNumber, "eip155") 437 if configured { 438 if chainId, ok := feature.GetBigInt("chainID"); ok { 439 return types.NewChainIdSigner(chainId) 440 } else { 441 panic(fmt.Errorf("chainID is not set for EIP-155 at %v", blockNumber)) 442 } 443 } 444 return types.BasicSigner{} 445 } 446 447 // GasTable returns the gas table corresponding to the current fork 448 // The returned GasTable's fields shouldn't, under any circumstances, be changed. 449 func (c *ChainConfig) GasTable(num *big.Int) *vm.GasTable { 450 f, _, configured := c.GetFeature(num, "gastable") 451 if !configured { 452 return DefaultHomeSteadGasTable 453 } 454 name, ok := f.GetString("type") 455 if !ok { 456 name = "" 457 } // will wall to default panic 458 switch name { 459 case "homestead": 460 return DefaultHomeSteadGasTable 461 case "eip150": 462 return DefaultGasRepriceGasTable 463 case "eip160": 464 return DefaultDiehardGasTable 465 default: 466 panic(fmt.Errorf("Unsupported gastable value '%v' at block: %v", name, num)) 467 } 468 } 469 470 // WriteToJSONFile writes a given config to a specified file path. 471 // It doesn't run any checks on the file path so make sure that's already squeaky clean. 472 func (c *SufficientChainConfig) WriteToJSONFile(path string) error { 473 jsonConfig, err := json.MarshalIndent(c, "", " ") 474 if err != nil { 475 return fmt.Errorf("Could not marshal json from chain config: %v", err) 476 } 477 478 if err := ioutil.WriteFile(path, jsonConfig, 0644); err != nil { 479 return fmt.Errorf("Could not write external chain config file: %v", err) 480 } 481 return nil 482 } 483 484 // resolvePath builds a path based on adjacentPath's directory. 485 // It assumes that adjacentPath is the path of a file or immediate parent directory, and that 486 // 'path' is either an absolute path or a path relative to the adjacentPath. 487 func resolvePath(path, parentOrAdjacentPath string) string { 488 if !filepath.IsAbs(path) { 489 baseDir := filepath.Dir(parentOrAdjacentPath) 490 path = filepath.Join(baseDir, path) 491 } 492 return path 493 } 494 495 func parseAllocationFile(config *SufficientChainConfig, open func(string) (io.ReadCloser, error), currentFile string) error { 496 if config.Genesis == nil || config.Genesis.AllocFile == "" { 497 return nil 498 } 499 500 if len(config.Genesis.Alloc) > 0 { 501 return fmt.Errorf("error processing %s: \"alloc\" values already set, but \"alloc_file\" is provided", currentFile) 502 } 503 path := resolvePath(config.Genesis.AllocFile, currentFile) 504 csvFile, err := open(path) 505 if err != nil { 506 return fmt.Errorf("failed to read allocation file: %v", err) 507 } 508 defer csvFile.Close() 509 510 config.Genesis.Alloc = make(map[hex]*GenesisDumpAlloc) 511 512 reader := csv.NewReader(csvFile) 513 line := 1 514 for { 515 row, err := reader.Read() 516 if err == io.EOF { 517 break 518 } else if err != nil { 519 return fmt.Errorf("error while reading allocation file: %v", err) 520 } 521 if len(row) != 2 { 522 return fmt.Errorf("invalid number of values in line %d: expected 2, got %d", line, len(row)) 523 } 524 line++ 525 526 config.Genesis.Alloc[hex(row[0])] = &GenesisDumpAlloc{Balance: row[1]} 527 } 528 529 config.Genesis.AllocFile = "" 530 return nil 531 } 532 533 func parseExternalChainConfig(mainConfigFile string, open func(string) (io.ReadCloser, error)) (*SufficientChainConfig, error) { 534 var config = &SufficientChainConfig{} 535 var processed []string 536 537 contains := func(hayStack []string, needle string) bool { 538 for _, v := range hayStack { 539 if needle == v { 540 return true 541 } 542 } 543 return false 544 } 545 546 var processFile func(path, parent string) error 547 processFile = func(path, parent string) (err error) { 548 path = resolvePath(path, parent) 549 if contains(processed, path) { 550 return nil 551 } 552 processed = append(processed, path) 553 554 f, err := open(path) 555 // return file close error as named return if another error is not already being returned 556 defer func() { 557 if closeErr := f.Close(); err == nil { 558 err = closeErr 559 } 560 }() 561 if err != nil { 562 return fmt.Errorf("failed to read chain configuration file: %s", err) 563 } 564 if err := json.NewDecoder(f).Decode(config); err != nil { 565 return fmt.Errorf("%v: %s", f, err) 566 } 567 568 // read csv alloc file 569 if err := parseAllocationFile(config, open, path); err != nil { 570 return err 571 } 572 573 includes := make([]string, len(config.Include)) 574 copy(includes, config.Include) 575 config.Include = nil 576 577 for _, include := range includes { 578 err := processFile(include, path) 579 if err != nil { 580 return err 581 } 582 } 583 return 584 } 585 586 err := processFile(mainConfigFile, ".") 587 if err != nil { 588 return nil, err 589 } 590 591 // Make JSON 'id' -> 'identity' (for backwards compatibility) 592 if config.ID != "" && config.Identity == "" { 593 config.Identity = config.ID 594 } 595 596 // Make 'ethash' default (backwards compatibility) 597 if config.Consensus == "" { 598 config.Consensus = "ethash" 599 } 600 601 // Parse bootstrap nodes 602 config.ParsedBootstrap = ParseBootstrapNodeStrings(config.Bootstrap) 603 604 if invalid, ok := config.IsValid(); !ok { 605 return nil, fmt.Errorf("Invalid chain configuration file. Please check the existence and integrity of keys and values for: %v", invalid) 606 } 607 608 config.ChainConfig = config.ChainConfig.SortForks() 609 return config, nil 610 } 611 612 // ReadExternalChainConfigFromFile reads a flagged external json file for blockchain configuration. 613 // It returns a valid and full ("hard") configuration or an error. 614 func ReadExternalChainConfigFromFile(incomingPath string) (*SufficientChainConfig, error) { 615 616 // ensure flag arg cleanliness 617 flaggedExternalChainConfigPath := filepath.Clean(incomingPath) 618 619 // ensure file exists and that it is NOT a directory 620 if info, err := os.Stat(flaggedExternalChainConfigPath); os.IsNotExist(err) { 621 return nil, fmt.Errorf("ERROR: No existing chain configuration file found at: %s", flaggedExternalChainConfigPath) 622 } else if info.IsDir() { 623 return nil, fmt.Errorf("ERROR: Specified configuration file cannot be a directory: %s", flaggedExternalChainConfigPath) 624 } 625 626 config, err := parseExternalChainConfig(flaggedExternalChainConfigPath, func(path string) (io.ReadCloser, error) { return os.Open(path) }) 627 if err != nil { 628 return nil, err 629 } 630 return config, nil 631 } 632 633 // ParseBootstrapNodeStrings is a helper function to parse stringified bs nodes, ie []"enode://e809c4a2fec7daed400e5e28564e23693b23b2cc5a019b612505631bbe7b9ccf709c1796d2a3d29ef2b045f210caf51e3c4f5b6d3587d43ad5d6397526fa6179@174.112.32.157:30303",... 634 // to usable Nodes. It takes a slice of strings and returns a slice of Nodes. 635 func ParseBootstrapNodeStrings(nodeStrings []string) []*discover.Node { 636 // Otherwise parse and use the CLI bootstrap nodes 637 bootnodes := []*discover.Node{} 638 639 for _, url := range nodeStrings { 640 url = strings.TrimSpace(url) 641 if url == "" { 642 continue 643 } 644 node, err := discover.ParseNode(url) 645 if err != nil { 646 glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err) 647 continue 648 } 649 bootnodes = append(bootnodes, node) 650 } 651 return bootnodes 652 } 653 654 // GetString gets and option value for an options with key 'name', 655 // returning value as a string. 656 func (o *ForkFeature) GetString(name string) (string, bool) { 657 o.parsedOptionsLock.Lock() 658 defer o.parsedOptionsLock.Unlock() 659 660 if o.ParsedOptions == nil { 661 o.ParsedOptions = make(map[string]interface{}) 662 } else { 663 val, ok := o.ParsedOptions[name] 664 if ok { 665 return val.(string), ok 666 } 667 } 668 o.optionsLock.RLock() 669 defer o.optionsLock.RUnlock() 670 671 val, ok := o.Options[name].(string) 672 o.ParsedOptions[name] = val //expect it as a string in config 673 674 return val, ok 675 } 676 677 // GetBigInt gets and option value for an options with key 'name', 678 // returning value as a *big.Int and ok if it exists. 679 func (o *ForkFeature) GetBigInt(name string) (*big.Int, bool) { 680 i := new(big.Int) 681 682 o.parsedOptionsLock.Lock() 683 defer o.parsedOptionsLock.Unlock() 684 685 if o.ParsedOptions == nil { 686 o.ParsedOptions = make(map[string]interface{}) 687 } else { 688 val, ok := o.ParsedOptions[name] 689 if ok { 690 if vv, ok := val.(*big.Int); ok { 691 return i.Set(vv), true 692 } 693 } 694 } 695 696 o.optionsLock.RLock() 697 originalValue, ok := o.Options[name] 698 o.optionsLock.RUnlock() 699 if !ok { 700 return nil, false 701 } 702 703 // interface{} type assertion for _61_ is float64 704 if value, ok := originalValue.(float64); ok { 705 i.SetInt64(int64(value)) 706 o.ParsedOptions[name] = i 707 return i, true 708 } 709 // handle other user-generated incoming options with some, albeit limited, degree of lenience 710 if value, ok := originalValue.(int64); ok { 711 i.SetInt64(value) 712 o.ParsedOptions[name] = i 713 return i, true 714 } 715 if value, ok := originalValue.(int); ok { 716 i.SetInt64(int64(value)) 717 o.ParsedOptions[name] = i 718 return i, true 719 } 720 if value, ok := originalValue.(string); ok { 721 ii, ok := new(big.Int).SetString(value, 0) 722 if ok { 723 i.Set(ii) 724 o.ParsedOptions[name] = i 725 } 726 return i, ok 727 } 728 return nil, false 729 } 730 731 // WriteGenesisBlock writes the genesis block to the database as block number 0 732 func WriteGenesisBlock(chainDb ethdb.Database, genesis *GenesisDump) (*types.Block, error) { 733 statedb, err := state.New(common.Hash{}, state.NewDatabase(chainDb)) 734 if err != nil { 735 return nil, err 736 } 737 738 for addrHex, account := range genesis.Alloc { 739 var addr common.Address 740 if err := addrHex.Decode(addr[:]); err != nil { 741 return nil, fmt.Errorf("malformed addres %q: %s", addrHex, err) 742 } 743 744 balance, ok := new(big.Int).SetString(account.Balance, 0) 745 if !ok { 746 return nil, fmt.Errorf("malformed account %q balance %q", addrHex, account.Balance) 747 } 748 statedb.AddBalance(addr, balance) 749 750 code, err := account.Code.Bytes() 751 if err != nil { 752 return nil, fmt.Errorf("malformed account %q code: %s", addrHex, err) 753 } 754 statedb.SetCode(addr, code) 755 756 for key, value := range account.Storage { 757 var k, v common.Hash 758 if err := key.Decode(k[:]); err != nil { 759 return nil, fmt.Errorf("malformed account %q key: %s", addrHex, err) 760 } 761 if err := value.Decode(v[:]); err != nil { 762 return nil, fmt.Errorf("malformed account %q value: %s", addrHex, err) 763 } 764 statedb.SetState(addr, k, v) 765 } 766 } 767 root, err := statedb.CommitTo(chainDb, false) 768 if err != nil { 769 return nil, err 770 } 771 772 header, err := genesis.Header() 773 if err != nil { 774 return nil, err 775 } 776 header.Root = root 777 778 gblock := types.NewBlock(header, nil, nil, nil) 779 780 if block := GetBlock(chainDb, gblock.Hash()); block != nil { 781 glog.V(logger.Debug).Infof("Genesis block %s already exists in chain -- writing canonical number", block.Hash().Hex()) 782 err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) 783 if err != nil { 784 return nil, err 785 } 786 return block, nil 787 } 788 789 //if err := stateBatch.Write(); err != nil { 790 // return nil, fmt.Errorf("cannot write state: %v", err) 791 //} 792 if err := WriteTd(chainDb, gblock.Hash(), header.Difficulty); err != nil { 793 return nil, err 794 } 795 if err := WriteBlock(chainDb, gblock); err != nil { 796 return nil, err 797 } 798 if err := WriteBlockReceipts(chainDb, gblock.Hash(), nil); err != nil { 799 return nil, err 800 } 801 if err := WriteCanonicalHash(chainDb, gblock.Hash(), gblock.NumberU64()); err != nil { 802 return nil, err 803 } 804 if err := WriteHeadBlockHash(chainDb, gblock.Hash()); err != nil { 805 return nil, err 806 } 807 808 return gblock, nil 809 } 810 811 func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) *types.Block { 812 dump := GenesisDump{ 813 GasLimit: "0x47E7C4", 814 Difficulty: "0x020000", 815 Alloc: make(map[hex]*GenesisDumpAlloc, len(accounts)), 816 } 817 818 for _, a := range accounts { 819 dump.Alloc[hex(hexlib.EncodeToString(a.Address[:]))] = &GenesisDumpAlloc{ 820 Balance: a.Balance.String(), 821 } 822 } 823 824 block, err := WriteGenesisBlock(db, &dump) 825 if err != nil { 826 panic(err) 827 } 828 return block 829 } 830 831 // MakeGenesisDump makes a genesis dump 832 func MakeGenesisDump(chaindb ethdb.Database) (*GenesisDump, error) { 833 834 genesis := GetBlock(chaindb, GetCanonicalHash(chaindb, 0)) 835 if genesis == nil { 836 return nil, nil 837 } 838 839 // Settings. 840 genesisHeader := genesis.Header() 841 nonce := fmt.Sprintf(`0x%x`, genesisHeader.Nonce) 842 time := common.BigToHash(genesisHeader.Time).Hex() 843 parentHash := genesisHeader.ParentHash.Hex() 844 gasLimit := common.BigToHash(genesisHeader.GasLimit).Hex() 845 difficulty := common.BigToHash(genesisHeader.Difficulty).Hex() 846 mixHash := genesisHeader.MixDigest.Hex() 847 coinbase := genesisHeader.Coinbase.Hex() 848 849 var dump = &GenesisDump{ 850 Nonce: prefixedHex(nonce), // common.ToHex(n)), // common.ToHex( 851 Timestamp: prefixedHex(time), 852 ParentHash: prefixedHex(parentHash), 853 //ExtraData: prefixedHex(extra), 854 GasLimit: prefixedHex(gasLimit), 855 Difficulty: prefixedHex(difficulty), 856 Mixhash: prefixedHex(mixHash), 857 Coinbase: prefixedHex(coinbase), 858 //Alloc: , 859 } 860 if genesisHeader.Extra != nil && len(genesisHeader.Extra) > 0 { 861 dump.ExtraData = prefixedHex(common.ToHex(genesisHeader.Extra)) 862 } 863 864 // State allocations. 865 genState, err := state.New(genesis.Root(), state.NewDatabase(chaindb)) 866 if err != nil { 867 return nil, err 868 } 869 stateDump := genState.RawDump([]common.Address{}) 870 871 stateAccounts := stateDump.Accounts 872 dump.Alloc = make(map[hex]*GenesisDumpAlloc, len(stateAccounts)) 873 874 for address, acct := range stateAccounts { 875 if common.IsHexAddress(address) { 876 dump.Alloc[hex(address)] = &GenesisDumpAlloc{ 877 Balance: acct.Balance, 878 } 879 } else { 880 return nil, fmt.Errorf("Invalid address in genesis state: %v", address) 881 } 882 } 883 return dump, nil 884 }