Browse Source

core: refactor genesis handling

This commit solves several issues concerning the genesis block:

* Genesis/ChainConfig loading was handled by cmd/geth code. This left
  library users in the cold. They could specify a JSON-encoded
  string and overwrite the config, but didn't get any of the additional
  checks performed by geth.
* Decoding and writing of genesis JSON was conflated in
  WriteGenesisBlock. This made it a lot harder to embed the genesis
  block into the forthcoming config file loader. This commit changes
  things so there is a single Genesis type that represents genesis
  blocks. All uses of Write*Genesis* are changed to use the new type
  instead.
* If the chain config supplied by the user was incompatible with the
  current chain (i.e. the chain had already advanced beyond a scheduled
  fork), it got overwritten. This is not an issue in practice because
  previous forks have always had the highest total difficulty. It might
  matter in the future though. The new code reverts the local chain to
  the point of the fork when upgrading configuration.

The change to genesis block data removes compression library
dependencies from package core.
Felix Lange 8 years ago
parent
commit
37dd9086ec

+ 8 - 10
accounts/abi/bind/backends/simulated.go

@@ -37,9 +37,6 @@ import (
 	"github.com/ethereum/go-ethereum/pow"
 )
 
-// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
-var chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
-
 // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
 var _ bind.ContractBackend = (*SimulatedBackend)(nil)
 
@@ -60,11 +57,12 @@ type SimulatedBackend struct {
 
 // NewSimulatedBackend creates a new binding backend using a simulated blockchain
 // for testing purposes.
-func NewSimulatedBackend(accounts ...core.GenesisAccount) *SimulatedBackend {
+func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
 	database, _ := ethdb.NewMemDatabase()
-	core.WriteGenesisBlockForTesting(database, accounts...)
-	blockchain, _ := core.NewBlockChain(database, chainConfig, new(pow.FakePow), new(event.TypeMux), vm.Config{})
-	backend := &SimulatedBackend{database: database, blockchain: blockchain}
+	genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
+	genesis.MustCommit(database)
+	blockchain, _ := core.NewBlockChain(database, genesis.Config, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+	backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}
 	backend.rollback()
 	return backend
 }
@@ -90,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
 }
 
 func (b *SimulatedBackend) rollback() {
-	blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
+	blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
 	b.pendingBlock = blocks[0]
 	b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
 }
@@ -253,7 +251,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
 	evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
 	// Create a new environment which holds all relevant information
 	// about the transaction and calling mechanisms.
-	vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{})
+	vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
 	gaspool := new(core.GasPool).AddGas(math.MaxBig256)
 	ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
 	return ret, gasUsed, err
@@ -274,7 +272,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
 		panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
 	}
 
-	blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
+	blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
 		for _, tx := range b.pendingBlock.Transactions() {
 			block.AddTx(tx)
 		}

+ 9 - 9
accounts/abi/bind/bind_test.go

@@ -169,7 +169,7 @@ var bindTests = []struct {
 			// Generate a new random account and a funded simulator
 			key, _ := crypto.GenerateKey()
 			auth := bind.NewKeyedTransactor(key)
-			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
+			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
 
 			// Deploy an interaction tester contract and call a transaction on it
 			_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
@@ -210,7 +210,7 @@ var bindTests = []struct {
 			// Generate a new random account and a funded simulator
 			key, _ := crypto.GenerateKey()
 			auth := bind.NewKeyedTransactor(key)
-			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
+			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
 
 			// Deploy a tuple tester contract and execute a structured call on it
 			_, _, getter, err := DeployGetter(auth, sim)
@@ -242,7 +242,7 @@ var bindTests = []struct {
 			// Generate a new random account and a funded simulator
 			key, _ := crypto.GenerateKey()
 			auth := bind.NewKeyedTransactor(key)
-			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
+			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
 
 			// Deploy a tuple tester contract and execute a structured call on it
 			_, _, tupler, err := DeployTupler(auth, sim)
@@ -284,7 +284,7 @@ var bindTests = []struct {
 			// Generate a new random account and a funded simulator
 			key, _ := crypto.GenerateKey()
 			auth := bind.NewKeyedTransactor(key)
-			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
+			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
 
 			// Deploy a slice tester contract and execute a n array call on it
 			_, _, slicer, err := DeploySlicer(auth, sim)
@@ -318,7 +318,7 @@ var bindTests = []struct {
 			// Generate a new random account and a funded simulator
 			key, _ := crypto.GenerateKey()
 			auth := bind.NewKeyedTransactor(key)
-			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
+			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
 
 			// Deploy a default method invoker contract and execute its default method
 			_, _, defaulter, err := DeployDefaulter(auth, sim)
@@ -351,7 +351,7 @@ var bindTests = []struct {
 		`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
 		`
 			// Create a simulator and wrap a non-deployed contract
-			sim := backends.NewSimulatedBackend()
+			sim := backends.NewSimulatedBackend(nil)
 
 			nonexistent, err := NewNonExistent(common.Address{}, sim)
 			if err != nil {
@@ -387,7 +387,7 @@ var bindTests = []struct {
 			// Generate a new random account and a funded simulator
 			key, _ := crypto.GenerateKey()
 			auth := bind.NewKeyedTransactor(key)
-			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
+			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
 
 			// Deploy a funky gas pattern contract
 			_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
@@ -423,7 +423,7 @@ var bindTests = []struct {
 			// Generate a new random account and a funded simulator
 			key, _ := crypto.GenerateKey()
 			auth := bind.NewKeyedTransactor(key)
-			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
+			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
 
 			// Deploy a sender tester contract and execute a structured call on it
 			_, _, callfrom, err := DeployCallFrom(auth, sim)
@@ -458,7 +458,7 @@ func TestBindings(t *testing.T) {
 		t.Skip("go sdk not found for testing")
 	}
 	// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
-	linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend())\n}")
+	linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}")
 	linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil)
 	if err != nil {
 		t.Fatalf("failed check for goimports symlink bug: %v", err)

+ 2 - 3
accounts/abi/bind/util_test.go

@@ -53,9 +53,8 @@ var waitDeployedTests = map[string]struct {
 
 func TestWaitDeployed(t *testing.T) {
 	for name, test := range waitDeployedTests {
-		backend := backends.NewSimulatedBackend(core.GenesisAccount{
-			Address: crypto.PubkeyToAddress(testKey.PublicKey),
-			Balance: big.NewInt(10000000000),
+		backend := backends.NewSimulatedBackend(core.GenesisAlloc{
+			crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
 		})
 
 		// Create the transaction.

+ 10 - 4
cmd/geth/chaincmd.go

@@ -17,6 +17,7 @@
 package main
 
 import (
+	"encoding/json"
 	"fmt"
 	"os"
 	"runtime"
@@ -110,17 +111,22 @@ func initGenesis(ctx *cli.Context) error {
 	stack := makeFullNode(ctx)
 	chaindb := utils.MakeChainDatabase(ctx, stack)
 
-	genesisFile, err := os.Open(genesisPath)
+	file, err := os.Open(genesisPath)
 	if err != nil {
 		utils.Fatalf("failed to read genesis file: %v", err)
 	}
-	defer genesisFile.Close()
+	defer file.Close()
 
-	block, err := core.WriteGenesisBlock(chaindb, genesisFile)
+	genesis := new(core.Genesis)
+	if err := json.NewDecoder(file).Decode(genesis); err != nil {
+		utils.Fatalf("invalid genesis file: %v", err)
+	}
+
+	_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
 	if err != nil {
 		utils.Fatalf("failed to write genesis block: %v", err)
 	}
-	log.Info("Successfully wrote genesis state", "hash", block.Hash())
+	log.Info("Successfully wrote genesis state", "hash", hash)
 	return nil
 }
 

+ 18 - 73
cmd/utils/flags.go

@@ -786,7 +786,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
 
 	ethConf := &eth.Config{
 		Etherbase:               MakeEtherbase(ks, ctx),
-		ChainConfig:             MakeChainConfig(ctx, stack),
 		FastSync:                ctx.GlobalBool(FastSyncFlag.Name),
 		LightMode:               ctx.GlobalBool(LightModeFlag.Name),
 		LightServ:               ctx.GlobalInt(LightServFlag.Name),
@@ -822,7 +821,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
 			ethConf.NetworkId = 3
 		}
 		ethConf.Genesis = core.DefaultTestnetGenesisBlock()
-
 	case ctx.GlobalBool(DevModeFlag.Name):
 		ethConf.Genesis = core.DevGenesisBlock()
 		if !ctx.GlobalIsSet(GasPriceFlag.Name) {
@@ -884,67 +882,6 @@ func SetupNetwork(ctx *cli.Context) {
 	params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name))
 }
 
-// MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
-func MakeChainConfig(ctx *cli.Context, stack *node.Node) *params.ChainConfig {
-	db := MakeChainDatabase(ctx, stack)
-	defer db.Close()
-
-	return MakeChainConfigFromDb(ctx, db)
-}
-
-// MakeChainConfigFromDb reads the chain configuration from the given database.
-func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainConfig {
-	// If the chain is already initialized, use any existing chain configs
-	config := new(params.ChainConfig)
-
-	genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
-	if genesis != nil {
-		storedConfig, err := core.GetChainConfig(db, genesis.Hash())
-		switch err {
-		case nil:
-			config = storedConfig
-		case core.ChainConfigNotFoundErr:
-			// No configs found, use empty, will populate below
-		default:
-			Fatalf("Could not make chain configuration: %v", err)
-		}
-	}
-	// set chain id in case it's zero.
-	if config.ChainId == nil {
-		config.ChainId = new(big.Int)
-	}
-	// Check whether we are allowed to set default config params or not:
-	//  - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`)
-	//  - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
-	defaults := genesis == nil ||
-		(genesis.Hash() == params.MainNetGenesisHash && !ctx.GlobalBool(TestNetFlag.Name)) ||
-		(genesis.Hash() == params.TestNetGenesisHash && ctx.GlobalBool(TestNetFlag.Name))
-
-	if defaults {
-		if ctx.GlobalBool(TestNetFlag.Name) {
-			config = params.TestnetChainConfig
-		} else if ctx.GlobalBool(DevModeFlag.Name) {
-			config = params.AllProtocolChanges
-		} else {
-			// Homestead fork
-			config.HomesteadBlock = params.MainNetHomesteadBlock
-			// DAO fork
-			config.DAOForkBlock = params.MainNetDAOForkBlock
-			config.DAOForkSupport = true
-
-			// DoS reprice fork
-			config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
-			config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
-
-			// DoS state cleanup fork
-			config.EIP155Block = params.MainNetSpuriousDragon
-			config.EIP158Block = params.MainNetSpuriousDragon
-			config.ChainId = params.MainNetChainID
-		}
-	}
-	return config
-}
-
 func ChainDbName(ctx *cli.Context) string {
 	if ctx.GlobalBool(LightModeFlag.Name) {
 		return "lightchaindata"
@@ -968,26 +905,34 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
 	return chainDb
 }
 
+func MakeGenesis(ctx *cli.Context) *core.Genesis {
+	var genesis *core.Genesis
+	switch {
+	case ctx.GlobalBool(TestNetFlag.Name):
+		genesis = core.DefaultTestnetGenesisBlock()
+	case ctx.GlobalBool(DevModeFlag.Name):
+		genesis = core.DevGenesisBlock()
+	}
+	return genesis
+}
+
 // MakeChain creates a chain manager from set command line flags.
 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
 	var err error
 	chainDb = MakeChainDatabase(ctx, stack)
 
-	if ctx.GlobalBool(TestNetFlag.Name) {
-		_, err := core.WriteTestNetGenesisBlock(chainDb)
-		if err != nil {
-			Fatalf("Failed to write testnet genesis: %v", err)
-		}
-	}
-	chainConfig := MakeChainConfigFromDb(ctx, chainDb)
-
 	seal := pow.PoW(pow.FakePow{})
 	if !ctx.GlobalBool(FakePoWFlag.Name) {
 		seal = pow.NewFullEthash("", 1, 0, "", 1, 0)
 	}
-	chain, err = core.NewBlockChain(chainDb, chainConfig, seal, new(event.TypeMux), vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)})
+	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
+	if err != nil {
+		Fatalf("%v", err)
+	}
+	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
+	chain, err = core.NewBlockChain(chainDb, config, seal, new(event.TypeMux), vmcfg)
 	if err != nil {
-		Fatalf("Could not start chainmanager: %v", err)
+		Fatalf("Can't create BlockChain: %v", err)
 	}
 	return chain, chainDb
 }

+ 4 - 5
console/console_test.go

@@ -21,17 +21,16 @@ import (
 	"errors"
 	"fmt"
 	"io/ioutil"
-	"math/big"
 	"os"
 	"strings"
 	"testing"
 	"time"
 
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/internal/jsre"
 	"github.com/ethereum/go-ethereum/node"
-	"github.com/ethereum/go-ethereum/params"
 )
 
 const (
@@ -97,9 +96,9 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
 		t.Fatalf("failed to create node: %v", err)
 	}
 	ethConf := &eth.Config{
-		ChainConfig: &params.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)},
-		Etherbase:   common.HexToAddress(testAddress),
-		PowTest:     true,
+		Genesis:   core.DevGenesisBlock(),
+		Etherbase: common.HexToAddress(testAddress),
+		PowTest:   true,
 	}
 	if confOverride != nil {
 		confOverride(ethConf)

+ 5 - 5
contracts/chequebook/cheque_test.go

@@ -42,11 +42,11 @@ var (
 )
 
 func newTestBackend() *backends.SimulatedBackend {
-	return backends.NewSimulatedBackend(
-		core.GenesisAccount{Address: addr0, Balance: big.NewInt(1000000000)},
-		core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000000)},
-		core.GenesisAccount{Address: addr2, Balance: big.NewInt(1000000000)},
-	)
+	return backends.NewSimulatedBackend(core.GenesisAlloc{
+		addr0: {Balance: big.NewInt(1000000000)},
+		addr1: {Balance: big.NewInt(1000000000)},
+		addr2: {Balance: big.NewInt(1000000000)},
+	})
 }
 
 func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {

+ 1 - 1
contracts/ens/ens_test.go

@@ -34,7 +34,7 @@ var (
 )
 
 func TestENS(t *testing.T) {
-	contractBackend := backends.NewSimulatedBackend(core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000000)})
+	contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
 	transactOpts := bind.NewKeyedTransactor(key)
 	// Workaround for bug estimating gas in the call to Register
 	transactOpts.GasLimit = big.NewInt(1000000)

+ 3 - 3
contracts/release/contract_test.go

@@ -35,11 +35,11 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat
 	key, _ := crypto.GenerateKey()
 	auth := bind.NewKeyedTransactor(key)
 
-	accounts := []core.GenesisAccount{{Address: auth.From, Balance: big.NewInt(10000000000)}}
+	alloc := core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}
 	for _, key := range prefund {
-		accounts = append(accounts, core.GenesisAccount{Address: crypto.PubkeyToAddress(key.PublicKey), Balance: big.NewInt(10000000000)})
+		alloc[crypto.PubkeyToAddress(key.PublicKey)] = core.GenesisAccount{Balance: big.NewInt(10000000000)}
 	}
-	sim := backends.NewSimulatedBackend(accounts...)
+	sim := backends.NewSimulatedBackend(alloc)
 
 	// Deploy a version oracle contract, commit and return
 	_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})

+ 8 - 4
core/bench_test.go

@@ -166,13 +166,17 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
 
 	// Generate a chain of b.N blocks using the supplied block
 	// generator function.
-	genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
-	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen)
+	gspec := Genesis{
+		Config: params.TestChainConfig,
+		Alloc:  GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}},
+	}
+	genesis := gspec.MustCommit(db)
+	chain, _ := GenerateChain(gspec.Config, genesis, db, b.N, gen)
 
 	// Time the insertion of the new chain.
 	// State and blocks are stored in the same DB.
 	evmux := new(event.TypeMux)
