aboutsummaryrefslogtreecommitdiff
path: root/core/genesis.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/genesis.go')
-rw-r--r--core/genesis.go252
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
+}