浏览代码

Merge pull request #3794 from fjl/core-genesis-refactor

core: refactor genesis handling
Péter Szilágyi 8 年之前
父节点
当前提交
8771c3061f
共有 54 个文件被更改,包括 1520 次插入1292 次删除
  1. 8 10
      accounts/abi/bind/backends/simulated.go
  2. 9 9
      accounts/abi/bind/bind_test.go
  3. 2 3
      accounts/abi/bind/util_test.go
  4. 10 4
      cmd/geth/chaincmd.go
  5. 18 73
      cmd/utils/flags.go
  6. 27 5
      common/hexutil/json.go
  7. 35 0
      common/hexutil/json_test.go
  8. 19 0
      common/math/big.go
  9. 7 6
      common/math/big_test.go
  10. 22 1
      common/math/integer.go
  11. 6 5
      common/math/integer_test.go
  12. 30 14
      common/types.go
  13. 4 5
      console/console_test.go
  14. 5 5
      contracts/chequebook/cheque_test.go
  15. 1 1
      contracts/ens/ens_test.go
  16. 3 3
      contracts/release/contract_test.go
  17. 8 4
      core/bench_test.go
  18. 9 24
      core/block_validator_test.go
  19. 108 243
      core/blockchain_test.go
  20. 9 25
      core/chain_makers.go
  21. 8 10
      core/chain_makers_test.go
  22. 1 1
      core/dao.go
  23. 8 7
      core/dao_test.go
  24. 1 1
      core/database_util_test.go
  25. 0 20
      core/default_genesis.go
  26. 106 0
      core/gen_genesis.go
  27. 61 0
      core/gen_genesis_account.go
  28. 217 161
      core/genesis.go
  29. 22 0
      core/genesis_alloc.go
  30. 161 0
      core/genesis_test.go
  31. 1 6
      core/headerchain.go
  32. 85 0
      core/mkalloc.go
  33. 3 2
      core/state/statedb.go
  34. 5 5
      core/tx_pool_test.go
  35. 0 14
      core/types/transaction.go
  36. 3 0
      core/types/transaction_signing.go
  37. 25 62
      eth/backend.go
  38. 1 1
      eth/backend_test.go
  39. 5 6
      eth/filters/filter_system_test.go
  40. 3 3
      eth/filters/filter_test.go
  41. 7 6
      eth/handler_test.go
  42. 12 12
      eth/helper_test.go
  43. 12 10
      les/backend.go
  44. 14 11
      les/helper_test.go
  45. 1 1
      les/server.go
  46. 1 5
      light/lightchain.go
  47. 26 55
      light/lightchain_test.go
  48. 3 2
      light/odr_test.go
  49. 3 2
      light/txpool_test.go
  50. 39 11
      mobile/geth.go
  51. 7 1
      mobile/params.go
  52. 140 68
      params/config.go
  53. 81 0
      params/config_test.go
  54. 118 369
      params/dao.go

+ 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
 }

+ 27 - 5
common/hexutil/json.go