-	chainman, _ := NewBlockChain(db, &params.ChainConfig{HomesteadBlock: new(big.Int)}, pow.FakePow{}, evmux, vm.Config{})
+	chainman, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
 	defer chainman.Stop()
 	b.ReportAllocs()
 	b.ResetTimer()
@@ -282,7 +286,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
 		if err != nil {
 			b.Fatalf("error opening database at %v: %v", dir, err)
 		}
-		chain, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
+		chain, err := NewBlockChain(db, params.TestChainConfig, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 		if err != nil {
 			b.Fatalf("error creating chain: %v", err)
 		}

+ 9 - 24
core/block_validator_test.go

@@ -17,51 +17,36 @@
 package core
 
 import (
-	"fmt"
 	"math/big"
 	"testing"
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 )
 
-func testChainConfig() *params.ChainConfig {
-	return params.TestChainConfig
-	//return &params.ChainConfig{HomesteadBlock: big.NewInt(0)}
-}
-
-func proc() (Validator, *BlockChain) {
-	db, _ := ethdb.NewMemDatabase()
-	var mux event.TypeMux
-
-	WriteTestNetGenesisBlock(db)
-	blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &mux, vm.Config{})
-	if err != nil {
-		fmt.Println(err)
+func testGenesis(account common.Address, balance *big.Int) *Genesis {
+	return &Genesis{
+		Config: params.TestChainConfig,
+		Alloc:  GenesisAlloc{account: {Balance: balance}},
 	}
-	return blockchain.validator, blockchain
 }
 
 func TestNumber(t *testing.T) {
-	_, chain := proc()
-
+	chain := newTestBlockChain()
 	statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
-	cfg := testChainConfig()
-	header := makeHeader(cfg, chain.Genesis(), statedb)
+	header := makeHeader(chain.config, chain.Genesis(), statedb)
 	header.Number = big.NewInt(3)
-	err := ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
+	err := ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
 	if err != BlockNumberErr {
 		t.Errorf("expected block number error, got %q", err)
 	}
 
-	header = makeHeader(cfg, chain.Genesis(), statedb)
-	err = ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
+	header = makeHeader(chain.config, chain.Genesis(), statedb)
+	err = ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
 	if err == BlockNumberErr {
 		t.Errorf("didn't expect block number error")
 	}

+ 108 - 243
core/blockchain_test.go

@@ -20,10 +20,6 @@ import (
 	"fmt"
 	"math/big"
 	"math/rand"
-	"os"
-	"path/filepath"
-	"runtime"
-	"strconv"
 	"testing"
 	"time"
 
@@ -36,24 +32,21 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
-	"github.com/ethereum/go-ethereum/rlp"
-	"github.com/hashicorp/golang-lru"
 )
 
-func init() {
-	runtime.GOMAXPROCS(runtime.NumCPU())
-}
-
-func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain {
-	var eventMux event.TypeMux
-	WriteTestNetGenesisBlock(db)
-	blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &eventMux, vm.Config{})
+// newTestBlockChain creates a blockchain without validation.
+func newTestBlockChain() *BlockChain {
+	db, _ := ethdb.NewMemDatabase()
+	gspec := &Genesis{
+		Config:     params.TestChainConfig,
+		Difficulty: big.NewInt(1),
+	}
+	gspec.MustCommit(db)
+	blockchain, err := NewBlockChain(db, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 	if err != nil {
-		t.Error("failed creating blockchain:", err)
-		t.FailNow()
-		return nil
+		panic(err)
 	}
-
+	blockchain.SetValidator(bproc{})
 	return blockchain
 }
 
@@ -171,21 +164,6 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error
 	return nil
 }
 
-func loadChain(fn string, t *testing.T) (types.Blocks, error) {
-	fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm)
-	if err != nil {
-		return nil, err
-	}
-	defer fh.Close()
-
-	var chain types.Blocks
-	if err := rlp.Decode(fh, &chain); err != nil {
-		return nil, err
-	}
-
-	return chain, nil
-}
-
 func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) {
 	_, err := blockchain.InsertChain(chain)
 	if err != nil {
@@ -196,12 +174,10 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *
 }
 
 func TestLastBlock(t *testing.T) {
-	db, _ := ethdb.NewMemDatabase()
-
-	bchain := theBlockChain(db, t)
-	block := makeBlockChain(bchain.CurrentBlock(), 1, db, 0)[0]
+	bchain := newTestBlockChain()
+	block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]
 	bchain.insert(block)
-	if block.Hash() != GetHeadBlockHash(db) {
+	if block.Hash() != GetHeadBlockHash(bchain.chainDb) {
 		t.Errorf("Write/Get HeadBlockHash failed")
 	}
 }
@@ -340,88 +316,6 @@ func testBrokenChain(t *testing.T, full bool) {
 	}
 }
 
-func TestChainInsertions(t *testing.T) {
-	t.Skip("Skipped: outdated test files")
-
-	db, _ := ethdb.NewMemDatabase()
-
-	chain1, err := loadChain("valid1", t)
-	if err != nil {
-		fmt.Println(err)
-		t.FailNow()
-	}
-
-	chain2, err := loadChain("valid2", t)
-	if err != nil {
-		fmt.Println(err)
-		t.FailNow()
-	}
-
-	blockchain := theBlockChain(db, t)
-
-	const max = 2
-	done := make(chan bool, max)
-
-	go insertChain(done, blockchain, chain1, t)
-	go insertChain(done, blockchain, chain2, t)
-
-	for i := 0; i < max; i++ {
-		<-done
-	}
-
-	if chain2[len(chain2)-1].Hash() != blockchain.CurrentBlock().Hash() {
-		t.Error("chain2 is canonical and shouldn't be")
-	}
-
-	if chain1[len(chain1)-1].Hash() != blockchain.CurrentBlock().Hash() {
-		t.Error("chain1 isn't canonical and should be")
-	}
-}
-
-func TestChainMultipleInsertions(t *testing.T) {
-	t.Skip("Skipped: outdated test files")
-
-	db, _ := ethdb.NewMemDatabase()
-
-	const max = 4
-	chains := make([]types.Blocks, max)
-	var longest int
-	for i := 0; i < max; i++ {
-		var err error
-		name := "valid" + strconv.Itoa(i+1)
-		chains[i], err = loadChain(name, t)
-		if len(chains[i]) >= len(chains[longest]) {
-			longest = i
-		}
-		fmt.Println("loaded", name, "with a length of", len(chains[i]))
-		if err != nil {
-			fmt.Println(err)
-			t.FailNow()
-		}
-	}
-
-	blockchain := theBlockChain(db, t)
-
-	done := make(chan bool, max)
-	for i, chain := range chains {
-		// XXX the go routine would otherwise reference the same (chain[3]) variable and fail
-		i := i
-		chain := chain
-		go func() {
-			insertChain(done, blockchain, chain, t)
-			fmt.Println(i, "done")
-		}()
-	}
-
-	for i := 0; i < max; i++ {
-		<-done
-	}
-
-	if chains[longest][len(chains[longest])-1].Hash() != blockchain.CurrentBlock().Hash() {
-		t.Error("Invalid canonical chain")
-	}
-}
-
 type bproc struct{}
 
 func (bproc) ValidateBlock(*types.Block) error                        { return nil }
@@ -452,6 +346,7 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
 			UncleHash:   types.EmptyUncleHash,
 			TxHash:      types.EmptyRootHash,
 			ReceiptHash: types.EmptyRootHash,
+			Time:        big.NewInt(int64(i) + 1),
 		}
 		if i == 0 {
 			header.ParentHash = genesis.Hash()
@@ -464,29 +359,6 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
 	return chain
 }
 
-func chm(genesis *types.Block, db ethdb.Database) *BlockChain {
-	var eventMux event.TypeMux
-	bc := &BlockChain{
-		chainDb:      db,
-		genesisBlock: genesis,
-		eventMux:     &eventMux,
-		pow:          pow.FakePow{},
-		config:       testChainConfig(),
-	}
-	valFn := func() HeaderValidator { return bc.Validator() }
-	bc.hc, _ = NewHeaderChain(db, testChainConfig(), valFn, bc.getProcInterrupt)
-	bc.bodyCache, _ = lru.New(100)
-	bc.bodyRLPCache, _ = lru.New(100)
-	bc.blockCache, _ = lru.New(100)
-	bc.futureBlocks, _ = lru.New(100)
-	bc.badBlocks, _ = lru.New(10)
-	bc.SetValidator(bproc{})
-	bc.SetProcessor(bproc{})
-	bc.ResetWithGenesisBlock(genesis)
-
-	return bc
-}
-
 // Tests that reorganising a long difficult chain after a short easy one
 // overwrites the canonical numbers and links in the database.
 func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }
@@ -506,18 +378,15 @@ func testReorgShort(t *testing.T, full bool) {
 }
 
 func testReorg(t *testing.T, first, second []int, td int64, full bool) {
-	// Create a pristine block chain
-	db, _ := ethdb.NewMemDatabase()
-	genesis, _ := WriteTestNetGenesisBlock(db)
-	bc := chm(genesis, db)
+	bc := newTestBlockChain()
 
 	// Insert an easy and a difficult chain afterwards
 	if full {
-		bc.InsertChain(makeBlockChainWithDiff(genesis, first, 11))
-		bc.InsertChain(makeBlockChainWithDiff(genesis, second, 22))
+		bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11))
+		bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22))
 	} else {
-		bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
-		bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
+		bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
+		bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
 	}
 	// Check that the chain is valid number and link wise
 	if full {
@@ -536,7 +405,7 @@ func testReorg(t *testing.T, first, second []int, td int64, full bool) {
 		}
 	}
 	// Make sure the chain total difficulty is the correct one
-	want := new(big.Int).Add(genesis.Difficulty(), big.NewInt(td))
+	want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
 	if full {
 		if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 {
 			t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
@@ -553,19 +422,16 @@ func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) }
 func TestBadBlockHashes(t *testing.T)  { testBadHashes(t, true) }
 
 func testBadHashes(t *testing.T, full bool) {
-	// Create a pristine block chain
-	db, _ := ethdb.NewMemDatabase()
-	genesis, _ := WriteTestNetGenesisBlock(db)
-	bc := chm(genesis, db)
+	bc := newTestBlockChain()
 
 	// Create a chain, ban a hash and try to import
 	var err error
 	if full {
-		blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 4}, 10)
+		blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
 		BadHashes[blocks[2].Header().Hash()] = true
 		_, err = bc.InsertChain(blocks)
 	} else {
-		headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10)
+		headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
 		BadHashes[headers[2].Hash()] = true
 		_, err = bc.InsertHeaderChain(headers, 1)
 	}
@@ -580,14 +446,11 @@ func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) }
 func TestReorgBadBlockHashes(t *testing.T)  { testReorgBadHashes(t, true) }
 
 func testReorgBadHashes(t *testing.T, full bool) {
-	// Create a pristine block chain
-	db, _ := ethdb.NewMemDatabase()
-	genesis, _ := WriteTestNetGenesisBlock(db)
-	bc := chm(genesis, db)
+	bc := newTestBlockChain()
 
 	// Create a chain, import and ban afterwards
-	headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
-	blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
+	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
+	blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
 
 	if full {
 		if _, err := bc.InsertChain(blocks); err != nil {
@@ -608,8 +471,9 @@ func testReorgBadHashes(t *testing.T, full bool) {
 		BadHashes[headers[3].Hash()] = true
 		defer func() { delete(BadHashes, headers[3].Hash()) }()
 	}
-	// Create a new chain manager and check it rolled back the state
-	ncm, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
+
+	// Create a new BlockChain and check that it rolled back the state.
+	ncm, err := NewBlockChain(bc.chainDb, bc.config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 	if err != nil {
 		t.Fatalf("failed to create new chain manager: %v", err)
 	}
@@ -663,7 +527,7 @@ func testInsertNonceError(t *testing.T, full bool) {
 			failHash = headers[failAt].Hash()
 
 			blockchain.pow = failPow{failNum}
-			blockchain.validator = NewBlockValidator(testChainConfig(), blockchain, failPow{failNum})
+			blockchain.validator = NewBlockValidator(params.TestChainConfig, blockchain, failPow{failNum})
 
 			failRes, err = blockchain.InsertHeaderChain(headers, 1)
 		}
@@ -705,10 +569,11 @@ func TestFastVsFullChains(t *testing.T) {
 		key, _   = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		address  = crypto.PubkeyToAddress(key.PublicKey)
 		funds    = big.NewInt(1000000000)
-		genesis  = GenesisBlockForTesting(gendb, address, funds)
-		signer   = types.NewEIP155Signer(big.NewInt(1))
+		gspec    = testGenesis(address, funds)
+		genesis  = gspec.MustCommit(gendb)
+		signer   = types.NewEIP155Signer(gspec.Config.ChainId)
 	)
-	blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) {
+	blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) {
 		block.SetCoinbase(common.Address{0x00})
 
 		// If the block number is multiple of 3, send a few bonus transactions to the miner
@@ -728,17 +593,17 @@ func TestFastVsFullChains(t *testing.T) {
 	})
 	// Import the chain as an archive node for the comparison baseline
 	archiveDb, _ := ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
-
-	archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	gspec.MustCommit(archiveDb)
+	archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 
 	if n, err := archive.InsertChain(blocks); err != nil {
 		t.Fatalf("failed to process block %d: %v", n, err)
 	}
+
 	// Fast import the chain as a non-archive node to test
 	fastDb, _ := ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
-	fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	gspec.MustCommit(fastDb)
+	fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
@@ -788,10 +653,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 		key, _   = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		address  = crypto.PubkeyToAddress(key.PublicKey)
 		funds    = big.NewInt(1000000000)
-		genesis  = GenesisBlockForTesting(gendb, address, funds)
+		gspec    = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
+		genesis  = gspec.MustCommit(gendb)
 	)
 	height := uint64(1024)
-	blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, int(height), nil)
+	blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, int(height), nil)
 
 	// Configure a subchain to roll back
 	remove := []common.Hash{}
@@ -812,9 +678,9 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 	}
 	// Import the chain as an archive node and ensure all pointers are updated
 	archiveDb, _ := ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
+	gspec.MustCommit(archiveDb)
 
-	archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 
 	if n, err := archive.InsertChain(blocks); err != nil {
 		t.Fatalf("failed to process block %d: %v", n, err)
@@ -825,8 +691,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 
 	// Import the chain as a non-archive node and ensure all pointers are updated
 	fastDb, _ := ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
-	fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	gspec.MustCommit(fastDb)
+	fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
@@ -844,8 +710,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 
 	// Import the chain as a light node and ensure all pointers are updated
 	lightDb, _ := ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds})
