diff options
author | Determinant <[email protected]> | 2019-08-12 13:04:52 -0400 |
---|---|---|
committer | Determinant <[email protected]> | 2019-08-12 13:04:52 -0400 |
commit | ce505015e5f973c8f5d605aa468ad75fceeeb169 (patch) | |
tree | e1417b83881024c9dc4960dd304805327f64d615 /core/genesis.go | |
parent | 068cb794976da713fb4671e1bb4e4657d3dcc2b3 (diff) |
...
Diffstat (limited to 'core/genesis.go')
-rw-r--r-- | core/genesis.go | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/core/genesis.go b/core/genesis.go new file mode 100644 index 0000000..b421e08 --- /dev/null +++ b/core/genesis.go @@ -0,0 +1,252 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package core + +import ( + "bytes" + "encoding/hex" + "errors" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/core" +) + +var errGenesisNoConfig = errors.New("genesis has no chain configuration") + +type Genesis = core.Genesis +type GenesisAlloc = core.GenesisAlloc +type GenesisAccount = core.GenesisAccount + +// storageJSON represents a 256 bit byte array, but allows less than 256 bits when +// unmarshaling from hex. +type storageJSON common.Hash + +func (h *storageJSON) UnmarshalText(text []byte) error { + text = bytes.TrimPrefix(text, []byte("0x")) + if len(text) > 64 { + return fmt.Errorf("too many hex characters in storage key/value %q", text) + } + offset := len(h) - len(text)/2 // pad on the left + if _, err := hex.Decode(h[offset:], text); err != nil { + fmt.Println(err) + return fmt.Errorf("invalid hex storage key/value %q", text) + } + return nil +} + +func (h storageJSON) MarshalText() ([]byte, error) { + return hexutil.Bytes(h[:]).MarshalText() +} + +// SetupGenesisBlock writes or updates the genesis block in db. +// The block that will be used is: +// +// genesis == nil genesis != nil +// +------------------------------------------ +// db has no genesis | main-net default | genesis +// db has genesis | from DB | genesis (if compatible) +// +// The stored chain configuration will be updated if it is compatible (i.e. does not +// specify a fork block below the local head block). In case of a conflict, the +// error is a *params.ConfigCompatError and the new, unwritten config is returned. +// +// The returned chain configuration is never nil. +func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { + if genesis != nil && genesis.Config == nil { + return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig + } + // Just commit the new block if there is no stored genesis block. + stored := rawdb.ReadCanonicalHash(db, 0) + if (stored == common.Hash{}) { + if genesis == nil { + log.Info("Writing default main-net genesis block") + genesis = DefaultGenesisBlock() + } else { + log.Info("Writing custom genesis block") + } + block, err := genesis.Commit(db) + if err != nil { + return genesis.Config, common.Hash{}, err + } + return genesis.Config, block.Hash(), nil + } + + // We have the genesis block in database(perhaps in ancient database) + // but the corresponding state is missing. + header := rawdb.ReadHeader(db, stored, 0) + if _, err := state.New(header.Root, state.NewDatabaseWithCache(db, 0)); err != nil { + if genesis == nil { + genesis = DefaultGenesisBlock() + } + // Ensure the stored genesis matches with the given one. + hash := genesis.ToBlock(nil).Hash() + if hash != stored { + return genesis.Config, hash, &core.GenesisMismatchError{stored, hash} + } + block, err := genesis.Commit(db) + if err != nil { + return genesis.Config, hash, err + } + return genesis.Config, block.Hash(), nil + } + + // Check whether the genesis block is already written. + if genesis != nil { + hash := genesis.ToBlock(nil).Hash() + if hash != stored { + return genesis.Config, hash, &core.GenesisMismatchError{stored, hash} + } + } + + // Get the existing chain configuration. + newcfg := configOrDefault(genesis, stored) + storedcfg := rawdb.ReadChainConfig(db, stored) + if storedcfg == nil { + log.Warn("Found genesis block without chain config") + rawdb.WriteChainConfig(db, stored, newcfg) + return newcfg, stored, nil + } + // Special case: don't change the existing config of a non-mainnet chain if no new + // config is supplied. These chains would get AllProtocolChanges (and a compat error) + // if we just continued here. + if genesis == nil && stored != params.MainnetGenesisHash { + return storedcfg, stored, nil + } + + // Check config compatibility and write the config. Compatibility errors + // are returned to the caller unless we're already at block zero. + height := rawdb.ReadHeaderNumber(db, rawdb.ReadHeadHeaderHash(db)) + if height == nil { + return newcfg, stored, fmt.Errorf("missing block number for head header hash") + } + compatErr := storedcfg.CheckCompatible(newcfg, *height) + if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 { + return newcfg, stored, compatErr + } + rawdb.WriteChainConfig(db, stored, newcfg) + return newcfg, stored, nil +} + +func configOrDefault(g *Genesis, ghash common.Hash) *params.ChainConfig { + switch { + case g != nil: + return g.Config + case ghash == params.MainnetGenesisHash: + return params.MainnetChainConfig + case ghash == params.TestnetGenesisHash: + return params.TestnetChainConfig + default: + return params.AllEthashProtocolChanges + } +} + +// DefaultGenesisBlock returns the Ethereum main net genesis block. +func DefaultGenesisBlock() *Genesis { + return &Genesis{ + Config: params.MainnetChainConfig, + Nonce: 66, + ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), + GasLimit: 5000, + Difficulty: big.NewInt(17179869184), + Alloc: decodePrealloc(mainnetAllocData), + } +} + +// DefaultTestnetGenesisBlock returns the Ropsten network genesis block. +func DefaultTestnetGenesisBlock() *Genesis { + return &Genesis{ + Config: params.TestnetChainConfig, + Nonce: 66, + ExtraData: hexutil.MustDecode("0x3535353535353535353535353535353535353535353535353535353535353535"), + GasLimit: 16777216, + Difficulty: big.NewInt(1048576), + Alloc: decodePrealloc(testnetAllocData), + } +} + +// DefaultRinkebyGenesisBlock returns the Rinkeby network genesis block. +func DefaultRinkebyGenesisBlock() *Genesis { + return &Genesis{ + Config: params.RinkebyChainConfig, + Timestamp: 1492009146, + ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + GasLimit: 4700000, + Difficulty: big.NewInt(1), + Alloc: decodePrealloc(rinkebyAllocData), + } +} + +// DefaultGoerliGenesisBlock returns the Görli network genesis block. +func DefaultGoerliGenesisBlock() *Genesis { + return &Genesis{ + Config: params.GoerliChainConfig, + Timestamp: 1548854791, + ExtraData: hexutil.MustDecode("0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + GasLimit: 10485760, + Difficulty: big.NewInt(1), + Alloc: decodePrealloc(goerliAllocData), + } +} + +// DeveloperGenesisBlock returns the 'geth --dev' genesis block. Note, this must +// be seeded with the +func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { + // Override the default period to the user requested one + config := *params.AllCliqueProtocolChanges + config.Clique.Period = period + + // Assemble and return the genesis with the precompiles and faucet pre-funded + return &Genesis{ + Config: &config, + ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, 65)...), + GasLimit: 6283185, + Difficulty: big.NewInt(1), + Alloc: map[common.Address]GenesisAccount{ + common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover + common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256 + common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD + common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity + common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp + common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd + common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul + common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing + faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, + }, + } +} + +func decodePrealloc(data string) GenesisAlloc { + var p []struct{ Addr, Balance *big.Int } + if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil { + panic(err) + } + ga := make(GenesisAlloc, len(p)) + for _, account := range p { + ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance} + } + return ga +} |