@@ -51,7 +51,7 @@ func (b *Bytes) UnmarshalJSON(input []byte) error {
 
 // UnmarshalText implements encoding.TextUnmarshaler.
 func (b *Bytes) UnmarshalText(input []byte) error {
-	raw, err := checkText(input)
+	raw, err := checkText(input, true)
 	if err != nil {
 		return err
 	}
@@ -73,7 +73,28 @@ func (b Bytes) String() string {
 // determines the required input length. This function is commonly used to implement the
 // UnmarshalText method for fixed-size types.
 func UnmarshalFixedText(typname string, input, out []byte) error {
-	raw, err := checkText(input)
+	raw, err := checkText(input, true)
+	if err != nil {
+		return err
+	}
+	if len(raw)/2 != len(out) {
+		return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
+	}
+	// Pre-verify syntax before modifying out.
+	for _, b := range raw {
+		if decodeNibble(b) == badNibble {
+			return ErrSyntax
+		}
+	}
+	hex.Decode(out, raw)
+	return nil
+}
+
+// UnmarshalFixedUnprefixedText decodes the input as a string with optional 0x prefix. The
+// length of out determines the required input length. This function is commonly used to
+// implement the UnmarshalText method for fixed-size types.
+func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error {
+	raw, err := checkText(input, false)
 	if err != nil {
 		return err
 	}
@@ -243,14 +264,15 @@ func bytesHave0xPrefix(input []byte) bool {
 	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
 }
 
-func checkText(input []byte) ([]byte, error) {
+func checkText(input []byte, wantPrefix bool) ([]byte, error) {
 	if len(input) == 0 {
 		return nil, nil // empty strings are allowed
 	}
-	if !bytesHave0xPrefix(input) {
+	if bytesHave0xPrefix(input) {
+		input = input[2:]
+	} else if wantPrefix {
 		return nil, ErrMissingPrefix
 	}
-	input = input[2:]
 	if len(input)%2 != 0 {
 		return nil, ErrOddLength
 	}

+ 35 - 0
common/hexutil/json_test.go

@@ -337,3 +337,38 @@ func TestUnmarshalUint(t *testing.T) {
 		}
 	}
 }
+
+func TestUnmarshalFixedUnprefixedText(t *testing.T) {
+	tests := []struct {
+		input   string
+		want    []byte
+		wantErr error
+	}{
+		{input: "0x2", wantErr: ErrOddLength},
+		{input: "2", wantErr: ErrOddLength},
+		{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
+		{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
+		// check that output is not modified for partially correct input
+		{input: "444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
+		{input: "0x444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
+		// valid inputs
+		{input: "44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
+		{input: "0x44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
+	}
+
+	for _, test := range tests {
+		out := make([]byte, 4)
+		err := UnmarshalFixedUnprefixedText("x", []byte(test.input), out)
+		switch {
+		case err == nil && test.wantErr != nil:
+			t.Errorf("%q: got no error, expected %q", test.input, test.wantErr)
+		case err != nil && test.wantErr == nil:
+			t.Errorf("%q: unexpected error %q", test.input, err)
+		case err != nil && err.Error() != test.wantErr.Error():
+			t.Errorf("%q: error mismatch: got %q, want %q", test.input, err, test.wantErr)
+		}
+		if test.want != nil && !bytes.Equal(out, test.want) {
+			t.Errorf("%q: output mismatch: got %x, want %x", test.input, out, test.want)
+		}
+	}
+}

+ 19 - 0
common/math/big.go

@@ -18,6 +18,7 @@
 package math
 
 import (
+	"fmt"
 	"math/big"
 )
 
@@ -35,6 +36,24 @@ const (
 	wordBytes = wordBits / 8
 )
 
+// HexOrDecimal256 marshals big.Int as hex or decimal.
+type HexOrDecimal256 big.Int
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (i *HexOrDecimal256) UnmarshalText(input []byte) error {
+	bigint, ok := ParseBig256(string(input))
+	if !ok {
+		return fmt.Errorf("invalid hex or decimal integer %q", input)
+	}
+	*i = HexOrDecimal256(*bigint)
+	return nil
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (i *HexOrDecimal256) MarshalText() ([]byte, error) {
+	return []byte(fmt.Sprintf("%#x", (*big.Int)(i))), nil
+}
+
 // ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax.
 // Leading zeros are accepted. The empty string parses as zero.
 func ParseBig256(s string) (*big.Int, bool) {

+ 7 - 6
common/math/big_test.go

@@ -23,7 +23,7 @@ import (
 	"testing"
 )
 
-func TestParseBig256(t *testing.T) {
+func TestHexOrDecimal256(t *testing.T) {
 	tests := []struct {
 		input string
 		num   *big.Int
@@ -47,13 +47,14 @@ func TestParseBig256(t *testing.T) {
 		{"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false},
 	}
 	for _, test := range tests {
-		num, ok := ParseBig256(test.input)
-		if ok != test.ok {
-			t.Errorf("ParseBig(%q) -> ok = %t, want %t", test.input, ok, test.ok)
+		var num HexOrDecimal256
+		err := num.UnmarshalText([]byte(test.input))
+		if (err == nil) != test.ok {
+			t.Errorf("ParseBig(%q) -> (err == nil) == %t, want %t", test.input, err == nil, test.ok)
 			continue
 		}
-		if num != nil && test.num != nil && num.Cmp(test.num) != 0 {
-			t.Errorf("ParseBig(%q) -> %d, want %d", test.input, num, test.num)
+		if test.num != nil && (*big.Int)(&num).Cmp(test.num) != 0 {
+			t.Errorf("ParseBig(%q) -> %d, want %d", test.input, (*big.Int)(&num), test.num)
 		}
 	}
 }

+ 22 - 1
common/math/integer.go

@@ -16,7 +16,10 @@
 
 package math
 
-import "strconv"
+import (
+	"fmt"
+	"strconv"
+)
 
 const (
 	// Integer limit values.
@@ -34,6 +37,24 @@ const (
 	MaxUint64 = 1<<64 - 1
 )
 
+// HexOrDecimal64 marshals uint64 as hex or decimal.
+type HexOrDecimal64 uint64
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (i *HexOrDecimal64) UnmarshalText(input []byte) error {
+	int, ok := ParseUint64(string(input))
+	if !ok {
+		return fmt.Errorf("invalid hex or decimal integer %q", input)
+	}
+	*i = HexOrDecimal64(int)
+	return nil
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (i HexOrDecimal64) MarshalText() ([]byte, error) {
+	return []byte(fmt.Sprintf("%#x", uint64(i))), nil
+}
+
 // ParseUint64 parses s as an integer in decimal or hexadecimal syntax.
 // Leading zeros are accepted. The empty string parses as zero.
 func ParseUint64(s string) (uint64, bool) {

+ 6 - 5
common/math/integer_test.go

@@ -65,7 +65,7 @@ func TestOverflow(t *testing.T) {
 	}
 }
 
-func TestParseUint64(t *testing.T) {
+func TestHexOrDecimal64(t *testing.T) {
 	tests := []struct {
 		input string
 		num   uint64
@@ -88,12 +88,13 @@ func TestParseUint64(t *testing.T) {
 		{"18446744073709551617", 0, false},
 	}
 	for _, test := range tests {
-		num, ok := ParseUint64(test.input)
-		if ok != test.ok {
-			t.Errorf("ParseUint64(%q) -> ok = %t, want %t", test.input, ok, test.ok)
+		var num HexOrDecimal64
+		err := num.UnmarshalText([]byte(test.input))
+		if (err == nil) != test.ok {
+			t.Errorf("ParseUint64(%q) -> (err == nil) = %t, want %t", test.input, err == nil, test.ok)
 			continue
 		}
-		if ok && num != test.num {
+		if err == nil && uint64(num) != test.num {
 			t.Errorf("ParseUint64(%q) -> %d, want %d", test.input, num, test.num)
 		}
 	}

+ 30 - 14
common/types.go

@@ -17,6 +17,7 @@
 package common
 
 import (
+	"encoding/hex"
 	"fmt"
 	"math/big"
 	"math/rand"
@@ -30,13 +31,8 @@ const (
 	AddressLength = 20
 )
 
-type (
-	// Hash represents the 32 byte Keccak256 hash of arbitrary data.
-	Hash [HashLength]byte
-
-	// Address represents the 20 byte address of an Ethereum account.
-	Address [AddressLength]byte
-)
+// Hash represents the 32 byte Keccak256 hash of arbitrary data.
+type Hash [HashLength]byte
 
 func BytesToHash(b []byte) Hash {
 	var h Hash
@@ -113,7 +109,24 @@ func EmptyHash(h Hash) bool {
 	return h == Hash{}
 }
 
+// UnprefixedHash allows marshaling a Hash without 0x prefix.
+type UnprefixedHash Hash
+
+// UnmarshalText decodes the hash from hex. The 0x prefix is optional.
+func (h *UnprefixedHash) UnmarshalText(input []byte) error {
+	return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:])
+}
+
+// MarshalText encodes the hash as hex.
+func (h UnprefixedHash) MarshalText() ([]byte, error) {
+	return []byte(hex.EncodeToString(h[:])), nil
+}
+
 /////////// Address
+
+// Address represents the 20 byte address of an Ethereum account.
+type Address [AddressLength]byte
+
 func BytesToAddress(b []byte) Address {
 	var a Address
 	a.SetBytes(b)
@@ -181,12 +194,15 @@ func (a *Address) UnmarshalText(input []byte) error {
 	return hexutil.UnmarshalFixedText("Address", input, a[:])
 }
 
-// PP Pretty Prints a byte slice in the following format:
-// 	hex(value[:4])...(hex[len(value)-4:])
-func PP(value []byte) string {
-	if len(value) <= 8 {
-		return Bytes2Hex(value)
-	}
+// UnprefixedHash allows marshaling an Address without 0x prefix.
+type UnprefixedAddress Address
+
+// UnmarshalText decodes the address from hex. The 0x prefix is optional.
+func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
+	return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:])
+}
 
-	return fmt.Sprintf("%x...%x", value[:4], value[len(value)-4])
+// MarshalText encodes the address as hex.
+func (a UnprefixedAddress) MarshalText() ([]byte, error) {
+	return []byte(hex.EncodeToString(a[:])), nil
 }

+ 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 {

文件差异内容过多而无法显示
+ 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
 }

文件差异内容过多而无法显示
+ 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))
+}

+ 3 - 2
core/state/statedb.go

@@ -611,7 +611,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
 // the root hash stored in a block.
 func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) {
 	batch = s.db.NewBatch()
-	root, _ = s.commit(batch, deleteEmptyObjects)
+	root, _ = s.CommitTo(batch, deleteEmptyObjects)
 
 	log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads())
 	return root, batch
@@ -623,7 +623,8 @@ func (s *StateDB) clearJournalAndRefund() {
 	s.refund = new(big.Int)
 }
 
-func (s *StateDB) commit(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
+// CommitTo writes the state to the given database.
+func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
 	defer s.clearJournalAndRefund()
 
 	// Commit objects to the trie.

+ 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)

+ 3 - 0
core/types/transaction_signing.go

@@ -112,6 +112,9 @@ type EIP155Signer struct {
 }
 
 func NewEIP155Signer(chainId *big.Int) EIP155Signer {
+	if chainId == nil {
+		chainId = new(big.Int)
+	}
 	return EIP155Signer{
 		chainId:    chainId,
 		chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),

+ 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"
-   }
-]
-`

部分文件因为文件数量过多而无法显示