-	light, _ := NewBlockChain(lightDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	gspec.MustCommit(lightDb)
+	light, _ := NewBlockChain(lightDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 
 	if n, err := light.InsertHeaderChain(headers, 1); err != nil {
 		t.Fatalf("failed to insert header %d: %v", n, err)
@@ -857,9 +723,6 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 
 // Tests that chain reorganisations handle transaction removals and reinsertions.
 func TestChainTxReorgs(t *testing.T) {
-	params.MinGasLimit = big.NewInt(125000)      // Minimum the gas limit may ever be.
-	params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
-
 	var (
 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
@@ -868,13 +731,19 @@ func TestChainTxReorgs(t *testing.T) {
 		addr2   = crypto.PubkeyToAddress(key2.PublicKey)
 		addr3   = crypto.PubkeyToAddress(key3.PublicKey)
 		db, _   = ethdb.NewMemDatabase()
-		signer  = types.NewEIP155Signer(big.NewInt(1))
-	)
-	genesis := WriteGenesisBlockForTesting(db,
-		GenesisAccount{addr1, big.NewInt(1000000)},
-		GenesisAccount{addr2, big.NewInt(1000000)},
-		GenesisAccount{addr3, big.NewInt(1000000)},
+		gspec   = &Genesis{
+			Config:   params.TestChainConfig,
+			GasLimit: 3141592,
+			Alloc: GenesisAlloc{
+				addr1: {Balance: big.NewInt(1000000)},
+				addr2: {Balance: big.NewInt(1000000)},
+				addr3: {Balance: big.NewInt(1000000)},
+			},
+		}
+		genesis = gspec.MustCommit(db)
+		signer  = types.NewEIP155Signer(gspec.Config.ChainId)
 	)
+
 	// Create two transactions shared between the chains:
 	//  - postponed: transaction included at a later block in the forked chain
 	//  - swapped: transaction included at the same block number in the forked chain
@@ -892,7 +761,7 @@ func TestChainTxReorgs(t *testing.T) {
 	//  - futureAdd: transaction added after the reorg has already finished
 	var pastAdd, freshAdd, futureAdd *types.Transaction
 
-	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
+	chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
 			pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
@@ -911,13 +780,13 @@ func TestChainTxReorgs(t *testing.T) {
 	})
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
 	if i, err := blockchain.InsertChain(chain); err != nil {
 		t.Fatalf("failed to insert original chain[%d]: %v", i, err)
 	}
 
 	// overwrite the old chain
-	chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
+	chain, _ = GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
 			pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
@@ -969,23 +838,20 @@ func TestChainTxReorgs(t *testing.T) {
 }
 
 func TestLogReorgs(t *testing.T) {
-	params.MinGasLimit = big.NewInt(125000)      // Minimum the gas limit may ever be.
-	params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
 
 	var (
 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		addr1   = crypto.PubkeyToAddress(key1.PublicKey)
 		db, _   = ethdb.NewMemDatabase()
 		// this code generates a log
-		code   = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
-		signer = types.NewEIP155Signer(big.NewInt(1))
-	)
-	genesis := WriteGenesisBlockForTesting(db,
-		GenesisAccount{addr1, big.NewInt(10000000000000)},
+		code    = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
+		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
+		genesis = gspec.MustCommit(db)
+		signer  = types.NewEIP155Signer(gspec.Config.ChainId)
 	)
 
-	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
+	var evmux event.TypeMux
+	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &evmux, vm.Config{})
 
 	subs := evmux.Subscribe(RemovedLogsEvent{})
 	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
@@ -1017,19 +883,20 @@ func TestReorgSideEvent(t *testing.T) {
 		db, _   = ethdb.NewMemDatabase()
 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		addr1   = crypto.PubkeyToAddress(key1.PublicKey)
-		genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
-		signer  = types.NewEIP155Signer(big.NewInt(1))
+		gspec   = testGenesis(addr1, big.NewInt(10000000000000))
+		genesis = gspec.MustCommit(db)
+		signer  = types.NewEIP155Signer(gspec.Config.ChainId)
 	)
 
 	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
 
-	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
+	chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {})
 	if _, err := blockchain.InsertChain(chain); err != nil {
 		t.Fatalf("failed to insert chain: %v", err)
 	}
 
-	replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
+	replacementBlocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, gen *BlockGen) {
 		tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
 		if i == 2 {
 			gen.OffsetTime(-1)
@@ -1092,28 +959,21 @@ done:
 
 // Tests if the canonical block can be fetched from the database during chain insertion.
 func TestCanonicalBlockRetrieval(t *testing.T) {
-	var (
-		db, _   = ethdb.NewMemDatabase()
-		genesis = WriteGenesisBlockForTesting(db)
-	)
-
-	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
-
-	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
+	bc := newTestBlockChain()
+	chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})
 
 	for i := range chain {
 		go func(block *types.Block) {
 			// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
 			for {
-				ch := GetCanonicalHash(db, block.NumberU64())
+				ch := GetCanonicalHash(bc.chainDb, block.NumberU64())
 				if ch == (common.Hash{}) {
 					continue // busy wait for canonical hash to be written
 				}
 				if ch != block.Hash() {
 					t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
 				}
-				fb := GetBlock(db, ch, block.NumberU64())
+				fb := GetBlock(bc.chainDb, ch, block.NumberU64())
 				if fb == nil {
 					t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
 				}
@@ -1124,7 +984,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
 			}
 		}(chain[i])
 
-		blockchain.InsertChain(types.Blocks{chain[i]})
+		bc.InsertChain(types.Blocks{chain[i]})
 	}
 }
 
@@ -1136,13 +996,16 @@ func TestEIP155Transition(t *testing.T) {
 		address    = crypto.PubkeyToAddress(key.PublicKey)
 		funds      = big.NewInt(1000000000)
 		deleteAddr = common.Address{1}
-		genesis    = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds}, GenesisAccount{deleteAddr, new(big.Int)})
-		config     = &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
-		mux        event.TypeMux
+		gspec      = &Genesis{
+			Config: &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
+			Alloc:  GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
+		}
+		genesis = gspec.MustCommit(db)
+		mux     event.TypeMux
 	)
 
-	blockchain, _ := NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{})
-	blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) {
+	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
+	blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) {
 		var (
 			tx      *types.Transaction
 			err     error
@@ -1164,7 +1027,7 @@ func TestEIP155Transition(t *testing.T) {
 			}
 			block.AddTx(tx)
 
-			tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
+			tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -1176,7 +1039,7 @@ func TestEIP155Transition(t *testing.T) {
 			}
 			block.AddTx(tx)
 
-			tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
+			tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -1204,7 +1067,7 @@ func TestEIP155Transition(t *testing.T) {
 	}
 
 	// generate an invalid chain id transaction
-	config = &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
+	config := &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
 	blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
 		var (
 			tx      *types.Transaction
@@ -1236,22 +1099,24 @@ func TestEIP161AccountRemoval(t *testing.T) {
 		address = crypto.PubkeyToAddress(key.PublicKey)
 		funds   = big.NewInt(1000000000)
 		theAddr = common.Address{1}
-		genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds})
-		config  = &params.ChainConfig{
-			ChainId:        big.NewInt(1),
-			HomesteadBlock: new(big.Int),
-			EIP155Block:    new(big.Int),
-			EIP158Block:    big.NewInt(2),
-		}
-		mux event.TypeMux
-
-		blockchain, _ = NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{})
+		gspec   = &Genesis{
+			Config: &params.ChainConfig{
+				ChainId:        big.NewInt(1),
+				HomesteadBlock: new(big.Int),
+				EIP155Block:    new(big.Int),
+				EIP158Block:    big.NewInt(2),
+			},
+			Alloc: GenesisAlloc{address: {Balance: funds}},
+		}
+		genesis       = gspec.MustCommit(db)
+		mux           event.TypeMux
+		blockchain, _ = NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
 	)
