From a32c51effda8682b292d04863aae7811f78abf7e Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 10 Jul 2015 14:29:40 +0200 Subject: [PATCH] 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. --- cmd/geth/js_test.go | 6 +- cmd/geth/main.go | 1 + cmd/utils/flags.go | 9 +- common/natspec/natspec_e2e_test.go | 8 +- core/bench_test.go | 4 +- core/block_processor_test.go | 4 +- core/chain_makers.go | 4 +- core/chain_makers_test.go | 4 +- core/chain_manager.go | 81 +++++++++-------- core/chain_manager_test.go | 46 +++++----- core/chain_util.go | 25 ++++++ core/genesis.go | 136 ++++++++++++++++++++--------- eth/backend.go | 44 ++++++---- eth/protocol_test.go | 5 +- tests/block_test_util.go | 5 +- 15 files changed, 244 insertions(+), 138 deletions(-) diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index db2c5ca03..ffd164d27 100644 --- a/cmd/geth/js_test.go +++ b/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 := ð.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) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 51a0defaa..6acdff9ad 100644 --- a/cmd/geth/main.go +++ b/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, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 903c97e71..73bdb935a 100644 --- a/cmd/utils/flags.go +++ b/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) } diff --git a/common/natspec/natspec_e2e_test.go b/common/natspec/natspec_e2e_test.go index 0cbe040c0..395cef3c7 100644 --- a/common/natspec/natspec_e2e_test.go +++ b/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(ð.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 { diff --git a/core/bench_test.go b/core/bench_test.go index 645df48c2..018d27d8d 100644 --- a/core/bench_test.go +++ b/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() diff --git a/core/block_processor_test.go b/core/block_processor_test.go index 4250b897b..dab5be974 100644 --- a/core/block_processor_test.go +++ b/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) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 501fe7a92..93f381e78 100644 --- a/core/chain_makers.go +++ b/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() diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 2f001be9b..ddd54d217 100644 --- a/core/chain_makers_test.go +++ b/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) diff --git a/core/chain_manager.go b/core/chain_manager.go index 3c5eb0e8a..8fa13ddec 100644 --- a/core/chain_manager.go +++ b/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, + blockDb: blockDb, + stateDb: stateDb, + extraDb: extraDb, + 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 = 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 } - bc.genesisBlock = genesis - bc.setLastState() // 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()) diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index 92f080f01..5f8cfd4f4 100644 --- a/core/chain_manager_test.go +++ b/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 } diff --git a/core/chain_util.go b/core/chain_util.go index 7e3d8eba8..253396ed7 100644 --- a/core/chain_util.go +++ b/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 +} diff --git a/core/genesis.go b/core/genesis.go index 2d369aae0..8c9a21c7e 100644 --- a/core/genesis.go +++ b/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) - } - statedb.Sync() + 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 + } + } + + 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)) +} diff --git a/eth/backend.go b/eth/backend.go index 9c661ad54..e7250c019 100644 --- a/eth/backend.go +++ b/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,23 +285,27 @@ func New(config *Config) (*Ethereum, error) { db.Meter("eth/db/extra/") } nodeDb := filepath.Join(config.DataDir, "nodes") - - // 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) - } - saveProtocolVersion(blockDb, config.ProtocolVersion) - */ glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId) + if len(config.GenesisFile) > 0 { + fr, err := os.Open(config.GenesisFile) + if err != nil { + return nil, err + } + + 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")) bcVersion := int(common.NewValue(b).Uint()) @@ -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) diff --git a/eth/protocol_test.go b/eth/protocol_test.go index 686380b40..77941852f 100644 --- a/eth/protocol_test.go +++ b/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) ) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index e624cced0..f7c2208b3 100644 --- a/tests/block_test_util.go +++ b/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 {