Browse Source

cmd, core, eth, common: genesis preparation

Implemented the --genesis flag thru which we can set a custom genesis
block, including the official Ethereum genesis block.
Jeffrey Wilcke 10 years ago
parent
commit
a32c51effd

+ 4 - 2
cmd/geth/js_test.go

@@ -37,6 +37,7 @@ import (
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/eth"
+	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/rpc/codec"
 	"github.com/ethereum/go-ethereum/rpc/comms"
 )
@@ -89,9 +90,9 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *eth
 		t.Fatal(err)
 	}
 
-	// set up mock genesis with balance on the testAddress
-	core.GenesisAccounts = []byte(testGenesis)
+	db, _ := ethdb.NewMemDatabase()
 
+	core.WriteGenesisBlockForTesting(db, common.HexToAddress(testAddress), common.String2Big(testBalance))
 	ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore"))
 	am := accounts.NewManager(ks)
 	conf := &eth.Config{
@@ -102,6 +103,7 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *eth
 		Name:           "test",
 		SolcPath:       testSolcPath,
 		PowTest:        true,
+		NewDB:          func(path string) (common.Database, error) { return db, nil },
 	}
 	if config != nil {
 		config(conf)

+ 1 - 0
cmd/geth/main.go

@@ -277,6 +277,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
 		utils.UnlockedAccountFlag,
 		utils.PasswordFileFlag,
 		utils.GenesisNonceFlag,
+		utils.GenesisFileFlag,
 		utils.BootnodesFlag,
 		utils.DataDirFlag,
 		utils.BlockchainVersionFlag,

+ 7 - 2
cmd/utils/flags.go

@@ -114,6 +114,10 @@ var (
 		Usage: "Sets the genesis nonce",
 		Value: 42,
 	}
+	GenesisFileFlag = cli.StringFlag{
+		Name:  "genesis",
+		Usage: "Inserts/Overwrites the genesis block (json format)",
+	}
 	IdentityFlag = cli.StringFlag{
 		Name:  "identity",
 		Usage: "Custom node name",
@@ -378,6 +382,7 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
 		Name:                    common.MakeName(clientID, version),
 		DataDir:                 ctx.GlobalString(DataDirFlag.Name),
 		GenesisNonce:            ctx.GlobalInt(GenesisNonceFlag.Name),
+		GenesisFile:             ctx.GlobalString(GenesisFileFlag.Name),
 		BlockChainVersion:       ctx.GlobalInt(BlockchainVersionFlag.Name),
 		SkipBcVersionCheck:      false,
 		NetworkId:               ctx.GlobalInt(NetworkIdFlag.Name),
@@ -434,8 +439,8 @@ func MakeChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, ex
 
 	eventMux := new(event.TypeMux)
 	pow := ethash.New()
-	genesis := core.GenesisBlock(uint64(ctx.GlobalInt(GenesisNonceFlag.Name)), blockDB)
-	chain, err = core.NewChainManager(genesis, blockDB, stateDB, extraDB, pow, eventMux)
+	//genesis := core.GenesisBlock(uint64(ctx.GlobalInt(GenesisNonceFlag.Name)), blockDB)
+	chain, err = core.NewChainManager(blockDB, stateDB, extraDB, pow, eventMux)
 	if err != nil {
 		Fatalf("Could not start chainmanager: %v", err)
 	}

+ 5 - 3
common/natspec/natspec_e2e_test.go

@@ -33,6 +33,7 @@ import (
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/eth"
+	"github.com/ethereum/go-ethereum/ethdb"
 	xe "github.com/ethereum/go-ethereum/xeth"
 )
 
@@ -128,12 +129,12 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
 	if err != nil {
 		panic(err)
 	}
+
 	testAddress := strings.TrimPrefix(testAccount.Address.Hex(), "0x")
 
+	db, _ := ethdb.NewMemDatabase()
 	// set up mock genesis with balance on the testAddress
-	core.GenesisAccounts = []byte(`{
-	"` + testAddress + `": {"balance": "` + testBalance + `"}
-	}`)
+	core.WriteGenesisBlockForTesting(db, common.HexToAddress(testAddress), common.String2Big(testBalance))
 
 	// only use minimalistic stack with no networking
 	ethereum, err = eth.New(&eth.Config{
@@ -142,6 +143,7 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
 		MaxPeers:       0,
 		PowTest:        true,
 		Etherbase:      common.HexToAddress(testAddress),
+		NewDB:          func(path string) (common.Database, error) { return db, nil },
 	})
 
 	if err != nil {

+ 2 - 2
core/bench_test.go

@@ -162,13 +162,13 @@ 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 := GenesisBlockForTesting(db, benchRootAddr, benchRootFunds)
+	genesis := WriteGenesisBlockForTesting(db, benchRootAddr, benchRootFunds)
 	chain := GenerateChain(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, _ := NewChainManager(genesis, db, db, db, FakePow{}, evmux)
+	chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
 	chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux))
 	defer chainman.Stop()
 	b.ReportAllocs()

+ 2 - 2
core/block_processor_test.go

@@ -33,8 +33,8 @@ func proc() (*BlockProcessor, *ChainManager) {
 	db, _ := ethdb.NewMemDatabase()
 	var mux event.TypeMux
 
-	genesis := GenesisBlock(0, db)
-	chainMan, err := NewChainManager(genesis, db, db, db, thePow(), &mux)
+	WriteTestNetGenesisBlock(db, db, 0)
+	chainMan, err := NewChainManager(db, db, db, thePow(), &mux)
 	if err != nil {
 		fmt.Println(err)
 	}

+ 3 - 1
core/chain_makers.go

@@ -183,7 +183,9 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
 // InsertChain on the result of makeChain.
 func newCanonical(n int, db common.Database) (*BlockProcessor, error) {
 	evmux := &event.TypeMux{}
-	chainman, _ := NewChainManager(GenesisBlock(0, db), db, db, db, FakePow{}, evmux)
+
+	WriteTestNetGenesisBlock(db, db, 0)
+	chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
 	bman := NewBlockProcessor(db, db, FakePow{}, chainman, evmux)
 	bman.bc.SetProcessor(bman)
 	parent := bman.bc.CurrentBlock()

+ 2 - 2
core/chain_makers_test.go

@@ -39,7 +39,7 @@ func ExampleGenerateChain() {
 	)
 
 	// Ensure that key1 has some funds in the genesis block.
-	genesis := GenesisBlockForTesting(db, addr1, big.NewInt(1000000))
+	genesis := WriteGenesisBlockForTesting(db, addr1, big.NewInt(1000000))
 
 	// This call generates a chain of 5 blocks. The function runs for
 	// each block and adds different features to gen based on the
@@ -74,7 +74,7 @@ func ExampleGenerateChain() {
 
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
-	chainman, _ := NewChainManager(genesis, db, db, db, FakePow{}, evmux)
+	chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
 	chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux))
 	if i, err := chainman.InsertChain(chain); err != nil {
 		fmt.Printf("insert error (block %d): %v\n", i, err)

+ 45 - 40
core/chain_manager.go

@@ -18,6 +18,7 @@
 package core
 
 import (
+	"errors"
 	"fmt"
 	"io"
 	"math/big"
@@ -34,7 +35,6 @@ import (
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/metrics"
 	"github.com/ethereum/go-ethereum/pow"
-	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/hashicorp/golang-lru"
 )
 
@@ -42,10 +42,9 @@ var (
 	chainlogger = logger.NewLogger("CHAIN")
 	jsonlogger  = logger.NewJsonLogger()
 
-	blockHashPre = []byte("block-hash-")
-	blockNumPre  = []byte("block-num-")
-
 	blockInsertTimer = metrics.NewTimer("chain/inserts")
+
+	ErrNoGenesis = errors.New("Genesis not found in chain")
 )
 
 const (
@@ -88,25 +87,32 @@ type ChainManager struct {
 	pow pow.PoW
 }
 
-func NewChainManager(genesis *types.Block, blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux *event.TypeMux) (*ChainManager, error) {
+func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux *event.TypeMux) (*ChainManager, error) {
 	cache, _ := lru.New(blockCacheLimit)
 	bc := &ChainManager{
-		blockDb:      blockDb,
-		stateDb:      stateDb,
-		extraDb:      extraDb,
-		genesisBlock: GenesisBlock(42, stateDb),
-		eventMux:     mux,
-		quit:         make(chan struct{}),
-		cache:        cache,
-		pow:          pow,
-	}
-	// Check the genesis block given to the chain manager. If the genesis block mismatches block number 0
-	// throw an error. If no block or the same block's found continue.
-	if g := bc.GetBlockByNumber(0); g != nil && g.Hash() != genesis.Hash() {
-		return nil, fmt.Errorf("Genesis mismatch. Maybe different nonce (%d vs %d)? %x / %x", g.Nonce(), genesis.Nonce(), g.Hash().Bytes()[:4], genesis.Hash().Bytes()[:4])
-	}
-	bc.genesisBlock = genesis
-	bc.setLastState()
+		blockDb:  blockDb,
+		stateDb:  stateDb,
+		extraDb:  extraDb,
+		eventMux: mux,
+		quit:     make(chan struct{}),
+		cache:    cache,
+		pow:      pow,
+	}
+
+	bc.genesisBlock = bc.GetBlockByNumber(0)
+	if bc.genesisBlock == nil {
+		// XXX Uncomment me before Frontier
+		//return nil, ErrNoGenesis
+		genesis, err := WriteTestNetGenesisBlock(bc.stateDb, bc.blockDb, 42)
+		if err != nil {
+			glog.Fatalln("genisis err", err)
+		}
+		bc.genesisBlock = genesis
+	}
+
+	if err := bc.setLastState(); err != nil {
+		return nil, err
+	}
 
 	// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
 	for hash, _ := range BadHashes {
@@ -226,7 +232,7 @@ func (bc *ChainManager) recover() bool {
 	return false
 }
 
-func (bc *ChainManager) setLastState() {
+func (bc *ChainManager) setLastState() error {
 	data, _ := bc.blockDb.Get([]byte("LastBlock"))
 	if len(data) != 0 {
 		block := bc.GetBlock(common.BytesToHash(data))
@@ -250,6 +256,8 @@ func (bc *ChainManager) setLastState() {
 	if glog.V(logger.Info) {
 		glog.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
 	}
+
+	return nil
 }
 
 func (bc *ChainManager) makeCache() {
@@ -272,7 +280,11 @@ func (bc *ChainManager) Reset() {
 	bc.cache, _ = lru.New(blockCacheLimit)
 
 	// Prepare the genesis block
-	bc.write(bc.genesisBlock)
+	err := WriteBlock(bc.blockDb, bc.genesisBlock)
+	if err != nil {
+		glog.Fatalln("db err:", err)
+	}
+
 	bc.insert(bc.genesisBlock)
 	bc.currentBlock = bc.genesisBlock
 	bc.makeCache()
@@ -295,7 +307,12 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
 	// Prepare the genesis block
 	gb.Td = gb.Difficulty()
 	bc.genesisBlock = gb
-	bc.write(bc.genesisBlock)
+
+	err := WriteBlock(bc.blockDb, bc.genesisBlock)
+	if err != nil {
+		glog.Fatalln("db err:", err)
+	}
+
 	bc.insert(bc.genesisBlock)
 	bc.currentBlock = bc.genesisBlock
 	bc.makeCache()
@@ -357,21 +374,6 @@ func (bc *ChainManager) insert(block *types.Block) {
 	bc.lastBlockHash = block.Hash()
 }
 
-func (bc *ChainManager) write(block *types.Block) {
-	tstart := time.Now()
-
-	enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block))
-	key := append(blockHashPre, block.Hash().Bytes()...)
-	err := bc.blockDb.Put(key, enc)
-	if err != nil {
-		glog.Fatal("db write fail:", err)
-	}
-
-	if glog.V(logger.Debug) {
-		glog.Infof("wrote block #%v %s. Took %v\n", block.Number(), common.PP(block.Hash().Bytes()), time.Since(tstart))
-	}
-}
-
 // Accessors
 func (bc *ChainManager) Genesis() *types.Block {
 	return bc.genesisBlock
@@ -535,7 +537,10 @@ func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status wr
 		status = SideStatTy
 	}
 
-	self.write(block)
+	err = WriteBlock(self.blockDb, block)
+	if err != nil {
+		glog.Fatalln("db err:", err)
+	}
 	// Delete from future blocks
 	self.futureBlocks.Remove(block.Hash())
 

+ 21 - 25
core/chain_manager_test.go

@@ -48,8 +48,8 @@ func thePow() pow.PoW {
 
 func theChainManager(db common.Database, t *testing.T) *ChainManager {
 	var eventMux event.TypeMux
-	genesis := GenesisBlock(0, db)
-	chainMan, err := NewChainManager(genesis, db, db, db, thePow(), &eventMux)
+	WriteTestNetGenesisBlock(db, db, 0)
+	chainMan, err := NewChainManager(db, db, db, thePow(), &eventMux)
 	if err != nil {
 		t.Error("failed creating chainmanager:", err)
 		t.FailNow()
@@ -125,7 +125,7 @@ func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
 
 		bman.bc.mu.Lock()
 		{
-			bman.bc.write(block)
+			WriteBlock(bman.bc.blockDb, block)
 		}
 		bman.bc.mu.Unlock()
 	}
@@ -362,25 +362,6 @@ func TestChainMultipleInsertions(t *testing.T) {
 	}
 }
 
-func TestGetBlocksFromHash(t *testing.T) {
-	t.Skip("Skipped: outdated test files")
-
-	db, _ := ethdb.NewMemDatabase()
-	chainMan := theChainManager(db, t)
-	chain, err := loadChain("valid1", t)
-	if err != nil {
-		fmt.Println(err)
-		t.FailNow()
-	}
-
-	for _, block := range chain {
-		chainMan.write(block)
-	}
-
-	blocks := chainMan.GetBlocksFromHash(chain[len(chain)-1].Hash(), 4)
-	fmt.Println(blocks)
-}
-
 type bproc struct{}
 
 func (bproc) Process(*types.Block) (state.Logs, types.Receipts, error) { return nil, nil, nil }
@@ -418,7 +399,12 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
 
 func TestReorgLongest(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
-	genesis := GenesisBlock(0, db)
+
+	genesis, err := WriteTestNetGenesisBlock(db, db, 0)
+	if err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
 	bc := chm(genesis, db)
 
 	chain1 := makeChainWithDiff(genesis, []int{1, 2, 4}, 10)
@@ -437,7 +423,11 @@ func TestReorgLongest(t *testing.T) {
 
 func TestReorgShortest(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
-	genesis := GenesisBlock(0, db)
+	genesis, err := WriteTestNetGenesisBlock(db, db, 0)
+	if err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
 	bc := chm(genesis, db)
 
 	chain1 := makeChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
@@ -457,7 +447,11 @@ func TestReorgShortest(t *testing.T) {
 func TestInsertNonceError(t *testing.T) {
 	for i := 1; i < 25 && !t.Failed(); i++ {
 		db, _ := ethdb.NewMemDatabase()
-		genesis := GenesisBlock(0, db)
+		genesis, err := WriteTestNetGenesisBlock(db, db, 0)
+		if err != nil {
+			t.Error(err)
+			t.FailNow()
+		}
 		bc := chm(genesis, db)
 		bc.processor = NewBlockProcessor(db, db, bc.pow, bc, bc.eventMux)
 		blocks := makeChain(bc.currentBlock, i, db, 0)
@@ -491,6 +485,7 @@ func TestInsertNonceError(t *testing.T) {
 	}
 }
 
+/*
 func TestGenesisMismatch(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
 	var mux event.TypeMux
@@ -505,6 +500,7 @@ func TestGenesisMismatch(t *testing.T) {
 		t.Error("expected genesis mismatch error")
 	}
 }
+*/
 
 // failpow returns false from Verify for a certain block number.
 type failpow struct{ num uint64 }

+ 25 - 0
core/chain_util.go

@@ -19,6 +19,7 @@ package core
 import (
 	"bytes"
 	"math/big"
+	"time"
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -28,6 +29,11 @@ import (
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
+var (
+	blockHashPre = []byte("block-hash-")
+	blockNumPre  = []byte("block-num-")
+)
+
 // CalcDifficulty is the difficulty adjustment algorithm. It returns
 // the difficulty that a new block b should have when created at time
 // given the parent block's time and difficulty.
@@ -118,3 +124,22 @@ func WriteHead(db common.Database, block *types.Block) error {
 	}
 	return nil
 }
+
+// WriteBlock writes a block to the database
+func WriteBlock(db common.Database, block *types.Block) error {
+	tstart := time.Now()
+
+	enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block))
+	key := append(blockHashPre, block.Hash().Bytes()...)
+	err := db.Put(key, enc)
+	if err != nil {
+		glog.Fatal("db write fail:", err)
+		return err
+	}
+
+	if glog.V(logger.Debug) {
+		glog.Infof("wrote block #%v %s. Took %v\n", block.Number(), common.PP(block.Hash().Bytes()), time.Since(tstart))
+	}
+
+	return nil
+}

+ 96 - 38
core/genesis.go

@@ -19,8 +19,10 @@ package core
 import (
 	"encoding/json"
 	"fmt"
+	"io"
+	"io/ioutil"
 	"math/big"
-	"os"
+	"strings"
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/state"
@@ -28,51 +30,71 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
-// GenesisBlock creates a genesis block with the given nonce.
-func GenesisBlock(nonce uint64, db common.Database) *types.Block {
-	var accounts map[string]struct {
-		Balance string
-		Code    string
-	}
-	err := json.Unmarshal(GenesisAccounts, &accounts)
+// WriteGenesisBlock writes the genesis block to the database as block number 0
+func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*types.Block, error) {
+	contents, err := ioutil.ReadAll(reader)
 	if err != nil {
-		fmt.Println("unable to decode genesis json data:", err)
-		os.Exit(1)
+		return nil, err
 	}
-	statedb := state.New(common.Hash{}, db)
-	for addr, account := range accounts {
-		codedAddr := common.Hex2Bytes(addr)
-		accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr))
-		accountState.SetBalance(common.Big(account.Balance))
-		accountState.SetCode(common.FromHex(account.Code))
-		statedb.UpdateStateObject(accountState)
+
+	var genesis struct {
+		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
+		}
 	}
-	statedb.Sync()
 
+	if err := json.Unmarshal(contents, &genesis); err != nil {
+		return nil, err
+	}
+
+	statedb := state.New(common.Hash{}, stateDb)
+	for addr, account := range genesis.Alloc {
+		address := common.HexToAddress(addr)
+		statedb.AddBalance(address, common.String2Big(account.Balance))
+		statedb.SetCode(address, common.Hex2Bytes(account.Code))
+		for key, value := range account.Storage {
+			statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
+		}
+	}
+	statedb.SyncObjects()
+
+	difficulty := common.String2Big(genesis.Difficulty)
 	block := types.NewBlock(&types.Header{
-		Difficulty: params.GenesisDifficulty,
-		GasLimit:   params.GenesisGasLimit,
-		Nonce:      types.EncodeNonce(nonce),
+		Nonce:      types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()),
+		Time:       common.String2Big(genesis.Timestamp).Uint64(),
+		ParentHash: common.HexToHash(genesis.ParentHash),
+		Extra:      common.Hex2Bytes(genesis.ExtraData),
+		GasLimit:   common.String2Big(genesis.GasLimit),
+		Difficulty: difficulty,
+		MixDigest:  common.HexToHash(genesis.Mixhash),
+		Coinbase:   common.HexToAddress(genesis.Coinbase),
 		Root:       statedb.Root(),
 	}, nil, nil, nil)
-	block.Td = params.GenesisDifficulty
-	return block
-}
+	block.Td = difficulty
 
-var GenesisAccounts = []byte(`{
-	"0000000000000000000000000000000000000001": {"balance": "1"},
-	"0000000000000000000000000000000000000002": {"balance": "1"},
-	"0000000000000000000000000000000000000003": {"balance": "1"},
-	"0000000000000000000000000000000000000004": {"balance": "1"},
-	"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
-	"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
-	"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
-	"6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
-	"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
-	"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
-	"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
-	"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
-}`)
+	statedb.Sync()
+
+	err = WriteBlock(blockDb, block)
+	if err != nil {
+		return nil, err
+	}
+	err = WriteHead(blockDb, block)
+	if 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.
@@ -90,3 +112,39 @@ func GenesisBlockForTesting(db common.Database, addr common.Address, balance *bi
 	block.Td = params.GenesisDifficulty
 	return block
 }
+
+func WriteGenesisBlockForTesting(db common.Database, addr common.Address, balance *big.Int) *types.Block {
+	testGenesis := fmt.Sprintf(`{
+	"nonce":"0x%x",
+	"gasLimit":"0x%x",
+	"difficulty":"0x%x",
+	"alloc": {
+		"0x%x":{"balance":"0x%x"}
+	}
+}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), addr, balance.Bytes())
+	block, _ := WriteGenesisBlock(db, db, strings.NewReader(testGenesis))
+	return block
+}
+
+func WriteTestNetGenesisBlock(stateDb, blockDb common.Database, nonce uint64) (*types.Block, error) {
+	testGenesis := fmt.Sprintf(`{
+	"nonce":"0x%x",
+	"gasLimit":"0x%x",
+	"difficulty":"0x%x",
+	"alloc": {
+		"0000000000000000000000000000000000000001": {"balance": "1"},
+		"0000000000000000000000000000000000000002": {"balance": "1"},
+		"0000000000000000000000000000000000000003": {"balance": "1"},
+		"0000000000000000000000000000000000000004": {"balance": "1"},
+		"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+		"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+		"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+		"6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+		"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+		"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+		"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+		"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
+	}
+}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
+	return WriteGenesisBlock(stateDb, blockDb, strings.NewReader(testGenesis))
+}

+ 26 - 16
eth/backend.go

@@ -75,6 +75,8 @@ type Config struct {
 	Name         string
 	NetworkId    int
 	GenesisNonce int
+	GenesisFile  string
+	GenesisBlock *types.Block // used by block tests
 
 	BlockChainVersion  int
 	SkipBcVersionCheck bool // e.g. blockchain export
@@ -283,22 +285,26 @@ func New(config *Config) (*Ethereum, error) {
 		db.Meter("eth/db/extra/")
 	}
 	nodeDb := filepath.Join(config.DataDir, "nodes")
+	glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
 
-	// Perform database sanity checks
-	/*
-		// The databases were previously tied to protocol versions. Currently we
-		// are moving away from this decision as approaching Frontier. The below
-		// check was left in for now but should eventually be just dropped.
-
-		d, _ := blockDb.Get([]byte("ProtocolVersion"))
-		protov := int(common.NewValue(d).Uint())
-		if protov != config.ProtocolVersion && protov != 0 {
-			path := filepath.Join(config.DataDir, "blockchain")
-			return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, config.ProtocolVersion, path)
+	if len(config.GenesisFile) > 0 {
+		fr, err := os.Open(config.GenesisFile)
+		if err != nil {
+			return nil, err
 		}
-		saveProtocolVersion(blockDb, config.ProtocolVersion)
-	*/
-	glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
+
+		block, err := core.WriteGenesisBlock(stateDb, blockDb, fr)
+		if err != nil {
+			return nil, err
+		}
+		glog.V(logger.Info).Infof("Successfully wrote genesis block. New genesis hash = %x\n", block.Hash())
+	}
+
+	// This is for testing only.
+	if config.GenesisBlock != nil {
+		core.WriteBlock(blockDb, config.GenesisBlock)
+		core.WriteHead(blockDb, config.GenesisBlock)
+	}
 
 	if !config.SkipBcVersionCheck {
 		b, _ := blockDb.Get([]byte("BlockchainVersion"))
@@ -344,9 +350,13 @@ func New(config *Config) (*Ethereum, error) {
 	} else {
 		eth.pow = ethash.New()
 	}
-	genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
-	eth.chainManager, err = core.NewChainManager(genesis, blockDb, stateDb, extraDb, eth.pow, eth.EventMux())
+	//genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
+	eth.chainManager, err = core.NewChainManager(blockDb, stateDb, extraDb, 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
 	}
 	eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)

+ 3 - 2
eth/protocol_test.go

@@ -178,10 +178,11 @@ type testPeer struct {
 }
 
 func newProtocolManagerForTesting(txAdded chan<- []*types.Transaction) *ProtocolManager {
+	db, _ := ethdb.NewMemDatabase()
+	core.WriteTestNetGenesisBlock(db, db, 0)
 	var (
 		em       = new(event.TypeMux)
-		db, _    = ethdb.NewMemDatabase()
-		chain, _ = core.NewChainManager(core.GenesisBlock(0, db), db, db, db, core.FakePow{}, em)
+		chain, _ = core.NewChainManager(db, db, db, core.FakePow{}, em)
 		txpool   = &fakeTxPool{added: txAdded}
 		pm       = NewProtocolManager(0, em, txpool, core.FakePow{}, chain)
 	)

+ 2 - 3
tests/block_test_util.go

@@ -160,6 +160,8 @@ func runBlockTests(bt map[string]*BlockTest, skipTests []string) error {
 }
 func runBlockTest(test *BlockTest) error {
 	cfg := test.makeEthConfig()
+	cfg.GenesisBlock = test.Genesis
+
 	ethereum, err := eth.New(cfg)
 	if err != nil {
 		return err
@@ -170,9 +172,6 @@ func runBlockTest(test *BlockTest) error {
 		return err
 	}
 
-	// import the genesis block
-	ethereum.ResetWithGenesisBlock(test.Genesis)
-
 	// import pre accounts
 	statedb, err := test.InsertPreState(ethereum)
 	if err != nil {