-	blocks, _ := GenerateChain(config, genesis, db, 3, func(i int, block *BlockGen) {
+	blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) {
 		var (
 			tx     *types.Transaction
 			err    error
-			signer = types.NewEIP155Signer(config.ChainId)
+			signer = types.NewEIP155Signer(gspec.Config.ChainId)
 		)
 		switch i {
 		case 0:
@@ -1279,7 +1144,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
 		t.Fatal(err)
 	}
 	if blockchain.stateCache.Exist(theAddr) {
-		t.Error("account should not expect")
+		t.Error("account should not exist")
 	}
 
 	// account musn't be created post eip 161
@@ -1287,6 +1152,6 @@ func TestEIP161AccountRemoval(t *testing.T) {
 		t.Fatal(err)
 	}
 	if blockchain.stateCache.Exist(theAddr) {
-		t.Error("account should not expect")
+		t.Error("account should not exist")
 	}
 }

+ 9 - 25
core/chain_makers.go

@@ -30,19 +30,6 @@ import (
 	"github.com/ethereum/go-ethereum/pow"
 )
 
-/*
- * TODO: move this to another package.
- */
-
-// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
-func MakeChainConfig() *params.ChainConfig {
-	return &params.ChainConfig{
-		HomesteadBlock: big.NewInt(0),
-		DAOForkBlock:   nil,
-		DAOForkSupport: true,
-	}
-}
-
 // So we can deterministically seed different blockchains
 var (
 	canonicalSeed = 1
@@ -154,7 +141,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
 	if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
 		panic("block time out of range")
 	}
-	b.header.Difficulty = CalcDifficulty(MakeChainConfig(), b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
+	b.header.Difficulty = CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
 }
 
 // GenerateChain creates a chain of n blocks. The first block's
@@ -170,14 +157,13 @@ func (b *BlockGen) OffsetTime(seconds int64) {
 // values. Inserting them into BlockChain requires use of FakePow or
 // a similar non-validating proof of work implementation.
 func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
+	if config == nil {
+		config = params.TestChainConfig
+	}
 	blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
 	genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
 		b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
-
 		// Mutate the state and block according to any hard-fork specs
-		if config == nil {
-			config = MakeChainConfig()
-		}
 		if daoBlock := config.DAOForkBlock; daoBlock != nil {
 			limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
 			if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 {
@@ -226,7 +212,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
 		Root:       state.IntermediateRoot(config.IsEIP158(parent.Number())),
 		ParentHash: parent.Hash(),
 		Coinbase:   parent.Coinbase(),
-		Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
+		Difficulty: CalcDifficulty(config, time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
 		GasLimit:   CalcGasLimit(parent),
 		GasUsed:    new(big.Int),
 		Number:     new(big.Int).Add(parent.Number(), common.Big1),
@@ -238,14 +224,12 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
 // chain. Depending on the full flag, if creates either a full block chain or a
 // header only chain.
 func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
-	// Create the new chain database
-	db, _ := ethdb.NewMemDatabase()
-	evmux := &event.TypeMux{}
-
 	// Initialize a fresh chain with only a genesis block
-	genesis, _ := WriteTestNetGenesisBlock(db)
+	gspec := new(Genesis)
+	db, _ := ethdb.NewMemDatabase()
+	genesis := gspec.MustCommit(db)
 
-	blockchain, _ := NewBlockChain(db, MakeChainConfig(), pow.FakePow{}, evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 	// Create and inject the requested chain
 	if n == 0 {
 		return db, blockchain, nil

+ 8 - 10
core/chain_makers_test.go

@@ -30,9 +30,6 @@ import (
 )
 
 func ExampleGenerateChain() {
-	params.MinGasLimit = big.NewInt(125000)      // Minimum the gas limit may ever be.
-	params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
-
 	var (
 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
@@ -41,19 +38,20 @@ func ExampleGenerateChain() {
 		addr2   = crypto.PubkeyToAddress(key2.PublicKey)
 		addr3   = crypto.PubkeyToAddress(key3.PublicKey)
 		db, _   = ethdb.NewMemDatabase()
-		signer  = types.HomesteadSigner{}
 	)
 
-	chainConfig := &params.ChainConfig{
-		HomesteadBlock: new(big.Int),
-	}
 	// Ensure that key1 has some funds in the genesis block.
-	genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
+	gspec := &Genesis{
+		Config: &params.ChainConfig{HomesteadBlock: new(big.Int)},
+		Alloc:  GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
+	}
+	genesis := gspec.MustCommit(db)
 
 	// This call generates a chain of 5 blocks. The function runs for
 	// each block and adds different features to gen based on the
 	// block index.
-	chain, _ := GenerateChain(chainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
+	signer := types.HomesteadSigner{}
+	chain, _ := GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
 			// In block 1, addr1 sends addr2 some ether.
@@ -83,7 +81,7 @@ func ExampleGenerateChain() {
 
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, chainConfig, pow.FakePow{}, evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
 	if i, err := blockchain.InsertChain(chain); err != nil {
 		fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
 		return

+ 1 - 1
core/dao.go

@@ -67,7 +67,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
 	}
 
 	// Move every DAO account and extra-balance account funds into the refund contract
-	for _, addr := range params.DAODrainList {
+	for _, addr := range params.DAODrainList() {
 		statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
 		statedb.SetBalance(addr, new(big.Int))
 	}

+ 8 - 7
core/dao_test.go

@@ -34,17 +34,18 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 
 	// Generate a common prefix for both pro-forkers and non-forkers
 	db, _ := ethdb.NewMemDatabase()
-	genesis := WriteGenesisBlockForTesting(db)
+	gspec := new(Genesis)
+	genesis := gspec.MustCommit(db)
 	prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
 
 	// Create the concurrent, conflicting two nodes
 	proDb, _ := ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(proDb)
+	gspec.MustCommit(proDb)
 	proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
 	proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
 
 	conDb, _ := ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(conDb)
+	gspec.MustCommit(conDb)
 	conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
 	conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
 
@@ -58,7 +59,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
 		// Create a pro-fork block, and try to feed into the no-fork chain
 		db, _ = ethdb.NewMemDatabase()
-		WriteGenesisBlockForTesting(db)
+		gspec.MustCommit(db)
 		bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
 
 		blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
@@ -79,7 +80,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 		}
 		// Create a no-fork block, and try to feed into the pro-fork chain
 		db, _ = ethdb.NewMemDatabase()
-		WriteGenesisBlockForTesting(db)
+		gspec.MustCommit(db)
 		bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
 
 		blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
@@ -101,7 +102,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	}
 	// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
 	db, _ = ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(db)
+	gspec.MustCommit(db)
 	bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
 
 	blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
@@ -117,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	}
 	// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
 	db, _ = ethdb.NewMemDatabase()
-	WriteGenesisBlockForTesting(db)
+	gspec.MustCommit(db)
 	bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
 
 	blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))

+ 1 - 1
core/database_util_test.go

@@ -562,7 +562,7 @@ func TestMipmapChain(t *testing.T) {
 	)
 	defer db.Close()
 
-	genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
+	genesis := testGenesis(addr, big.NewInt(1000000)).MustCommit(db)
 	chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
 		var receipts types.Receipts
 		switch i {

File diff suppressed because it is too large
+ 0 - 20
core/default_genesis.go


+ 106 - 0
core/gen_genesis.go

@@ -0,0 +1,106 @@
+// generated by github.com/fjl/gencodec, do not edit.
+
+package core
+
+import (
+	"encoding/json"
+	"errors"
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/params"
+)
+
+func (g *Genesis) MarshalJSON() ([]byte, error) {
+	type GenesisJSON struct {
+		ChainConfig *params.ChainConfig                         `json:"config" optional:"true"`
+		Nonce       *math.HexOrDecimal64                        `json:"nonce" optional:"true"`
+		Timestamp   *math.HexOrDecimal64                        `json:"timestamp" optional:"true"`
+		ParentHash  *common.Hash                                `json:"parentHash" optional:"true"`
+		ExtraData   hexutil.Bytes                               `json:"extraData" optional:"true"`
+		GasLimit    *math.HexOrDecimal64                        `json:"gasLimit"`
+		Difficulty  *math.HexOrDecimal256                       `json:"difficulty"`
+		Mixhash     *common.Hash                                `json:"mixHash" optional:"true"`
+		Coinbase    *common.Address                             `json:"coinbase" optional:"true"`
+		Alloc       map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
+	}
+	var enc GenesisJSON
+	enc.ChainConfig = g.Config
+	enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
+	enc.Timestamp = (*math.HexOrDecimal64)(&g.Timestamp)
+	enc.ParentHash = &g.ParentHash
+	if g.ExtraData != nil {
+		enc.ExtraData = g.ExtraData
+	}
+	enc.GasLimit = (*math.HexOrDecimal64)(&g.GasLimit)
+	enc.Difficulty = (*math.HexOrDecimal256)(g.Difficulty)
+	enc.Mixhash = &g.Mixhash
+	enc.Coinbase = &g.Coinbase
+	if g.Alloc != nil {
+		enc.Alloc = make(map[common.UnprefixedAddress]GenesisAccount, len(g.Alloc))
+		for k, v := range g.Alloc {
+			enc.Alloc[common.UnprefixedAddress(k)] = v
+		}
+	}
+	return json.Marshal(&enc)
+}
+
+func (g *Genesis) UnmarshalJSON(input []byte) error {
+	type GenesisJSON struct {
+		ChainConfig *params.ChainConfig                         `json:"config" optional:"true"`
+		Nonce       *math.HexOrDecimal64                        `json:"nonce" optional:"true"`
+		Timestamp   *math.HexOrDecimal64                        `json:"timestamp" optional:"true"`
+		ParentHash  *common.Hash                                `json:"parentHash" optional:"true"`
+		ExtraData   hexutil.Bytes                               `json:"extraData" optional:"true"`
+		GasLimit    *math.HexOrDecimal64                        `json:"gasLimit"`
+		Difficulty  *math.HexOrDecimal256                       `json:"difficulty"`
+		Mixhash     *common.Hash                                `json:"mixHash" optional:"true"`
+		Coinbase    *common.Address                             `json:"coinbase" optional:"true"`
+		Alloc       map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
+	}
+	var dec GenesisJSON
+	if err := json.Unmarshal(input, &dec); err != nil {
+		return err
+	}
+	var x Genesis
+	if dec.ChainConfig != nil {
+		x.Config = dec.ChainConfig
+	}
+	if dec.Nonce != nil {
+		x.Nonce = uint64(*dec.Nonce)
+	}
+	if dec.Timestamp != nil {
+		x.Timestamp = uint64(*dec.Timestamp)
+	}
+	if dec.ParentHash != nil {
+		x.ParentHash = *dec.ParentHash
+	}
+	if dec.ExtraData != nil {
+		x.ExtraData = dec.ExtraData
+	}
+	if dec.GasLimit == nil {
+		return errors.New("missing required field 'gasLimit' for Genesis")
+	}
+	x.GasLimit = uint64(*dec.GasLimit)
+	if dec.Difficulty == nil {
+		return errors.New("missing required field 'difficulty' for Genesis")
+	}
+	x.Difficulty = (*big.Int)(dec.Difficulty)
+	if dec.Mixhash != nil {
+		x.Mixhash = *dec.Mixhash
+	}
+	if dec.Coinbase != nil {
+		x.Coinbase = *dec.Coinbase
+	}
+	if dec.Alloc == nil {
+		return errors.New("missing required field 'alloc' for Genesis")
+	}
+	x.Alloc = make(GenesisAlloc, len(dec.Alloc))
+	for k, v := range dec.Alloc {
+		x.Alloc[common.Address(k)] = v
+	}
+	*g = x
+	return nil
+}

+ 61 - 0
core/gen_genesis_account.go

@@ -0,0 +1,61 @@
+// generated by github.com/fjl/gencodec, do not edit.
+
+package core
+
+import (
+	"encoding/json"
+	"errors"
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/ethereum/go-ethereum/common/math"
+)
+
+func (g *GenesisAccount) MarshalJSON() ([]byte, error) {
+	type GenesisAccountJSON struct {
+		Code    hexutil.Bytes               `json:"code" optional:"true"`
+		Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
+		Balance *math.HexOrDecimal256       `json:"balance"`
+		Nonce   *math.HexOrDecimal64        `json:"nonce" optional:"true"`
+	}
+	var enc GenesisAccountJSON
+	if g.Code != nil {
+		enc.Code = g.Code
+	}
+	if g.Storage != nil {
+		enc.Storage = g.Storage
+	}
+	enc.Balance = (*math.HexOrDecimal256)(g.Balance)
+	enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
+	return json.Marshal(&enc)
+}
+
+func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
+	type GenesisAccountJSON struct {
+		Code    hexutil.Bytes               `json:"code" optional:"true"`
+		Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
+		Balance *math.HexOrDecimal256       `json:"balance"`
+		Nonce   *math.HexOrDecimal64        `json:"nonce" optional:"true"`
+	}
+	var dec GenesisAccountJSON
+	if err := json.Unmarshal(input, &dec); err != nil {
+		return err
+	}
+	var x GenesisAccount
+	if dec.Code != nil {
+		x.Code = dec.Code
+	}
+	if dec.Storage != nil {
+		x.Storage = dec.Storage
+	}
+	if dec.Balance == nil {
+		return errors.New("missing required field 'balance' for GenesisAccount")
+	}
+	x.Balance = (*big.Int)(dec.Balance)
+	if dec.Nonce != nil {
+		x.Nonce = uint64(*dec.Nonce)
+	}
+	*g = x
+	return nil
+}

+ 217 - 161
core/genesis.go

@@ -17,230 +17,286 @@
 package core
 
 import (
-	"compress/bzip2"
-	"compress/gzip"
-	"encoding/base64"
-	"encoding/json"
+	"errors"
 	"fmt"
-	"io"
-	"io/ioutil"
 	"math/big"
 	"strings"
 
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
+	"github.com/ethereum/go-ethereum/rlp"
 )
 
-// WriteGenesisBlock writes the genesis block to the database as block number 0
-func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) {
-	contents, err := ioutil.ReadAll(reader)
-	if err != nil {
-		return nil, err
-	}
+//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
+//go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
 
-	var genesis struct {
-		ChainConfig *params.ChainConfig `json:"config"`
-		Nonce       string
-		Timestamp   string
-		ParentHash  string
-		ExtraData   string
-		GasLimit    string
-		Difficulty  string
-		Mixhash     string
-		Coinbase    string
-		Alloc       map[string]struct {
-			Code    string
-			Storage map[string]string
-			Balance string
-			Nonce   string
-		}
-	}
+var errGenesisNoConfig = errors.New("genesis has no chain configuration")
 
-	if err := json.Unmarshal(contents, &genesis); err != nil {
-		return nil, err
-	}
-	if genesis.ChainConfig == nil {
-		genesis.ChainConfig = params.AllProtocolChanges
+// Genesis specifies the header fields, state of a genesis block. It also defines hard
+// fork switch-over blocks through the chain configuration.
+type Genesis struct {
+	Config     *params.ChainConfig `json:"config" optional:"true"`
+	Nonce      uint64              `json:"nonce" optional:"true"`
+	Timestamp  uint64              `json:"timestamp" optional:"true"`
+	ParentHash common.Hash         `json:"parentHash" optional:"true"`
+	ExtraData  []byte              `json:"extraData" optional:"true"`
+	GasLimit   uint64              `json:"gasLimit"`
+	Difficulty *big.Int            `json:"difficulty"`
+	Mixhash    common.Hash         `json:"mixHash" optional:"true"`
+	Coinbase   common.Address      `json:"coinbase" optional:"true"`
+	Alloc      GenesisAlloc        `json:"alloc"`
+}
+
+// GenesisAlloc specifies the initial state that is part of the genesis block.
+type GenesisAlloc map[common.Address]GenesisAccount
+
+// GenesisAccount is an account in the state of the genesis block.
+type GenesisAccount struct {
+	Code    []byte                      `json:"code" optional:"true"`
+	Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
+	Balance *big.Int                    `json:"balance"`
+	Nonce   uint64                      `json:"nonce" optional:"true"`
+}
+
+// field type overrides for gencodec
+type genesisSpecMarshaling struct {
+	Nonce      math.HexOrDecimal64
+	Timestamp  math.HexOrDecimal64
+	ExtraData  hexutil.Bytes
+	GasLimit   math.HexOrDecimal64
+	Difficulty *math.HexOrDecimal256
+	Alloc      map[common.UnprefixedAddress]GenesisAccount
+}
+type genesisAccountMarshaling struct {
+	Code    hexutil.Bytes
+	Balance *math.HexOrDecimal256
+	Nonce   math.HexOrDecimal64
+}
+
+// GenesisMismatchError is raised when trying to overwrite an existing
+// genesis block with an incompatible one.
+type GenesisMismatchError struct {
+	Stored, New common.Hash
+}
+
+func (e *GenesisMismatchError) Error() string {
+	return fmt.Sprintf("wrong genesis block in database (have %x, new %x)", e.Stored[:8], e.New[:8])
+}
+
+// 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.AllProtocolChanges, common.Hash{}, errGenesisNoConfig
 	}
 
-	// creating with empty hash always works
-	statedb, _ := state.New(common.Hash{}, chainDb)
-	for addr, account := range genesis.Alloc {
-		balance, ok := math.ParseBig256(account.Balance)
-		if !ok {
-			return nil, fmt.Errorf("invalid balance for account %s: %q", addr, account.Balance)
-		}
-		nonce, ok := math.ParseUint64(account.Nonce)
-		if !ok {
-			return nil, fmt.Errorf("invalid nonce for account %s: %q", addr, account.Nonce)
+	// Just commit the new block if there is no stored genesis block.
+	stored := GetCanonicalHash(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)
+		return genesis.Config, block.Hash(), err
+	}
 
-		address := common.HexToAddress(addr)
-		statedb.AddBalance(address, balance)
-		statedb.SetCode(address, common.FromHex(account.Code))
-		statedb.SetNonce(address, nonce)
-		for key, value := range account.Storage {
-			statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
+	// Check whether the genesis block is already written.
+	if genesis != nil {
+		block, _ := genesis.ToBlock()
+		hash := block.Hash()
+		if hash != stored {
+			return genesis.Config, block.Hash(), &GenesisMismatchError{stored, hash}
 		}
 	}
-	root, stateBatch := statedb.CommitBatch(false)
 
-	difficulty, ok := math.ParseBig256(genesis.Difficulty)
-	if !ok {
-		return nil, fmt.Errorf("invalid difficulty: %q", genesis.Difficulty)
+	// Get the existing chain configuration.
+	newcfg := genesis.configOrDefault(stored)
+	storedcfg, err := GetChainConfig(db, stored)
+	if err != nil {
+		if err == ChainConfigNotFoundErr {
+			// This case happens if a genesis write was interrupted.
+			log.Warn("Found genesis block without chain config")
+			err = WriteChainConfig(db, stored, newcfg)
+		}
+		return newcfg, stored, err
 	}
-	gaslimit, ok := math.ParseUint64(genesis.GasLimit)
-	if !ok {
-		return nil, fmt.Errorf("invalid gas limit: %q", genesis.GasLimit)
+	// 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
 	}
-	nonce, ok := math.ParseUint64(genesis.Nonce)
-	if !ok {
-		return nil, fmt.Errorf("invalid nonce: %q", genesis.Nonce)
+
+	// Check config compatibility and write the config. Compatibility errors
+	// are returned to the caller unless we're already at block zero.
+	height := GetBlockNumber(db, GetHeadHeaderHash(db))
+	if height == missingNumber {
+		return newcfg, stored, fmt.Errorf("missing block number for head header hash")
 	}
-	timestamp, ok := math.ParseBig256(genesis.Timestamp)
-	if !ok {
-		return nil, fmt.Errorf("invalid timestamp: %q", genesis.Timestamp)
+	compatErr := storedcfg.CheckCompatible(newcfg, height)
+	if compatErr != nil && height != 0 && compatErr.RewindTo != 0 {
+		return newcfg, stored, compatErr
 	}
+	return newcfg, stored, WriteChainConfig(db, stored, newcfg)
+}
 
-	block := types.NewBlock(&types.Header{
-		Nonce:      types.EncodeNonce(nonce),
-		Time:       timestamp,
-		ParentHash: common.HexToHash(genesis.ParentHash),
-		Extra:      common.FromHex(genesis.ExtraData),
-		GasLimit:   new(big.Int).SetUint64(gaslimit),
-		Difficulty: difficulty,
-		MixDigest:  common.HexToHash(genesis.Mixhash),
-		Coinbase:   common.HexToAddress(genesis.Coinbase),
-		Root:       root,
-	}, nil, nil, nil)
+func (g *Genesis) configOrDefault(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.AllProtocolChanges
+	}
+}
 
-	if block := GetBlock(chainDb, block.Hash(), block.NumberU64()); block != nil {
-		log.Info("Genesis block known, writing canonical number")
-		err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
-		if err != nil {
-			return nil, err
+// ToBlock creates the block and state of a genesis specification.
+func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) {
+	db, _ := ethdb.NewMemDatabase()
+	statedb, _ := state.New(common.Hash{}, db)
+	for addr, account := range g.Alloc {
+		statedb.AddBalance(addr, account.Balance)
+		statedb.SetCode(addr, account.Code)
+		statedb.SetNonce(addr, account.Nonce)
+		for key, value := range account.Storage {
+			statedb.SetState(addr, key, value)
 		}
-		return block, nil
 	}
+	root := statedb.IntermediateRoot(false)
+	head := &types.Header{
+		Nonce:      types.EncodeNonce(g.Nonce),
+		Time:       new(big.Int).SetUint64(g.Timestamp),
+		ParentHash: g.ParentHash,
+		Extra:      g.ExtraData,
+		GasLimit:   new(big.Int).SetUint64(g.GasLimit),
+		Difficulty: g.Difficulty,
+		MixDigest:  g.Mixhash,
+		Coinbase:   g.Coinbase,
+		Root:       root,
+	}
+	if g.GasLimit == 0 {
+		head.GasLimit = params.GenesisGasLimit
+	}
+	if g.Difficulty == nil {
+		head.Difficulty = params.GenesisDifficulty
+	}
+	return types.NewBlock(head, nil, nil, nil), statedb
+}
 
-	if err := stateBatch.Write(); err != nil {
+// Commit writes the block and state of a genesis specification to the database.
+// The block is committed as the canonical head block.
+func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
+	block, statedb := g.ToBlock()
+	if _, err := statedb.CommitTo(db, false); err != nil {
 		return nil, fmt.Errorf("cannot write state: %v", err)
 	}
-	if err := WriteTd(chainDb, block.Hash(), block.NumberU64(), difficulty); err != nil {
+	if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil {
 		return nil, err
 	}
-	if err := WriteBlock(chainDb, block); err != nil {
+	if err := WriteBlock(db, block); err != nil {
 		return nil, err
 	}
-	if err := WriteBlockReceipts(chainDb, block.Hash(), block.NumberU64(), nil); err != nil {
+	if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), nil); err != nil {
 		return nil, err
 	}
-	if err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()); err != nil {
+	if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil {
 		return nil, err
 	}
-	if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil {
+	if err := WriteHeadBlockHash(db, block.Hash()); err != nil {
 		return nil, err
 	}
-	if err := WriteChainConfig(chainDb, block.Hash(), genesis.ChainConfig); err != nil {
+	if err := WriteHeadHeaderHash(db, block.Hash()); err != nil {
 		return nil, err
 	}
-	return block, nil
-}
-
-// GenesisBlockForTesting creates a block in which addr has the given wei balance.
-// The state trie of the block is written to db. the passed db needs to contain a state root
-func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
-	statedb, _ := state.New(common.Hash{}, db)
-	obj := statedb.GetOrNewStateObject(addr)
-	obj.SetBalance(balance)
-	root, err := statedb.Commit(false)
-	if err != nil {
-		panic(fmt.Sprintf("cannot write state: %v", err))
+	config := g.Config
+	if config == nil {
+		config = params.AllProtocolChanges
 	}
-	block := types.NewBlock(&types.Header{
-		Difficulty: params.GenesisDifficulty,
-		GasLimit:   params.GenesisGasLimit,
-		Root:       root,
-	}, nil, nil, nil)
-	return block
+	return block, WriteChainConfig(db, block.Hash(), config)
 }
 
-type GenesisAccount struct {
-	Address common.Address
-	Balance *big.Int
-}
-
-func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) *types.Block {
-	accountJson := "{"
-	for i, account := range accounts {
-		if i != 0 {
-			accountJson += ","
-		}
-		accountJson += fmt.Sprintf(`"0x%x":{"balance":"%d"}`, account.Address, account.Balance)
-	}
-	accountJson += "}"
-
-	testGenesis := fmt.Sprintf(`{
-	"nonce":"0x%x",
-	"gasLimit":"0x%x",
-	"difficulty":"0x%x",
-	"alloc": %s
-}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), accountJson)
-	block, err := WriteGenesisBlock(db, strings.NewReader(testGenesis))
+// MustCommit writes the genesis block and state to db, panicking on error.
+// The block is committed as the canonical head block.
+func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
+	block, err := g.Commit(db)
 	if err != nil {
 		panic(err)
 	}
 	return block
 }
 
-// WriteDefaultGenesisBlock assembles the official Ethereum genesis block and
-// writes it - along with all associated state - into a chain database.
-func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
-	return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
+// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
+func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
+	g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
+	return g.MustCommit(db)
 }
 
-// WriteTestNetGenesisBlock assembles the test network genesis block and
-// writes it - along with all associated state - into a chain database.
-func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
-	return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock()))
+// 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),
+	}
 }
 
-// DefaultGenesisBlock assembles a JSON string representing the default Ethereum
-// genesis block.
-func DefaultGenesisBlock() string {
-	reader, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock)))
-	if err != nil {
-		panic(fmt.Sprintf("failed to access default genesis: %v", err))
-	}
-	blob, err := ioutil.ReadAll(reader)
-	if err != nil {
-		panic(fmt.Sprintf("failed to load default genesis: %v", err))
+// 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),
 	}
-	return string(blob)
 }
 
-// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum
-// test network genesis block.
-func DefaultTestnetGenesisBlock() string {
-	reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
-	blob, err := ioutil.ReadAll(reader)
-	if err != nil {
-		panic(fmt.Sprintf("failed to load default genesis: %v", err))
+// DevGenesisBlock returns the 'geth --dev' genesis block.
+func DevGenesisBlock() *Genesis {
+	return &Genesis{
+		Config:     params.AllProtocolChanges,
+		Nonce:      42,
+		GasLimit:   4712388,
+		Difficulty: big.NewInt(131072),
+		Alloc:      decodePrealloc(devAllocData),
 	}
-	return string(blob)
 }
 
-// DevGenesisBlock assembles a JSON string representing a local dev genesis block.
-func DevGenesisBlock() string {
-	reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock)))
-	blob, err := ioutil.ReadAll(reader)
-	if err != nil {
-		panic(fmt.Sprintf("failed to load dev genesis: %v", err))
+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 string(blob)
+	return ga
 }

File diff suppressed because it is too large
+ 22 - 0
core/genesis_alloc.go


+ 161 - 0
core/genesis_test.go

@@ -0,0 +1,161 @@
+// Copyright 2017 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 (
+	"math/big"
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/vm"
+	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/params"
+	"github.com/ethereum/go-ethereum/pow"
+)
+
+func TestDefaultGenesisBlock(t *testing.T) {
+	block, _ := DefaultGenesisBlock().ToBlock()
+	if block.Hash() != params.MainNetGenesisHash {
+		t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainNetGenesisHash)
+	}
+	block, _ = DefaultTestnetGenesisBlock().ToBlock()
+	if block.Hash() != params.TestNetGenesisHash {
+		t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestNetGenesisHash)
+	}
+}
+
+func TestSetupGenesis(t *testing.T) {
+	var (
+		customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
+		customg     = Genesis{
+			Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
+			Alloc: GenesisAlloc{
+				{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
+			},
+		}
+		oldcustomg = customg
+	)
+	oldcustomg.Config = &params.ChainConfig{HomesteadBlock: big.NewInt(2)}
+	tests := []struct {
+		name       string
+		fn         func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
+		wantConfig *params.ChainConfig
+		wantHash   common.Hash
+		wantErr    error
+	}{
+		{
+			name: "genesis without ChainConfig",
+			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+				return SetupGenesisBlock(db, new(Genesis))
+			},
+			wantErr:    errGenesisNoConfig,
+			wantConfig: params.AllProtocolChanges,
+		},
+		{
+			name: "no block in DB, genesis == nil",
+			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+				return SetupGenesisBlock(db, nil)
+			},
+			wantHash:   params.MainNetGenesisHash,
+			wantConfig: params.MainnetChainConfig,
+		},
+		{
+			name: "mainnet block in DB, genesis == nil",
+			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+				DefaultGenesisBlock().MustCommit(db)
+				return SetupGenesisBlock(db, nil)
+			},
+			wantHash:   params.MainNetGenesisHash,
+			wantConfig: params.MainnetChainConfig,
+		},
+		{
+			name: "custom block in DB, genesis == nil",
+			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+				customg.MustCommit(db)
+				return SetupGenesisBlock(db, nil)
+			},
+			wantHash:   customghash,
+			wantConfig: customg.Config,
+		},
+		{
+			name: "custom block in DB, genesis == testnet",
+			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+				customg.MustCommit(db)
+				return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
+			},
+			wantErr:    &GenesisMismatchError{Stored: customghash, New: params.TestNetGenesisHash},
+			wantHash:   params.TestNetGenesisHash,
+			wantConfig: params.TestnetChainConfig,
+		},
+		{
+			name: "compatible config in DB",
+			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+				oldcustomg.MustCommit(db)
+				return SetupGenesisBlock(db, &customg)
+			},
+			wantHash:   customghash,
+			wantConfig: customg.Config,
+		},
+		{
+			name: "incompatible config in DB",
+			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+				// Commit the 'old' genesis block with Homestead transition at #2.
+				// Advance to block #4, past the homestead transition block of customg.
+				genesis := oldcustomg.MustCommit(db)
+				bc, _ := NewBlockChain(db, oldcustomg.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+				bc.SetValidator(bproc{})
+				bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
+				bc.CurrentBlock()
+				// This should return a compatibility error.
+				return SetupGenesisBlock(db, &customg)
+			},
+			wantHash:   customghash,
+			wantConfig: customg.Config,
+			wantErr: &params.ConfigCompatError{
+				What:         "Homestead fork block",
+				StoredConfig: big.NewInt(2),
+				NewConfig:    big.NewInt(3),
+				RewindTo:     1,
+			},
+		},
+	}
+
+	for _, test := range tests {
+		db, _ := ethdb.NewMemDatabase()
+		config, hash, err := test.fn(db)
+		// Check the return values.
+		if !reflect.DeepEqual(err, test.wantErr) {
+			spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
+			t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
+		}
+		if !reflect.DeepEqual(config, test.wantConfig) {
+			t.Errorf("%s:\nreturned %v\nwant     %v", test.name, config, test.wantConfig)
+		}
+		if hash != test.wantHash {
+			t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
+		} else if err == nil {
+			// Check database content.
+			stored := GetBlock(db, test.wantHash, 0)
+			if stored.Hash() != test.wantHash {
+				t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
+			}
+		}
+	}
+}

+ 1 - 6
core/headerchain.go

@@ -97,12 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid
 
 	hc.genesisHeader = hc.GetHeaderByNumber(0)
 	if hc.genesisHeader == nil {
-		genesisBlock, err := WriteDefaultGenesisBlock(chainDb)
-		if err != nil {
-			return nil, err
-		}
-		log.Warn("Wrote default Ethereum genesis block")
-		hc.genesisHeader = genesisBlock.Header()
+		return nil, ErrNoGenesis
 	}
 
 	hc.currentHeader = hc.genesisHeader

+ 85 - 0
core/mkalloc.go

@@ -0,0 +1,85 @@
+// Copyright 2017 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/>.
+
+// +build none
+
+/*
+
+   The mkalloc tool creates the genesis allocation constants in genesis_alloc.go
+   It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples.
+
+       go run mkalloc.go genesis.json
+
+*/
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"math/big"
+	"os"
+	"sort"
+	"strconv"
+
+	"github.com/ethereum/go-ethereum/core"
+	"github.com/ethereum/go-ethereum/rlp"
+)
+
+type allocItem struct{ Addr, Balance *big.Int }
+
+type allocList []allocItem
+
+func (a allocList) Len() int           { return len(a) }
+func (a allocList) Less(i, j int) bool { return a[i].Addr.Cmp(a[j].Addr) < 0 }
+func (a allocList) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+func makelist(g *core.Genesis) allocList {
+	a := make(allocList, 0, len(g.Alloc))
+	for addr, account := range g.Alloc {
+		if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
+			panic(fmt.Sprintf("can't encode account %x", addr))
+		}
+		a = append(a, allocItem{addr.Big(), account.Balance})
+	}
+	sort.Sort(a)
+	return a
+}
+
+func makealloc(g *core.Genesis) string {
+	a := makelist(g)
+	data, err := rlp.EncodeToBytes(a)
+	if err != nil {
+		panic(err)
+	}
+	return strconv.QuoteToASCII(string(data))
+}
+
+func main() {
+	if len(os.Args) != 2 {
+		fmt.Fprintln(os.Stderr, "Usage: mkalloc genesis.json")
+		os.Exit(1)
+	}
+
+	g := new(core.Genesis)
+	file, err := os.Open(os.Args[1])
+	if err != nil {
+		panic(err)
+	}
+	if err := json.NewDecoder(file).Decode(g); err != nil {
+		panic(err)
+	}
+	fmt.Println("const allocData =", makealloc(g))
+}

+ 5 - 5
core/tx_pool_test.go

@@ -42,7 +42,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
 	statedb, _ := state.New(common.Hash{}, db)
 
 	key, _ := crypto.GenerateKey()
-	newPool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+	newPool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 	newPool.resetState()
 
 	return newPool, key
@@ -91,7 +91,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
 
 	gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
 
-	txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc)
+	txpool := NewTxPool(params.TestChainConfig, mux, stateFunc, gasLimitFunc)
 	txpool.resetState()
 
 	nonce := txpool.State().GetNonce(address)
@@ -564,7 +564,7 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
 	statedb, _ := state.New(common.Hash{}, db)
 
-	pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 	pool.resetState()
 
 	// Create a number of test accounts and fund them
@@ -713,7 +713,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
 	statedb, _ := state.New(common.Hash{}, db)
 
-	pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 	pool.resetState()
 
 	// Create a number of test accounts and fund them
@@ -759,7 +759,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
 	statedb, _ := state.New(common.Hash{}, db)
 
-	pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 	pool.resetState()
 
 	// Create a number of test accounts and fund them

+ 0 - 14
core/types/transaction.go

@@ -27,7 +27,6 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/crypto"
-	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
@@ -119,19 +118,6 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice
 	return &Transaction{data: d}
 }
 
-func pickSigner(rules params.Rules) Signer {
-	var signer Signer
-	switch {
-	case rules.IsEIP155:
-		signer = NewEIP155Signer(rules.ChainId)
-	case rules.IsHomestead:
-		signer = HomesteadSigner{}
-	default:
-		signer = FrontierSigner{}
-	}
-	return signer
-}
-
 // ChainId returns which chain id this transaction was signed for (if at all)
 func (tx *Transaction) ChainId() *big.Int {
 	return deriveChainId(tx.data.V)

+ 25 - 62
eth/backend.go

@@ -18,11 +18,9 @@
 package eth
 
 import (
-	"errors"
 	"fmt"
 	"math/big"
 	"regexp"
-	"strings"
 	"sync"
 	"time"
 
@@ -60,15 +58,17 @@ var (
 )
 
 type Config struct {
-	ChainConfig *params.ChainConfig // chain configuration
+	// The genesis block, which is inserted if the database is empty.
+	// If nil, the Ethereum main net block is used.
+	Genesis *core.Genesis
 
-	NetworkId  int    // Network ID to use for selecting peers to connect to
-	Genesis    string // Genesis JSON to seed the chain database with
-	FastSync   bool   // Enables the state download based fast synchronisation algorithm
-	LightMode  bool   // Running in light client mode
-	LightServ  int    // Maximum percentage of time allowed for serving LES requests
-	LightPeers int    // Maximum number of LES client peers
-	MaxPeers   int    // Maximum number of global peers
+	NetworkId int // Network ID to use for selecting peers to connect to
+
+	FastSync   bool // Enables the state download based fast synchronisation algorithm
+	LightMode  bool // Running in light client mode
+	LightServ  int  // Maximum percentage of time allowed for serving LES requests
+	LightPeers int  // Maximum number of LES client peers
+	MaxPeers   int  // Maximum number of global peers
 
 	SkipBcVersionCheck bool // e.g. blockchain export
 	DatabaseCache      int
@@ -100,9 +100,6 @@ type Config struct {
 	GpobaseCorrectionFactor int
 
 	EnablePreimageRecording bool
-
-	TestGenesisBlock *types.Block   // Genesis block to seed the chain database with (testing only!)
-	TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!)
 }
 
 type LesServer interface {
@@ -155,11 +152,15 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 		return nil, err
 	}
 	stopDbUpgrade := upgradeSequentialKeys(chainDb)
-	if err := SetupGenesisBlock(&chainDb, config); err != nil {
-		return nil, err
+	chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
+	if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
+		return nil, genesisErr
 	}
+	log.Info("Initialised chain configuration", "config", chainConfig)
+
 	eth := &Ethereum{
 		chainDb:        chainDb,
+		chainConfig:    chainConfig,
 		eventMux:       ctx.EventMux,
 		accountManager: ctx.AccountManager,
 		pow:            CreatePoW(ctx, config),
@@ -184,33 +185,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 		core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
 	}
 
-	// load the genesis block or write a new one if no genesis
-	// block is prenent in the database.
-	genesis := core.GetBlock(chainDb, core.GetCanonicalHash(chainDb, 0), 0)
-	if genesis == nil {
-		genesis, err = core.WriteDefaultGenesisBlock(chainDb)
-		if err != nil {
-			return nil, err
-		}
-		log.Warn("Wrote default Ethereum genesis block")
-	}
-
-	if config.ChainConfig == nil {
-		return nil, errors.New("missing chain config")
-	}
-	core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
-
-	eth.chainConfig = config.ChainConfig
-
-	log.Info("Initialised chain configuration", "config", eth.chainConfig)
-
-	eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux(), vm.Config{EnablePreimageRecording: config.EnablePreimageRecording})
+	vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
+	eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.eventMux, vmConfig)
 	if err != nil {
-		if err == core.ErrNoGenesis {
-			return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`)
-		}
 		return nil, err
 	}
+	// Rewind the chain in case of an incompatible config upgrade.
+	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
+		log.Warn("Rewinding chain to upgrade configuration", "err", compat)
+		eth.blockchain.SetHead(compat.RewindTo)
+		core.WriteChainConfig(chainDb, genesisHash, chainConfig)
+	}
+
 	newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
 	eth.txPool = newPool
 
@@ -255,29 +241,6 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data
 	return db, err
 }
 
-// SetupGenesisBlock initializes the genesis block for an Ethereum service
-func SetupGenesisBlock(chainDb *ethdb.Database, config *Config) error {
-	// Load up any custom genesis block if requested
-	if len(config.Genesis) > 0 {
-		block, err := core.WriteGenesisBlock(*chainDb, strings.NewReader(config.Genesis))
-		if err != nil {
-			return err
-		}
-		log.Info("Successfully wrote custom genesis block", "hash", block.Hash())
-	}
-	// Load up a test setup if directly injected
-	if config.TestGenesisState != nil {
-		*chainDb = config.TestGenesisState
-	}
-	if config.TestGenesisBlock != nil {
-		core.WriteTd(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64(), config.TestGenesisBlock.Difficulty())
-		core.WriteBlock(*chainDb, config.TestGenesisBlock)
-		core.WriteCanonicalHash(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64())
-		core.WriteHeadBlockHash(*chainDb, config.TestGenesisBlock.Hash())
-	}
-	return nil
-}
-
 // CreatePoW creates the required type of PoW instance for an Ethereum service
 func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
 	switch {

+ 1 - 1
eth/backend_test.go

@@ -30,7 +30,7 @@ import (
 func TestMipmapUpgrade(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
 	addr := common.BytesToAddress([]byte("jeff"))
-	genesis := core.WriteGenesisBlockForTesting(db)
+	genesis := new(core.Genesis).MustCommit(db)
 
 	chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
 		var receipts types.Receipts

+ 5 - 6
eth/filters/filter_system_test.go

@@ -72,12 +72,11 @@ func TestBlockSubscription(t *testing.T) {
 	t.Parallel()
 
 	var (
-		mux     = new(event.TypeMux)
-		db, _   = ethdb.NewMemDatabase()
-		backend = &testBackend{mux, db}
-		api     = NewPublicFilterAPI(backend, false)
-
-		genesis     = core.WriteGenesisBlockForTesting(db)
+		mux         = new(event.TypeMux)
+		db, _       = ethdb.NewMemDatabase()
+		backend     = &testBackend{mux, db}
+		api         = NewPublicFilterAPI(backend, false)
+		genesis     = new(core.Genesis).MustCommit(db)
 		chain, _    = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
 		chainEvents = []core.ChainEvent{}
 	)

+ 3 - 3
eth/filters/filter_test.go

@@ -60,7 +60,7 @@ func BenchmarkMipmaps(b *testing.B) {
 	)
 	defer db.Close()
 
-	genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
+	genesis := core.GenesisBlockForTesting(db, addr1, big.NewInt(1000000))
 	chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
 		var receipts types.Receipts
 		switch i {
@@ -112,7 +112,7 @@ func BenchmarkMipmaps(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		logs, _ := filter.Find(context.Background())
 		if len(logs) != 4 {
-			b.Fatal("expected 4 log, got", len(logs))
+			b.Fatal("expected 4 logs, got", len(logs))
 		}
 	}
 }
@@ -138,7 +138,7 @@ func TestFilters(t *testing.T) {
 	)
 	defer db.Close()
 
-	genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
+	genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000))
 	chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
 		var receipts types.Receipts
 		switch i {

+ 7 - 6
eth/handler_test.go

@@ -315,12 +315,12 @@ func testGetNodeData(t *testing.T, protocol int) {
 		switch i {
 		case 0:
 			// In block 1, the test bank sends account #1 some ether.
-			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
+			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
 			block.AddTx(tx)
 		case 1:
 			// In block 2, the test bank sends some more ether to account #1.
 			// acc1Addr passes it on to account #2.
-			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
+			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
 			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
 			block.AddTx(tx1)
 			block.AddTx(tx2)
@@ -372,7 +372,7 @@ func testGetNodeData(t *testing.T, protocol int) {
 	for i := 0; i < len(data); i++ {
 		statedb.Put(hashes[i].Bytes(), data[i])
 	}
-	accounts := []common.Address{testBank.Address, acc1Addr, acc2Addr}
+	accounts := []common.Address{testBank, acc1Addr, acc2Addr}
 	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
 		trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb)
 
@@ -407,12 +407,12 @@ func testGetReceipt(t *testing.T, protocol int) {
 		switch i {
 		case 0:
 			// In block 1, the test bank sends account #1 some ether.
-			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
+			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
 			block.AddTx(tx)
 		case 1:
 			// In block 2, the test bank sends some more ether to account #1.
 			// acc1Addr passes it on to account #2.
-			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
+			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
 			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
 			block.AddTx(tx1)
 			block.AddTx(tx2)
@@ -471,8 +471,9 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
 		evmux         = new(event.TypeMux)
 		pow           = new(pow.FakePow)
 		db, _         = ethdb.NewMemDatabase()
-		genesis       = core.WriteGenesisBlockForTesting(db)
 		config        = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
+		gspec         = &core.Genesis{Config: config}
+		genesis       = gspec.MustCommit(db)
 		blockchain, _ = core.NewBlockChain(db, config, pow, evmux, vm.Config{})
 	)
 	pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)

+ 12 - 12
eth/helper_test.go

@@ -42,10 +42,7 @@ import (
 
 var (
 	testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
-	testBank       = core.GenesisAccount{
-		Address: crypto.PubkeyToAddress(testBankKey.PublicKey),
-		Balance: big.NewInt(1000000),
-	}
+	testBank       = crypto.PubkeyToAddress(testBankKey.PublicKey)
 )
 
 // newTestProtocolManager creates a new protocol manager for testing purposes,
@@ -53,19 +50,22 @@ var (
 // channels for different events.
 func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) {
 	var (
-		evmux         = new(event.TypeMux)
-		pow           = new(pow.FakePow)
-		db, _         = ethdb.NewMemDatabase()
-		genesis       = core.WriteGenesisBlockForTesting(db, testBank)
-		chainConfig   = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
-		blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
+		evmux = new(event.TypeMux)
+		pow   = new(pow.FakePow)
+		db, _ = ethdb.NewMemDatabase()
+		gspec = &core.Genesis{
+			Config: params.TestChainConfig,
+			Alloc:  core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
+		}
+		genesis       = gspec.MustCommit(db)
+		blockchain, _ = core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
 	)
-	chain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
+	chain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
 	if _, err := blockchain.InsertChain(chain); err != nil {
 		panic(err)
 	}
 
-	pm, err := NewProtocolManager(chainConfig, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
+	pm, err := NewProtocolManager(gspec.Config, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
 	if err != nil {
 		return nil, err
 	}

+ 12 - 10
les/backend.go

@@ -18,7 +18,6 @@
 package les
 
 import (
-	"errors"
 	"fmt"
 	"time"
 
@@ -74,15 +73,19 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
 	if err != nil {
 		return nil, err
 	}
-	if err := eth.SetupGenesisBlock(&chainDb, config); err != nil {
-		return nil, err
+	chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
+	if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
+		return nil, genesisErr
 	}
+	log.Info("Initialised chain configuration", "config", chainConfig)
+
 	odr := NewLesOdr(chainDb)
 	relay := NewLesTxRelay()
 	eth := &LightEthereum{
 		odr:            odr,
 		relay:          relay,
 		chainDb:        chainDb,
+		chainConfig:    chainConfig,
 		eventMux:       ctx.EventMux,
 		accountManager: ctx.AccountManager,
 		pow:            eth.CreatePoW(ctx, config),
@@ -91,17 +94,16 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
 		solcPath:       config.SolcPath,
 	}
 
-	if config.ChainConfig == nil {
-		return nil, errors.New("missing chain config")
-	}
-	eth.chainConfig = config.ChainConfig
 	eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
 	if err != nil {
-		if err == core.ErrNoGenesis {
-			return nil, fmt.Errorf(`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`)
-		}
 		return nil, err
 	}
+	// Rewind the chain in case of an incompatible config upgrade.
+	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
+		log.Warn("Rewinding chain to upgrade configuration", "err", compat)
+		eth.blockchain.SetHead(compat.RewindTo)
+		core.WriteChainConfig(chainDb, genesisHash, chainConfig)
+	}
 
 	eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay)
 	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.pow, eth.blockchain, nil, chainDb, odr, relay); err != nil {

+ 14 - 11
les/helper_test.go

@@ -134,28 +134,31 @@ func testRCL() RequestCostList {
 // channels for different events.
 func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen)) (*ProtocolManager, ethdb.Database, *LesOdr, error) {
 	var (
-		evmux       = new(event.TypeMux)
-		pow         = new(pow.FakePow)
-		db, _       = ethdb.NewMemDatabase()
-		genesis     = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
-		chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
-		odr         *LesOdr
-		chain       BlockChain
+		evmux = new(event.TypeMux)
+		pow   = new(pow.FakePow)
+		db, _ = ethdb.NewMemDatabase()
+		gspec = core.Genesis{
+			Config: params.TestChainConfig,
+			Alloc:  core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
+		}
+		genesis = gspec.MustCommit(db)
+		odr     *LesOdr
+		chain   BlockChain
 	)
 
 	if lightSync {
 		odr = NewLesOdr(db)
-		chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
+		chain, _ = light.NewLightChain(odr, gspec.Config, pow, evmux)
 	} else {
-		blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
-		gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
+		blockchain, _ := core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
+		gchain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
 		if _, err := blockchain.InsertChain(gchain); err != nil {
 			panic(err)
 		}
 		chain = blockchain
 	}
 
-	pm, err := NewProtocolManager(chainConfig, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
+	pm, err := NewProtocolManager(gspec.Config, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
 	if err != nil {
 		return nil, nil, nil, err
 	}

+ 1 - 1
les/server.go

@@ -45,7 +45,7 @@ type LesServer struct {
 }
 
 func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
-	pm, err := NewProtocolManager(config.ChainConfig, false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
+	pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
 	if err != nil {
 		return nil, err
 	}

+ 1 - 5
light/lightchain.go

@@ -96,11 +96,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
 
 	bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
 	if bc.genesisBlock == nil {
-		bc.genesisBlock, err = core.WriteDefaultGenesisBlock(odr.Database())
-		if err != nil {
-			return nil, err
-		}
-		log.Warn("Wrote default ethereum genesis block")
+		return nil, core.ErrNoGenesis
 	}
 
 	if bc.genesisBlock.Hash() == params.MainNetGenesisHash {

+ 26 - 55
light/lightchain_test.go

@@ -20,7 +20,6 @@ import (
 	"context"
 	"fmt"
 	"math/big"
-	"runtime"
 	"testing"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -30,7 +29,6 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
-	"github.com/hashicorp/golang-lru"
 )
 
 // So we can deterministically seed different blockchains
@@ -59,14 +57,10 @@ func testChainConfig() *params.ChainConfig {
 // chain. Depending on the full flag, if creates either a full block chain or a
 // header only chain.
 func newCanonical(n int) (ethdb.Database, *LightChain, error) {
-	// Create te new chain database
 	db, _ := ethdb.NewMemDatabase()
-	evmux := &event.TypeMux{}
-
-	// Initialize a fresh chain with only a genesis block
-	genesis, _ := core.WriteTestNetGenesisBlock(db)
-
-	blockchain, _ := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, evmux)
+	gspec := core.Genesis{Config: testChainConfig()}
+	genesis := gspec.MustCommit(db)
+	blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
 	// Create and inject the requested chain
 	if n == 0 {
 		return db, blockchain, nil
@@ -77,21 +71,20 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
 	return db, blockchain, err
 }
 
-func init() {
-	runtime.GOMAXPROCS(runtime.NumCPU())
-}
-
-func theLightChain(db ethdb.Database, t *testing.T) *LightChain {
-	var eventMux event.TypeMux
-	core.WriteTestNetGenesisBlock(db)
-	LightChain, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.NewTestEthash(), &eventMux)
+// newTestLightChain creates a LightChain that doesn't validate anything.
+func newTestLightChain() *LightChain {
+	db, _ := ethdb.NewMemDatabase()
+	gspec := &core.Genesis{
+		Difficulty: big.NewInt(1),
+		Config:     testChainConfig(),
+	}
+	gspec.MustCommit(db)
+	lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
 	if err != nil {
-		t.Error("failed creating LightChain:", err)
-		t.FailNow()
-		return nil
+		panic(err)
 	}
-
-	return LightChain
+	lc.SetValidator(bproc{})
+	return lc
 }
 
 // Test fork of length N starting from block i
@@ -302,20 +295,6 @@ func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error {
 	return nil
 }
 
-func chm(genesis *types.Block, db ethdb.Database) *LightChain {
-	odr := &dummyOdr{db: db}
-	var eventMux event.TypeMux
-	bc := &LightChain{odr: odr, chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: pow.FakePow{}}
-	bc.hc, _ = core.NewHeaderChain(db, testChainConfig(), bc.Validator, bc.getProcInterrupt)
-	bc.bodyCache, _ = lru.New(100)
-	bc.bodyRLPCache, _ = lru.New(100)
-	bc.blockCache, _ = lru.New(100)
-	bc.SetValidator(bproc{})
-	bc.ResetWithGenesisBlock(genesis)
-
-	return bc
-}
-
 // Tests that reorganizing a long difficult chain after a short easy one
 // overwrites the canonical numbers and links in the database.
 func TestReorgLongHeaders(t *testing.T) {
@@ -329,14 +308,11 @@ func TestReorgShortHeaders(t *testing.T) {
 }
 
 func testReorg(t *testing.T, first, second []int, td int64) {
-	// Create a pristine block chain
-	db, _ := ethdb.NewMemDatabase()
-	genesis, _ := core.WriteTestNetGenesisBlock(db)
-	bc := chm(genesis, db)
+	bc := newTestLightChain()
 
 	// Insert an easy and a difficult chain afterwards
-	bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
-	bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
+	bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
+	bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
 	// Check that the chain is valid number and link wise
 	prev := bc.CurrentHeader()
 	for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {
@@ -345,7 +321,7 @@ func testReorg(t *testing.T, first, second []int, td int64) {
 		}
 	}
 	// Make sure the chain total difficulty is the correct one
-	want := new(big.Int).Add(genesis.Difficulty(), big.NewInt(td))
+	want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
 	if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 {
 		t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
 	}
@@ -353,14 +329,11 @@ func testReorg(t *testing.T, first, second []int, td int64) {
 
 // Tests that the insertion functions detect banned hashes.
 func TestBadHeaderHashes(t *testing.T) {
-	// Create a pristine block chain
-	db, _ := ethdb.NewMemDatabase()
-	genesis, _ := core.WriteTestNetGenesisBlock(db)
-	bc := chm(genesis, db)
+	bc := newTestLightChain()
 
 	// Create a chain, ban a hash and try to import
 	var err error
-	headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10)
+	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
 	core.BadHashes[headers[2].Hash()] = true
 	_, err = bc.InsertHeaderChain(headers, 1)
 	if !core.IsBadHashError(err) {
@@ -371,13 +344,10 @@ func TestBadHeaderHashes(t *testing.T) {
 // Tests that bad hashes are detected on boot, and the chan rolled back to a
 // good state prior to the bad hash.
 func TestReorgBadHeaderHashes(t *testing.T) {
-	// Create a pristine block chain
-	db, _ := ethdb.NewMemDatabase()
-	genesis, _ := core.WriteTestNetGenesisBlock(db)
-	bc := chm(genesis, db)
+	bc := newTestLightChain()
 
 	// Create a chain, import and ban aferwards
-	headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
+	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
 
 	if _, err := bc.InsertHeaderChain(headers, 1); err != nil {
 		t.Fatalf("failed to import headers: %v", err)
@@ -387,8 +357,9 @@ func TestReorgBadHeaderHashes(t *testing.T) {
 	}
 	core.BadHashes[headers[3].Hash()] = true
 	defer func() { delete(core.BadHashes, headers[3].Hash()) }()
-	// Create a new chain manager and check it rolled back the state
-	ncm, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
+
+	// Create a new LightChain and check that it rolled back the state.
+	ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
 	if err != nil {
 		t.Fatalf("failed to create new chain manager: %v", err)
 	}

+ 3 - 2
light/odr_test.go

@@ -251,9 +251,10 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
 		pow     = new(pow.FakePow)
 		sdb, _  = ethdb.NewMemDatabase()
 		ldb, _  = ethdb.NewMemDatabase()
-		genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+		gspec   = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
+		genesis = gspec.MustCommit(sdb)
 	)
-	core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+	gspec.MustCommit(ldb)
 	// Assemble the test environment
 	blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
 	chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}

+ 3 - 2
light/txpool_test.go

@@ -86,9 +86,10 @@ func TestTxPool(t *testing.T) {
 		pow     = new(pow.FakePow)
 		sdb, _  = ethdb.NewMemDatabase()
 		ldb, _  = ethdb.NewMemDatabase()
-		genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+		gspec   = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
+		genesis = gspec.MustCommit(sdb)
 	)
-	core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+	gspec.MustCommit(ldb)
 	// Assemble the test environment
 	blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
 	chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}

+ 39 - 11
mobile/geth.go

@@ -20,10 +20,12 @@
 package geth
 
 import (
+	"encoding/json"
 	"fmt"
 	"math/big"
 	"path/filepath"
 
+	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/ethclient"
 	"github.com/ethereum/go-ethereum/ethstats"
@@ -92,6 +94,18 @@ func NewNodeConfig() *NodeConfig {
 	return &config
 }
 
+// SetMainnet sets up the node for use on the Ethereum mainnet.
+func (cfg *NodeConfig) SetMainnet() {
+	cfg.EthereumGenesis = ""
+	cfg.EthereumChainConfig = MainnetChainConfig()
+}
+
+// SetTestnet sets up the node for use on the Ethereum testnet.
+func (cfg *NodeConfig) SetTestnet() {
+	cfg.EthereumGenesis = TestnetGenesis()
+	cfg.EthereumChainConfig = TestnetChainConfig()
+}
+
 // Node represents a Geth Ethereum node instance.
 type Node struct {
 	node *node.Node
@@ -127,20 +141,34 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
 	if err != nil {
 		return nil, err
 	}
+
+	var genesis *core.Genesis
+	if config.EthereumGenesis != "" {
+		genesis = new(core.Genesis)
+		if err := json.Unmarshal([]byte(config.EthereumGenesis), genesis); err != nil {
+			return nil, fmt.Errorf("invalid EthereumGenesis: %v", err)
+		}
+	}
+	if config.EthereumChainConfig != nil {
+		if genesis == nil {
+			genesis = core.DefaultGenesisBlock()
+		}
+		genesis.Config = &params.ChainConfig{
+			ChainId:        big.NewInt(config.EthereumChainConfig.ChainID),
+			HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
+			DAOForkBlock:   big.NewInt(config.EthereumChainConfig.DAOForkBlock),
+			DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
+			EIP150Block:    big.NewInt(config.EthereumChainConfig.EIP150Block),
+			EIP150Hash:     config.EthereumChainConfig.EIP150Hash.hash,
+			EIP155Block:    big.NewInt(config.EthereumChainConfig.EIP155Block),
+			EIP158Block:    big.NewInt(config.EthereumChainConfig.EIP158Block),
+		}
+	}
+
 	// Register the Ethereum protocol if requested
 	if config.EthereumEnabled {
 		ethConf := &eth.Config{
-			ChainConfig: &params.ChainConfig{
-				ChainId:        big.NewInt(config.EthereumChainConfig.ChainID),
-				HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
-				DAOForkBlock:   big.NewInt(config.EthereumChainConfig.DAOForkBlock),
-				DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
-				EIP150Block:    big.NewInt(config.EthereumChainConfig.EIP150Block),
-				EIP150Hash:     config.EthereumChainConfig.EIP150Hash.hash,
-				EIP155Block:    big.NewInt(config.EthereumChainConfig.EIP155Block),
-				EIP158Block:    big.NewInt(config.EthereumChainConfig.EIP158Block),
-			},
-			Genesis:                 config.EthereumGenesis,
+			Genesis:                 genesis,
 			LightMode:               true,
 			DatabaseCache:           config.EthereumDatabaseCache,
 			NetworkId:               config.EthereumNetworkID,

+ 7 - 1
mobile/params.go

@@ -19,6 +19,8 @@
 package geth
 
 import (
+	"encoding/json"
+
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/p2p/discv5"
 	"github.com/ethereum/go-ethereum/params"
@@ -60,7 +62,11 @@ func TestnetChainConfig() *ChainConfig {
 
 // TestnetGenesis returns the JSON spec to use for the Ethereum test network.
 func TestnetGenesis() string {
-	return core.DefaultTestnetGenesisBlock()
+	enc, err := json.Marshal(core.DefaultTestnetGenesisBlock())
+	if err != nil {
+		panic(err)
+	}
+	return string(enc)
 }
 
 // ChainConfig is the core config which determines the blockchain settings.

+ 140 - 68
params/config.go

@@ -23,39 +23,43 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 )
 
-// MainnetChainConfig is the chain parameters to run a node on the main network.
-var MainnetChainConfig = &ChainConfig{
-	ChainId:        MainNetChainID,
-	HomesteadBlock: MainNetHomesteadBlock,
-	DAOForkBlock:   MainNetDAOForkBlock,
-	DAOForkSupport: true,
-	EIP150Block:    MainNetHomesteadGasRepriceBlock,
-	EIP150Hash:     MainNetHomesteadGasRepriceHash,
-	EIP155Block:    MainNetSpuriousDragon,
-	EIP158Block:    MainNetSpuriousDragon,
-}
-
-// TestnetChainConfig is the chain parameters to run a node on the test network.
-var TestnetChainConfig = &ChainConfig{
-	ChainId:        big.NewInt(3),
-	HomesteadBlock: big.NewInt(0),
-	DAOForkBlock:   nil,
-	DAOForkSupport: true,
-	EIP150Block:    big.NewInt(0),
-	EIP150Hash:     common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
-	EIP155Block:    big.NewInt(10),
-	EIP158Block:    big.NewInt(10),
-}
-
-// AllProtocolChanges contains every protocol change (EIPs)
-// introduced and accepted by the Ethereum core developers.
-//
-// This configuration is intentionally not using keyed fields.
-// This configuration must *always* have all forks enabled, which
-// means that all fields must be set at all times. This forces
-// anyone adding flags to the config to also have to set these
-// fields.
-var AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
+var (
+	// MainnetChainConfig is the chain parameters to run a node on the main network.
+	MainnetChainConfig = &ChainConfig{
+		ChainId:        MainNetChainID,
+		HomesteadBlock: MainNetHomesteadBlock,
+		DAOForkBlock:   MainNetDAOForkBlock,
+		DAOForkSupport: true,
+		EIP150Block:    MainNetHomesteadGasRepriceBlock,
+		EIP150Hash:     MainNetHomesteadGasRepriceHash,
+		EIP155Block:    MainNetSpuriousDragon,
+		EIP158Block:    MainNetSpuriousDragon,
+	}
+
+	// TestnetChainConfig contains the chain parameters to run a node on the ropsten test network.
+	TestnetChainConfig = &ChainConfig{
+		ChainId:        big.NewInt(3),
+		HomesteadBlock: big.NewInt(0),
+		DAOForkBlock:   nil,
+		DAOForkSupport: true,
+		EIP150Block:    big.NewInt(0),
+		EIP150Hash:     common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
+		EIP155Block:    big.NewInt(10),
+		EIP158Block:    big.NewInt(10),
+	}
+
+	// AllProtocolChanges contains every protocol change (EIPs)
+	// introduced and accepted by the Ethereum core developers.
+	// TestChainConfig is like AllProtocolChanges but has chain ID 1.
+	//
+	// This configuration is intentionally not using keyed fields.
+	// This configuration must *always* have all forks enabled, which
+	// means that all fields must be set at all times. This forces
+	// anyone adding flags to the config to also have to set these
+	// fields.
+	AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
+	TestChainConfig    = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
+)
 
 // ChainConfig is the core config which determines the blockchain settings.
 //
@@ -77,7 +81,7 @@ type ChainConfig struct {
 	EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
 }
 
-// String implements the Stringer interface.
+// String implements the fmt.Stringer interface.
 func (c *ChainConfig) String() string {
 	return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}",
 		c.ChainId,
@@ -90,17 +94,26 @@ func (c *ChainConfig) String() string {
 	)
 }
 
-var (
-	TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
-	TestRules       = TestChainConfig.Rules(new(big.Int))
-)
-
 // IsHomestead returns whether num is either equal to the homestead block or greater.
 func (c *ChainConfig) IsHomestead(num *big.Int) bool {
-	if c.HomesteadBlock == nil || num == nil {
-		return false
-	}
-	return num.Cmp(c.HomesteadBlock) >= 0
+	return isForked(c.HomesteadBlock, num)
+}
+
+// IsDAO returns whether num is either equal to the DAO fork block or greater.
+func (c *ChainConfig) IsDAOFork(num *big.Int) bool {
+	return isForked(c.DAOForkBlock, num)
+}
+
+func (c *ChainConfig) IsEIP150(num *big.Int) bool {
+	return isForked(c.EIP150Block, num)
+}
+
+func (c *ChainConfig) IsEIP155(num *big.Int) bool {
+	return isForked(c.EIP155Block, num)
+}
+
+func (c *ChainConfig) IsEIP158(num *big.Int) bool {
+	return isForked(c.EIP158Block, num)
 }
 
 // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
@@ -110,51 +123,110 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
 	if num == nil {
 		return GasTableHomestead
 	}
-
 	switch {
-	case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0:
+	case c.IsEIP158(num):
 		return GasTableEIP158
-	case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0:
+	case c.IsEIP150(num):
 		return GasTableHomesteadGasRepriceFork
 	default:
 		return GasTableHomestead
 	}
 }
 
-func (c *ChainConfig) IsEIP150(num *big.Int) bool {
-	if c.EIP150Block == nil || num == nil {
-		return false
+// CheckCompatible checks whether scheduled fork transitions have been imported
+// with a mismatching chain configuration.
+func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
+	bhead := new(big.Int).SetUint64(height)
+
+	// Iterate checkCompatible to find the lowest conflict.
+	var lasterr *ConfigCompatError
+	for {
+		err := c.checkCompatible(newcfg, bhead)
+		if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
+			break
+		}
+		lasterr = err
+		bhead.SetUint64(err.RewindTo)
 	}
-	return num.Cmp(c.EIP150Block) >= 0
-
+	return lasterr
 }
 
-func (c *ChainConfig) IsEIP155(num *big.Int) bool {
-	if c.EIP155Block == nil || num == nil {
-		return false
+func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
+	if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
+		return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
+	}
+	if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) {
+		return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock)
 	}
-	return num.Cmp(c.EIP155Block) >= 0
+	if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport {
+		return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock)
+	}
+	if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
+		return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
+	}
+	if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
+		return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
+	}
+	if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
+		return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
+	}
+	if c.IsEIP158(head) && !configNumEqual(c.ChainId, newcfg.ChainId) {
+		return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
+	}
+	return nil
+}
 
+// isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to
+// block s2 because head is already past the fork.
+func isForkIncompatible(s1, s2, head *big.Int) bool {
+	return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2)
 }
 
-func (c *ChainConfig) IsEIP158(num *big.Int) bool {
-	if c.EIP158Block == nil || num == nil {
+// isForked returns whether a fork scheduled at block s is active at the given head block.
+func isForked(s, head *big.Int) bool {
+	if s == nil || head == nil {
 		return false
 	}
-	return num.Cmp(c.EIP158Block) >= 0
+	return s.Cmp(head) <= 0
+}
 
+func configNumEqual(x, y *big.Int) bool {
+	if x == nil {
+		return y == nil
+	}
+	if y == nil {
+		return x == nil
+	}
+	return x.Cmp(y) == 0
 }
 
-// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions
-// that do not have or require information about the block.
-//
-// Rules is a one time interface meaning that it shouldn't be used in between transition
-// phases.
-type Rules struct {
-	ChainId                                   *big.Int
-	IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
+// ConfigCompatError is raised if the locally-stored blockchain is initialised with a
+// ChainConfig that would alter the past.
+type ConfigCompatError struct {
+	What string
+	// block numbers of the stored and new configurations
+	StoredConfig, NewConfig *big.Int
+	// the block number to which the local chain must be rewound to correct the error
+	RewindTo uint64
+}
+
+func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
+	var rew *big.Int
+	switch {
+	case storedblock == nil:
+		rew = newblock
+	case newblock == nil || storedblock.Cmp(newblock) < 0:
+		rew = storedblock
+	default:
+		rew = newblock
+	}
+	err := &ConfigCompatError{what, storedblock, newblock, 0}
+	if rew != nil && rew.Sign() > 0 {
+		err.RewindTo = rew.Uint64() - 1
+	}
+	return err
 }
 
-func (c *ChainConfig) Rules(num *big.Int) Rules {
-	return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)}
+func (err *ConfigCompatError) Error() string {
+	return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
 }

+ 81 - 0
params/config_test.go

@@ -0,0 +1,81 @@
+// Copyright 2017 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 params
+
+import (
+	"math/big"
+	"reflect"
+	"testing"
+)
+
+func TestCheckCompatible(t *testing.T) {
+	type test struct {
+		stored, new *ChainConfig
+		head        uint64
+		wantErr     *ConfigCompatError
+	}
+	tests := []test{
+		{stored: AllProtocolChanges, new: AllProtocolChanges, head: 0, wantErr: nil},
+		{stored: AllProtocolChanges, new: AllProtocolChanges, head: 100, wantErr: nil},
+		{
+			stored:  &ChainConfig{EIP150Block: big.NewInt(10)},
+			new:     &ChainConfig{EIP150Block: big.NewInt(20)},
+			head:    9,
+			wantErr: nil,
+		},
+		{
+			stored: AllProtocolChanges,
+			new:    &ChainConfig{HomesteadBlock: nil},
+			head:   3,
+			wantErr: &ConfigCompatError{
+				What:         "Homestead fork block",
+				StoredConfig: big.NewInt(0),
+				NewConfig:    nil,
+				RewindTo:     0,
+			},
+		},
+		{
+			stored: AllProtocolChanges,
+			new:    &ChainConfig{HomesteadBlock: big.NewInt(1)},
+			head:   3,
+			wantErr: &ConfigCompatError{
+				What:         "Homestead fork block",
+				StoredConfig: big.NewInt(0),
+				NewConfig:    big.NewInt(1),
+				RewindTo:     0,
+			},
+		},
+		{
+			stored: &ChainConfig{HomesteadBlock: big.NewInt(30), EIP150Block: big.NewInt(10)},
+			new:    &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)},
+			head:   25,
+			wantErr: &ConfigCompatError{
+				What:         "EIP150 fork block",
+				StoredConfig: big.NewInt(10),
+				NewConfig:    big.NewInt(20),
+				RewindTo:     9,
+			},
+		},
+	}
+
+	for _, test := range tests {
+		err := test.stored.CheckCompatible(test.new, test.head)
+		if !reflect.DeepEqual(err, test.wantErr) {
+			t.Errorf("error mismatch:\nstored: %v\nnew: %v\nhead: %v\nerr: %v\nwant: %v", test.stored, test.new, test.head, err, test.wantErr)
+		}
+	}
+}

+ 118 - 369
params/dao.go

@@ -17,8 +17,6 @@
 package params
 
 import (
-	"encoding/json"
-	"fmt"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -47,372 +45,123 @@ var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d2
 
 // DAODrainList is the list of accounts whose full balances will be moved into a
 // refund contract at the beginning of the dao-fork block.
-var DAODrainList []common.Address
-
-func init() {
-	// Parse the list of DAO accounts to drain
-	var list []map[string]string
-	if err := json.Unmarshal([]byte(daoDrainListJSON), &list); err != nil {
-		panic(fmt.Errorf("Failed to parse DAO drain list: %v", err))
-	}
-	// Collect all the accounts that need draining
-	for _, dao := range list {
-		DAODrainList = append(DAODrainList, common.HexToAddress(dao["address"]))
-		DAODrainList = append(DAODrainList, common.HexToAddress(dao["extraBalanceAccount"]))
+func DAODrainList() []common.Address {
+	return []common.Address{
+		common.HexToAddress("0xd4fe7bc31cedb7bfb8a345f31e668033056b2728"),
+		common.HexToAddress("0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"),
+		common.HexToAddress("0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f"),
+		common.HexToAddress("0xecd135fa4f61a655311e86238c92adcd779555d2"),
+		common.HexToAddress("0x1975bd06d486162d5dc297798dfc41edd5d160a7"),
+		common.HexToAddress("0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"),
+		common.HexToAddress("0x319f70bab6845585f412ec7724b744fec6095c85"),
+		common.HexToAddress("0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"),
+		common.HexToAddress("0x5c8536898fbb74fc7445814902fd08422eac56d0"),
+		common.HexToAddress("0x6966ab0d485353095148a2155858910e0965b6f9"),
+		common.HexToAddress("0x779543a0491a837ca36ce8c635d6154e3c4911a6"),
+		common.HexToAddress("0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"),
+		common.HexToAddress("0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5"),
+		common.HexToAddress("0x9c50426be05db97f5d64fc54bf89eff947f0a321"),
+		common.HexToAddress("0x200450f06520bdd6c527622a273333384d870efb"),
+		common.HexToAddress("0xbe8539bfe837b67d1282b2b1d61c3f723966f049"),
+		common.HexToAddress("0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb"),
+		common.HexToAddress("0xf1385fb24aad0cd7432824085e42aff90886fef5"),
+		common.HexToAddress("0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091"),
+		common.HexToAddress("0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"),
+		common.HexToAddress("0x51e0ddd9998364a2eb38588679f0d2c42653e4a6"),
+		common.HexToAddress("0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"),
+		common.HexToAddress("0xf0b1aa0eb660754448a7937c022e30aa692fe0c5"),
+		common.HexToAddress("0x24c4d950dfd4dd1902bbed3508144a54542bba94"),
+		common.HexToAddress("0x9f27daea7aca0aa0446220b98d028715e3bc803d"),
+		common.HexToAddress("0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"),
+		common.HexToAddress("0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b"),
+		common.HexToAddress("0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"),
+		common.HexToAddress("0x6f6704e5a10332af6672e50b3d9754dc460dfa4d"),
+		common.HexToAddress("0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"),
+		common.HexToAddress("0x492ea3bb0f3315521c31f273e565b868fc090f17"),
+		common.HexToAddress("0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"),
+		common.HexToAddress("0x9ea779f907f0b315b364b0cfc39a0fde5b02a416"),
+		common.HexToAddress("0xceaeb481747ca6c540a000c1f3641f8cef161fa7"),
+		common.HexToAddress("0xcc34673c6c40e791051898567a1222daf90be287"),
+		common.HexToAddress("0x579a80d909f346fbfb1189493f521d7f48d52238"),
+		common.HexToAddress("0xe308bd1ac5fda103967359b2712dd89deffb7973"),
+		common.HexToAddress("0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"),
+		common.HexToAddress("0xac1ecab32727358dba8962a0f3b261731aad9723"),
+		common.HexToAddress("0x4fd6ace747f06ece9c49699c7cabc62d02211f75"),
+		common.HexToAddress("0x440c59b325d2997a134c2c7c60a8c61611212bad"),
+		common.HexToAddress("0x4486a3d68fac6967006d7a517b889fd3f98c102b"),
+		common.HexToAddress("0x9c15b54878ba618f494b38f0ae7443db6af648ba"),
+		common.HexToAddress("0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"),
+		common.HexToAddress("0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241"),
+		common.HexToAddress("0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"),
+		common.HexToAddress("0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b"),
+		common.HexToAddress("0xb9637156d330c0d605a791f1c31ba5890582fe1c"),
+		common.HexToAddress("0x6131c42fa982e56929107413a9d526fd99405560"),
+		common.HexToAddress("0x1591fc0f688c81fbeb17f5426a162a7024d430c2"),
+		common.HexToAddress("0x542a9515200d14b68e934e9830d91645a980dd7a"),
+		common.HexToAddress("0xc4bbd073882dd2add2424cf47d35213405b01324"),
+		common.HexToAddress("0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4"),
+		common.HexToAddress("0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"),
+		common.HexToAddress("0x3ba4d81db016dc2890c81f3acec2454bff5aada5"),
+		common.HexToAddress("0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"),
+		common.HexToAddress("0xe4ae1efdfc53b73893af49113d8694a057b9c0d1"),
+		common.HexToAddress("0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"),
+		common.HexToAddress("0x0737a6b837f97f46ebade41b9bc3e1c509c85c53"),
+		common.HexToAddress("0x97f43a37f595ab5dd318fb46e7a155eae057317a"),
+		common.HexToAddress("0x52c5317c848ba20c7504cb2c8052abd1fde29d03"),
+		common.HexToAddress("0x4863226780fe7c0356454236d3b1c8792785748d"),
+		common.HexToAddress("0x5d2b2e6fcbe3b11d26b525e085ff818dae332479"),
+		common.HexToAddress("0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"),
+		common.HexToAddress("0x057b56736d32b86616a10f619859c6cd6f59092a"),
+		common.HexToAddress("0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"),
+		common.HexToAddress("0x304a554a310c7e546dfe434669c62820b7d83490"),
+		common.HexToAddress("0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"),
+		common.HexToAddress("0x4deb0033bb26bc534b197e61d19e0733e5679784"),
+		common.HexToAddress("0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"),
+		common.HexToAddress("0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b"),
+		common.HexToAddress("0x4fa802324e929786dbda3b8820dc7834e9134a2a"),
+		common.HexToAddress("0x9da397b9e80755301a3b32173283a91c0ef6c87e"),
+		common.HexToAddress("0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"),
+		common.HexToAddress("0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9"),
+		common.HexToAddress("0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"),
+		common.HexToAddress("0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76"),
+		common.HexToAddress("0x12e626b0eebfe86a56d633b9864e389b45dcb260"),
+		common.HexToAddress("0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7"),
+		common.HexToAddress("0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"),
+		common.HexToAddress("0xd164b088bd9108b60d0ca3751da4bceb207b0782"),
+		common.HexToAddress("0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"),
+		common.HexToAddress("0x1cba23d343a983e9b5cfd19496b9a9701ada385f"),
+		common.HexToAddress("0xa82f360a8d3455c5c41366975bde739c37bfeb8a"),
+		common.HexToAddress("0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339"),
+		common.HexToAddress("0x005f5cee7a43331d5a3d3eec71305925a62f34b6"),
+		common.HexToAddress("0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d"),
+		common.HexToAddress("0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"),
+		common.HexToAddress("0xbc07118b9ac290e4622f5e77a0853539789effbe"),
+		common.HexToAddress("0x47e7aa56d6bdf3f36be34619660de61275420af8"),
+		common.HexToAddress("0xacd87e28b0c9d1254e868b81cba4cc20d9a32225"),
+		common.HexToAddress("0xadf80daec7ba8dcf15392f1ac611fff65d94f880"),
+		common.HexToAddress("0x5524c55fb03cf21f549444ccbecb664d0acad706"),
+		common.HexToAddress("0x40b803a9abce16f50f36a77ba41180eb90023925"),
+		common.HexToAddress("0xfe24cdd8648121a43a7c86d289be4dd2951ed49f"),
+		common.HexToAddress("0x17802f43a0137c506ba92291391a8a8f207f487d"),
+		common.HexToAddress("0x253488078a4edf4d6f42f113d1e62836a942cf1a"),
+		common.HexToAddress("0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"),
+		common.HexToAddress("0xb136707642a4ea12fb4bae820f03d2562ebff487"),
+		common.HexToAddress("0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"),
+		common.HexToAddress("0xf14c14075d6c4ed84b86798af0956deef67365b5"),
+		common.HexToAddress("0xca544e5c4687d109611d0f8f928b53a25af72448"),
+		common.HexToAddress("0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c"),
+		common.HexToAddress("0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"),
+		common.HexToAddress("0x6d87578288b6cb5549d5076a207456a1f6a63dc0"),
+		common.HexToAddress("0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"),
+		common.HexToAddress("0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6"),
+		common.HexToAddress("0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"),
+		common.HexToAddress("0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a"),
+		common.HexToAddress("0xd343b217de44030afaa275f54d31a9317c7f441e"),
+		common.HexToAddress("0x84ef4b2357079cd7a7c69fd7a37cd0609a679106"),
+		common.HexToAddress("0xda2fef9e4a3230988ff17df2165440f37e8b1708"),
+		common.HexToAddress("0xf4c64518ea10f995918a454158c6b61407ea345c"),
+		common.HexToAddress("0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"),
+		common.HexToAddress("0xbb9bc244d798123fde783fcc1c72d3bb8c189413"),
+		common.HexToAddress("0x807640a13483f8ac783c557fcdf27be11ea4ac7a"),
 	}
 }
-
-// daoDrainListJSON is the JSON encoded list of accounts whose full balances will
-// be moved into a refund contract at the beginning of the dao-fork block.
-const daoDrainListJSON = `
-[
-   {
-      "address":"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
-      "balance":"186cc8bfaefb7be",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"
-   },
-   {
-      "address":"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
-      "balance":"b14e8feab1ff435",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xecd135fa4f61a655311e86238c92adcd779555d2"
-   },
-   {
-      "address":"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
-      "balance":"359d26614cb5070c77",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"
-   },
-   {
-      "address":"0x319f70bab6845585f412ec7724b744fec6095c85",
-      "balance":"6e075cd846d2cb1d42",
-      "extraBalance":"13d34fd41b545b81",
-      "extraBalanceAccount":"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"
-   },
-   {
-      "address":"0x5c8536898fbb74fc7445814902fd08422eac56d0",
-      "balance":"b1e5593558008fd78",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x6966ab0d485353095148a2155858910e0965b6f9"
-   },
-   {
-      "address":"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
-      "balance":"392eaa20d1aad59a4c",
-      "extraBalance":"426938826a96c9",
-      "extraBalanceAccount":"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"
-   },
-   {
-      "address":"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
-      "balance":"2875d22b29793d4ba7",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x9c50426be05db97f5d64fc54bf89eff947f0a321"
-   },
-   {
-      "address":"0x200450f06520bdd6c527622a273333384d870efb",
-      "balance":"43c341d9f96954c049",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xbe8539bfe837b67d1282b2b1d61c3f723966f049"
-   },
-   {
-      "address":"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
-      "balance":"75251057154d70fa816",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xf1385fb24aad0cd7432824085e42aff90886fef5"
-   },
-   {
-      "address":"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
-      "balance":"392409769296cf67f36",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"
-   },
-   {
-      "address":"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
-      "balance":"8ac72eccbf4e8083",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"
-   },
-   {
-      "address":"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
-      "balance":"82289c3bb3e8c98799",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x24c4d950dfd4dd1902bbed3508144a54542bba94"
-   },
-   {
-      "address":"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
-      "balance":"56bc29049ebed40fd",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"
-   },
-   {
-      "address":"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
-      "balance":"56bc7d3ff79110524",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"
-   },
-   {
-      "address":"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
-      "balance":"23b651bd48cbc70cc",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"
-   },
-   {
-      "address":"0x492ea3bb0f3315521c31f273e565b868fc090f17",
-      "balance":"13ea6d4fee651dd7c9",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"
-   },
-   {
-      "address":"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
-      "balance":"35ac471a3836ae7de5a",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xceaeb481747ca6c540a000c1f3641f8cef161fa7"
-   },
-   {
-      "address":"0xcc34673c6c40e791051898567a1222daf90be287",
-      "balance":"d529c0b76b7aa0",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x579a80d909f346fbfb1189493f521d7f48d52238"
-   },
-   {
-      "address":"0xe308bd1ac5fda103967359b2712dd89deffb7973",
-      "balance":"5cd9e7df3a8e5cdd3",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"
-   },
-   {
-      "address":"0xac1ecab32727358dba8962a0f3b261731aad9723",
-      "balance":"2c8442fe35363313b93",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x4fd6ace747f06ece9c49699c7cabc62d02211f75"
-   },
-   {
-      "address":"0x440c59b325d2997a134c2c7c60a8c61611212bad",
-      "balance":"e77583a3958130e53",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x4486a3d68fac6967006d7a517b889fd3f98c102b"
-   },
-   {
-      "address":"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
-      "balance":"1f0b6ade348ca998",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"
-   },
-   {
-      "address":"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
-      "balance":"61725880736659",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"
-   },
-   {
-      "address":"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
-      "balance":"42948d8dc7ddbc22d",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xb9637156d330c0d605a791f1c31ba5890582fe1c"
-   },
-   {
-      "address":"0x6131c42fa982e56929107413a9d526fd99405560",
-      "balance":"7306683851d1eafbfa",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x1591fc0f688c81fbeb17f5426a162a7024d430c2"
-   },
-   {
-      "address":"0x542a9515200d14b68e934e9830d91645a980dd7a",
-      "balance":"2a8457d0d8432e21d0c",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xc4bbd073882dd2add2424cf47d35213405b01324"
-   },
-   {
-      "address":"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
-      "balance":"d8d7391feaeaa8cdb",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"
-   },
-   {
-      "address":"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
-      "balance":"1",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"
-   },
-   {
-      "address":"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
-      "balance":"456397665fa74041",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"
-   },
-   {
-      "address":"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
-      "balance":"6324dcb7126ecbef",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x97f43a37f595ab5dd318fb46e7a155eae057317a"
-   },
-   {
-      "address":"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
-      "balance":"6c3419b0705c01cd0d",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x4863226780fe7c0356454236d3b1c8792785748d"
-   },
-   {
-      "address":"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
-      "balance":"456397665fa74041",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"
-   },
-   {
-      "address":"0x057b56736d32b86616a10f619859c6cd6f59092a",
-      "balance":"232c025bb44b46",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"
-   },
-   {
-      "address":"0x304a554a310c7e546dfe434669c62820b7d83490",
-      "balance":"3034f5ca7d45e17df199b",
-      "extraBalance":"f7d15162c44e97b6e",
-      "extraBalanceAccount":"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"
-   },
-   {
-      "address":"0x4deb0033bb26bc534b197e61d19e0733e5679784",
-      "balance":"4417e96ed796591e09",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"
-   },
-   {
-      "address":"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
-      "balance":"d3ff7771412bbcc9",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x4fa802324e929786dbda3b8820dc7834e9134a2a"
-   },
-   {
-      "address":"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
-      "balance":"32ae324c233816b4c2",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"
-   },
-   {
-      "address":"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
-      "balance":"1e530695b705f037c6",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"
-   },
-   {
-      "address":"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
-      "balance":"68013bad5b4b1133fc5",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x12e626b0eebfe86a56d633b9864e389b45dcb260"
-   },
-   {
-      "address":"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
-      "balance":"456397665fa74041",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"
-   },
-   {
-      "address":"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
-      "balance":"3635ce47fabaaa336e",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"
-   },
-   {
-      "address":"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
-      "balance":"f3abd9906c170a",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xa82f360a8d3455c5c41366975bde739c37bfeb8a"
-   },
-   {
-      "address":"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
-      "balance":"4c6679d9d9b95a4e08",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x005f5cee7a43331d5a3d3eec71305925a62f34b6"
-   },
-   {
-      "address":"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
-      "balance":"40f622936475de31849",
-      "extraBalance":"671e1bbabded39754",
-      "extraBalanceAccount":"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"
-   },
-   {
-      "address":"0xbc07118b9ac290e4622f5e77a0853539789effbe",
-      "balance":"1316ccfa4a35db5e58f",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x47e7aa56d6bdf3f36be34619660de61275420af8"
-   },
-   {
-      "address":"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
-      "balance":"b3ad6bb72000bab9f",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xadf80daec7ba8dcf15392f1ac611fff65d94f880"
-   },
-   {
-      "address":"0x5524c55fb03cf21f549444ccbecb664d0acad706",
-      "balance":"16f2da372a5c8a70967",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x40b803a9abce16f50f36a77ba41180eb90023925"
-   },
-   {
-      "address":"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
-      "balance":"ea0b1bdc78f500a43",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x17802f43a0137c506ba92291391a8a8f207f487d"
-   },
-   {
-      "address":"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
-      "balance":"3060e3aed135cc80",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"
-   },
-   {
-      "address":"0xb136707642a4ea12fb4bae820f03d2562ebff487",
-      "balance":"6050bdeb3354b5c98adc3",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"
-   },
-   {
-      "address":"0xf14c14075d6c4ed84b86798af0956deef67365b5",
-      "balance":"1d77844e94c25ba2",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xca544e5c4687d109611d0f8f928b53a25af72448"
-   },
-   {
-      "address":"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
-      "balance":"2e93a72de4fc5ec0ed",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"
-   },
-   {
-      "address":"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
-      "balance":"1afd340799e48c18",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"
-   },
-   {
-      "address":"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
-      "balance":"14d0944eb3be947a8",
-      "extraBalance":"0",
-      "extraBalanceAccount":"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"
-   },
-   {
-      "address":"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
-      "balance":"6202b236a200e365eba",
-      "extraBalance":"11979be9020f03ec4ec",
-      "extraBalanceAccount":"0xd343b217de44030afaa275f54d31a9317c7f441e"
-   },
-   {
-      "address":"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
-      "balance":"7ed634ebbba531901e07",
-      "extraBalance":"f9c5eff28cb08720c85",
-      "extraBalanceAccount":"0xda2fef9e4a3230988ff17df2165440f37e8b1708"
-   },
-   {
-      "address":"0xf4c64518ea10f995918a454158c6b61407ea345c",
-      "balance":"39152e15508a96ff894a",
-      "extraBalance":"14041ca908bcc185c8",
-      "extraBalanceAccount":"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"
-   },
-   {
-      "address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
-      "balance":"1",
-      "extraBalance":"5553ebc",
-      "extraBalanceAccount":"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
-   }
-]
-`

Some files were not shown because too many files changed in this diff