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  }