// upgradeChainDatabase ensures that the chain database stores block split into // separate header and body entries. func upgradeChainDatabase(db ethdb.Database) error { // Short circuit if the head block is stored already as separate header and body data, err := db.Get([]byte("LastBlock")) if err != nil { return nil } head := common.BytesToHash(data) if block := core.GetBlockByHashOld(db, head); block == nil { return nil } // At least some of the database is still the old format, upgrade (skip the head block!) glog.V(logger.Info).Info("Old database detected, upgrading...") if db, ok := db.(*ethdb.LDBDatabase); ok { blockPrefix := []byte("block-hash-") for it := db.NewIterator(); it.Next(); { // Skip anything other than a combined block if !bytes.HasPrefix(it.Key(), blockPrefix) { continue } // Skip the head block (merge last to signal upgrade completion) if bytes.HasSuffix(it.Key(), head.Bytes()) { continue } // Load the block, split and serialize (order!) block := core.GetBlockByHashOld(db, common.BytesToHash(bytes.TrimPrefix(it.Key(), blockPrefix))) if err := core.WriteTd(db, block.Hash(), block.DeprecatedTd()); err != nil { return err } if err := core.WriteBody(db, block.Hash(), &types.Body{block.Transactions(), block.Uncles()}); err != nil { return err } if err := core.WriteHeader(db, block.Header()); err != nil { return err } if err := db.Delete(it.Key()); err != nil { return err } } // Lastly, upgrade the head block, disabling the upgrade mechanism current := core.GetBlockByHashOld(db, head) if err := core.WriteTd(db, current.Hash(), current.DeprecatedTd()); err != nil { return err } if err := core.WriteBody(db, current.Hash(), &types.Body{current.Transactions(), current.Uncles()}); err != nil { return err } if err := core.WriteHeader(db, current.Header()); err != nil { return err } } return nil }
func runBlockTest(homesteadBlock, daoForkBlock *big.Int, test *BlockTest) error { // import pre accounts & construct test genesis block & state root db, _ := ethdb.NewMemDatabase() if _, err := test.InsertPreState(db); err != nil { return fmt.Errorf("InsertPreState: %v", err) } core.WriteTd(db, test.Genesis.Hash(), test.Genesis.Difficulty()) core.WriteBlock(db, test.Genesis) core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64()) core.WriteHeadBlockHash(db, test.Genesis.Hash()) evmux := new(event.TypeMux) config := &core.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true} chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux) if err != nil { return err } //vm.Debug = true validBlocks, err := test.TryBlocksInsert(chain) if err != nil { return err } lastblockhash := common.HexToHash(test.lastblockhash) cmlast := chain.LastBlockHash() if lastblockhash != cmlast { return fmt.Errorf("lastblockhash validation mismatch: want: %x, have: %x", lastblockhash, cmlast) } newDB, err := chain.State() if err != nil { return err } if err = test.ValidatePostState(newDB); err != nil { return fmt.Errorf("post state validation failed: %v", err) } return test.ValidateImportedHeaders(chain, validBlocks) }
func New(config *Config) (*Expanse, error) { logger.New(config.DataDir, config.LogFile, config.Verbosity) // Let the database take 3/4 of the max open files (TODO figure out a way to get the actual limit of the open files) const dbCount = 3 ethdb.OpenFileLimit = 128 / (dbCount + 1) newdb := config.NewDB if newdb == nil { newdb = func(path string) (ethdb.Database, error) { return ethdb.NewLDBDatabase(path, config.DatabaseCache) } } // Open the chain database and perform any upgrades needed chainDb, err := newdb(filepath.Join(config.DataDir, "chaindata")) if err != nil { if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { err = fmt.Errorf("%v (check if another instance of geth is already running with the same data directory '%s')", err, config.DataDir) } return nil, fmt.Errorf("blockchain db err: %v", err) } if db, ok := chainDb.(*ethdb.LDBDatabase); ok { db.Meter("eth/db/chaindata/") } if err := upgradeChainDatabase(chainDb); err != nil { return nil, err } if err := addMipmapBloomBins(chainDb); err != nil { return nil, err } dappDb, err := newdb(filepath.Join(config.DataDir, "dapp")) if err != nil { if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { err = fmt.Errorf("%v (check if another instance of geth is already running with the same data directory '%s')", err, config.DataDir) } return nil, fmt.Errorf("dapp db err: %v", err) } if db, ok := dappDb.(*ethdb.LDBDatabase); ok { db.Meter("eth/db/dapp/") } nodeDb := filepath.Join(config.DataDir, "nodes") 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(chainDb, fr) if err != nil { return nil, err } glog.V(logger.Info).Infof("Successfully wrote genesis block. New genesis hash = %x\n", block.Hash()) } // different modes switch { case config.Olympic: glog.V(logger.Error).Infoln("Starting Olympic network") fallthrough case config.DevMode: _, err := core.WriteOlympicGenesisBlock(chainDb, 42) if err != nil { return nil, err } case config.TestNet: state.StartingNonce = 1048576 // (2**20) _, err := core.WriteTestNetGenesisBlock(chainDb, 0x6d6f7264656e) if err != nil { return nil, err } } // This is for testing only. if config.GenesisBlock != nil { core.WriteTd(chainDb, config.GenesisBlock.Hash(), config.GenesisBlock.Difficulty()) core.WriteBlock(chainDb, config.GenesisBlock) core.WriteCanonicalHash(chainDb, config.GenesisBlock.Hash(), config.GenesisBlock.NumberU64()) core.WriteHeadBlockHash(chainDb, config.GenesisBlock.Hash()) } if !config.SkipBcVersionCheck { b, _ := chainDb.Get([]byte("BlockchainVersion")) bcVersion := int(common.NewValue(b).Uint()) if bcVersion != config.BlockChainVersion && bcVersion != 0 { return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run gexp upgradedb.\n", bcVersion, config.BlockChainVersion) } saveBlockchainVersion(chainDb, config.BlockChainVersion) } glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion) exp := &Expanse{ shutdownChan: make(chan bool), chainDb: chainDb, dappDb: dappDb, eventMux: &event.TypeMux{}, accountManager: config.AccountManager, DataDir: config.DataDir, etherbase: config.Etherbase, clientVersion: config.Name, // TODO should separate from Name netVersionId: config.NetworkId, NatSpec: config.NatSpec, MinerThreads: config.MinerThreads, SolcPath: config.SolcPath, AutoDAG: config.AutoDAG, PowTest: config.PowTest, GpoMinGasPrice: config.GpoMinGasPrice, GpoMaxGasPrice: config.GpoMaxGasPrice, GpoFullBlockRatio: config.GpoFullBlockRatio, GpobaseStepDown: config.GpobaseStepDown, GpobaseStepUp: config.GpobaseStepUp, GpobaseCorrectionFactor: config.GpobaseCorrectionFactor, httpclient: httpclient.New(config.DocRoot), } if config.PowTest { glog.V(logger.Info).Infof("ethash used in test mode") exp.pow, err = ethash.NewForTesting() if err != nil { return nil, err } } else { exp.pow = ethash.New() } //genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb) exp.blockchain, err = core.NewBlockChain(chainDb, exp.pow, exp.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 } newPool := core.NewTxPool(exp.EventMux(), exp.blockchain.State, exp.blockchain.GasLimit) exp.txPool = newPool if exp.protocolManager, err = NewProtocolManager(config.FastSync, config.NetworkId, exp.eventMux, exp.txPool, exp.pow, exp.blockchain, chainDb); err != nil { return nil, err } exp.miner = miner.New(exp, exp.EventMux(), exp.pow) exp.miner.SetGasPrice(config.GasPrice) exp.miner.SetExtra(config.ExtraData) if config.Shh { exp.whisper = whisper.New() exp.shhVersionId = int(exp.whisper.Version()) } netprv, err := config.nodeKey() if err != nil { return nil, err } protocols := append([]p2p.Protocol{}, exp.protocolManager.SubProtocols...) if config.Shh { protocols = append(protocols, exp.whisper.Protocol()) } exp.net = &p2p.Server{ PrivateKey: netprv, Name: config.Name, MaxPeers: config.MaxPeers, MaxPendingPeers: config.MaxPendingPeers, Discovery: config.Discovery, Protocols: protocols, NAT: config.NAT, NoDial: !config.Dial, BootstrapNodes: config.parseBootNodes(), StaticNodes: config.parseNodes(staticNodes), TrustedNodes: config.parseNodes(trustedNodes), NodeDatabase: nodeDb, } if len(config.Port) > 0 { exp.net.ListenAddr = ":" + config.Port } vm.Debug = config.VmDebug return exp, nil }
func New(ctx *node.ServiceContext, config *Config) (*Expanse, error) { // Open the chain database and perform any upgrades needed chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles) if err != nil { return nil, err } if db, ok := chainDb.(*ethdb.LDBDatabase); ok { db.Meter("exp/db/chaindata/") } if err := upgradeChainDatabase(chainDb); err != nil { return nil, err } if err := addMipmapBloomBins(chainDb); err != nil { return nil, err } dappDb, err := ctx.OpenDatabase("dapp", config.DatabaseCache, config.DatabaseHandles) if err != nil { return nil, err } if db, ok := dappDb.(*ethdb.LDBDatabase); ok { db.Meter("exp/db/dapp/") } glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId) // 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 nil, err } glog.V(logger.Info).Infof("Successfully wrote custom genesis block: %x", 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.Difficulty()) core.WriteBlock(chainDb, config.TestGenesisBlock) core.WriteCanonicalHash(chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64()) core.WriteHeadBlockHash(chainDb, config.TestGenesisBlock.Hash()) } if !config.SkipBcVersionCheck { bcVersion := core.GetBlockChainVersion(chainDb) if bcVersion != config.BlockChainVersion && bcVersion != 0 { return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run gexp upgradedb.\n", bcVersion, config.BlockChainVersion) } core.WriteBlockChainVersion(chainDb, config.BlockChainVersion) } glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion) exp := &Expanse{ shutdownChan: make(chan bool), chainDb: chainDb, dappDb: dappDb, eventMux: ctx.EventMux, accountManager: config.AccountManager, etherbase: config.Etherbase, netVersionId: config.NetworkId, NatSpec: config.NatSpec, MinerThreads: config.MinerThreads, SolcPath: config.SolcPath, AutoDAG: config.AutoDAG, PowTest: config.PowTest, GpoMinGasPrice: config.GpoMinGasPrice, GpoMaxGasPrice: config.GpoMaxGasPrice, GpoFullBlockRatio: config.GpoFullBlockRatio, GpobaseStepDown: config.GpobaseStepDown, GpobaseStepUp: config.GpobaseStepUp, GpobaseCorrectionFactor: config.GpobaseCorrectionFactor, httpclient: httpclient.New(config.DocRoot), } switch { case config.PowTest: glog.V(logger.Info).Infof("ethash used in test mode") exp.pow, err = ethash.NewForTesting() if err != nil { return nil, err } case config.PowShared: glog.V(logger.Info).Infof("ethash used in shared mode") exp.pow = ethash.NewShared() default: exp.pow = ethash.New() } // 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)) if genesis == nil { genesis, err = core.WriteDefaultGenesisBlock(chainDb) if err != nil { return nil, err } glog.V(logger.Info).Infoln("WARNING: Wrote default expanse genesis block") } if config.ChainConfig == nil { return nil, errors.New("missing chain config") } core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig) exp.chainConfig = config.ChainConfig exp.chainConfig.VmConfig = vm.Config{ EnableJit: config.EnableJit, ForceJit: config.ForceJit, } exp.blockchain, err = core.NewBlockChain(chainDb, exp.chainConfig, exp.pow, exp.EventMux()) 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 } exp.gpo = NewGasPriceOracle(exp) newPool := core.NewTxPool(exp.chainConfig, exp.EventMux(), exp.blockchain.State, exp.blockchain.GasLimit) exp.txPool = newPool if exp.protocolManager, err = NewProtocolManager(exp.chainConfig, config.FastSync, config.NetworkId, exp.eventMux, exp.txPool, exp.pow, exp.blockchain, chainDb); err != nil { return nil, err } exp.miner = miner.New(exp, exp.chainConfig, exp.EventMux(), exp.pow) exp.miner.SetGasPrice(config.GasPrice) exp.miner.SetExtra(config.ExtraData) return exp, nil }