github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/eth/backend.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package eth implements the Ethereum protocol. 18 package eth 19 20 import ( 21 "bytes" 22 "errors" 23 "fmt" 24 "math/big" 25 "os" 26 "path/filepath" 27 "strconv" 28 "sync" 29 "time" 30 31 "github.com/ethereumproject/ethash" 32 "github.com/ethereumproject/go-ethereum/accounts" 33 "github.com/ethereumproject/go-ethereum/common" 34 "github.com/ethereumproject/go-ethereum/common/compiler" 35 "github.com/ethereumproject/go-ethereum/common/httpclient" 36 "github.com/ethereumproject/go-ethereum/common/registrar/ethreg" 37 "github.com/ethereumproject/go-ethereum/core" 38 "github.com/ethereumproject/go-ethereum/core/types" 39 "github.com/ethereumproject/go-ethereum/eth/downloader" 40 "github.com/ethereumproject/go-ethereum/eth/filters" 41 "github.com/ethereumproject/go-ethereum/ethdb" 42 "github.com/ethereumproject/go-ethereum/event" 43 "github.com/ethereumproject/go-ethereum/logger" 44 "github.com/ethereumproject/go-ethereum/logger/glog" 45 "github.com/ethereumproject/go-ethereum/miner" 46 "github.com/ethereumproject/go-ethereum/node" 47 "github.com/ethereumproject/go-ethereum/p2p" 48 "github.com/ethereumproject/go-ethereum/rlp" 49 "github.com/ethereumproject/go-ethereum/rpc" 50 ) 51 52 const ( 53 epochLength = 30000 54 ethashRevision = 23 55 56 autoDAGcheckInterval = 10 * time.Hour 57 autoDAGepochHeight = epochLength / 2 58 ) 59 60 type Config struct { 61 ChainConfig *core.ChainConfig // chain configuration 62 63 NetworkId int // Network ID to use for selecting peers to connect to 64 Genesis *core.GenesisDump 65 FastSync bool // Enables the state download based fast synchronisation algorithm 66 MaxPeers int 67 68 BlockChainVersion int 69 SkipBcVersionCheck bool // e.g. blockchain export 70 DatabaseCache int 71 DatabaseHandles int 72 73 NatSpec bool 74 DocRoot string 75 AutoDAG bool 76 PowTest bool 77 PowShared bool 78 79 AccountManager *accounts.Manager 80 Etherbase common.Address 81 GasPrice *big.Int 82 MinerThreads int 83 SolcPath string 84 85 UseAddrTxIndex bool 86 87 GpoMinGasPrice *big.Int 88 GpoMaxGasPrice *big.Int 89 GpoFullBlockRatio int 90 GpobaseStepDown int 91 GpobaseStepUp int 92 GpobaseCorrectionFactor int 93 94 TestGenesisBlock *types.Block // Genesis block to seed the chain database with (testing only!) 95 TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!) 96 } 97 98 type Ethereum struct { 99 config *Config 100 chainConfig *core.ChainConfig 101 // Channel for shutting down the ethereum 102 shutdownChan chan bool 103 104 // DB interfaces 105 chainDb ethdb.Database // Block chain database 106 dappDb ethdb.Database // Dapp database 107 indexesDb ethdb.Database // Indexes database (optional -- eg. add-tx indexes) 108 109 // Handlers 110 txPool *core.TxPool 111 txMu sync.Mutex 112 blockchain *core.BlockChain 113 accountManager *accounts.Manager 114 pow *ethash.Ethash 115 protocolManager *ProtocolManager 116 SolcPath string 117 solc *compiler.Solidity 118 gpo *GasPriceOracle 119 120 GpoMinGasPrice *big.Int 121 GpoMaxGasPrice *big.Int 122 GpoFullBlockRatio int 123 GpobaseStepDown int 124 GpobaseStepUp int 125 GpobaseCorrectionFactor int 126 127 httpclient *httpclient.HTTPClient 128 129 eventMux *event.TypeMux 130 miner *miner.Miner 131 132 Mining bool 133 MinerThreads int 134 NatSpec bool 135 AutoDAG bool 136 PowTest bool 137 autodagquit chan bool 138 etherbase common.Address 139 netVersionId int 140 netRPCService *PublicNetAPI 141 } 142 143 func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { 144 // Open the chain database and perform any upgrades needed 145 chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles) 146 if err != nil { 147 return nil, err 148 } 149 if err := upgradeChainDatabase(chainDb); err != nil { 150 return nil, err 151 } 152 if err := addMipmapBloomBins(chainDb); err != nil { 153 return nil, err 154 } 155 156 dappDb, err := ctx.OpenDatabase("dapp", config.DatabaseCache, config.DatabaseHandles) 157 if err != nil { 158 return nil, err 159 } 160 161 glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v, Chain Id: %v", ProtocolVersions, config.NetworkId, config.ChainConfig.GetChainID()) 162 glog.D(logger.Warn).Infof("Protocol Versions: %v, Network Id: %v, Chain Id: %v", logger.ColorGreen(fmt.Sprintf("%v", ProtocolVersions)), logger.ColorGreen(strconv.Itoa(config.NetworkId)), logger.ColorGreen(func() string { 163 cid := config.ChainConfig.GetChainID().String() 164 if cid == "0" { 165 cid = "not set" 166 } 167 return cid 168 }())) 169 170 // Load up any custom genesis block if requested 171 if config.Genesis != nil { 172 _, err := core.WriteGenesisBlock(chainDb, config.Genesis) 173 if err != nil { 174 return nil, err 175 } 176 } 177 178 // Load up a test setup if directly injected 179 if config.TestGenesisState != nil { 180 chainDb = config.TestGenesisState 181 } 182 if config.TestGenesisBlock != nil { 183 core.WriteTd(chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.Difficulty()) 184 core.WriteBlock(chainDb, config.TestGenesisBlock) 185 core.WriteCanonicalHash(chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64()) 186 core.WriteHeadBlockHash(chainDb, config.TestGenesisBlock.Hash()) 187 } 188 189 if !config.SkipBcVersionCheck { 190 bcVersion := core.GetBlockChainVersion(chainDb) 191 if bcVersion != config.BlockChainVersion && bcVersion != 0 { 192 return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, config.BlockChainVersion) 193 } 194 core.WriteBlockChainVersion(chainDb, config.BlockChainVersion) 195 } 196 glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion) 197 198 eth := &Ethereum{ 199 config: config, 200 shutdownChan: make(chan bool), 201 chainDb: chainDb, 202 dappDb: dappDb, 203 eventMux: ctx.EventMux, 204 accountManager: config.AccountManager, 205 etherbase: config.Etherbase, 206 netVersionId: config.NetworkId, 207 NatSpec: config.NatSpec, 208 MinerThreads: config.MinerThreads, 209 SolcPath: config.SolcPath, 210 AutoDAG: config.AutoDAG, 211 PowTest: config.PowTest, 212 GpoMinGasPrice: config.GpoMinGasPrice, 213 GpoMaxGasPrice: config.GpoMaxGasPrice, 214 GpoFullBlockRatio: config.GpoFullBlockRatio, 215 GpobaseStepDown: config.GpobaseStepDown, 216 GpobaseStepUp: config.GpobaseStepUp, 217 GpobaseCorrectionFactor: config.GpobaseCorrectionFactor, 218 httpclient: httpclient.New(config.DocRoot), 219 } 220 switch { 221 case config.PowTest: 222 glog.V(logger.Info).Infof("Consensus: ethash used in test mode") 223 eth.pow, err = ethash.NewForTesting() 224 if err != nil { 225 return nil, err 226 } 227 case config.PowShared: 228 glog.V(logger.Info).Infof("Consensus: ethash used in shared mode") 229 eth.pow = ethash.NewShared() 230 231 default: 232 eth.pow = ethash.New() 233 } 234 235 // Initialize indexes db if enabled 236 // Blockchain will be assigned the db and atx enabled after blockchain is initialized below. 237 var indexesDb ethdb.Database 238 if config.UseAddrTxIndex { 239 // TODO: these are arbitrary numbers I just made up. Optimize? 240 // The reason these numbers are different than the atxi-build command is because for "appending" (vs. building) 241 // the atxi database should require far fewer resources since application performance is limited primarily by block import (chaindata db). 242 ethdb.SetCacheRatio("chaindata", 0.95) 243 ethdb.SetHandleRatio("chaindata", 0.95) 244 ethdb.SetCacheRatio("indexes", 0.05) 245 ethdb.SetHandleRatio("indexes", 0.05) 246 indexesDb, err = ctx.OpenDatabase("indexes", config.DatabaseCache, config.DatabaseCache) 247 if err != nil { 248 return nil, err 249 } 250 eth.indexesDb = indexesDb 251 } 252 253 // load the genesis block or write a new one if no genesis 254 // block is present in the database. 255 genesis := core.GetBlock(chainDb, core.GetCanonicalHash(chainDb, 0)) 256 if genesis == nil { 257 genesis, err = core.WriteGenesisBlock(chainDb, core.DefaultConfigMainnet.Genesis) 258 if err != nil { 259 return nil, err 260 } 261 glog.V(logger.Info).Infof("Successfully wrote default ethereum mainnet genesis block: %s", logger.ColorGreen(genesis.Hash().Hex())) 262 glog.D(logger.Warn).Infof("Wrote mainnet genesis block: %s", logger.ColorGreen(genesis.Hash().Hex())) 263 } 264 265 // Log genesis block information. 266 var genName string 267 if fmt.Sprintf("%x", genesis.Hash()) == "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303" { 268 genName = "morden testnet" 269 } else if fmt.Sprintf("%x", genesis.Hash()) == "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" { 270 genName = "mainnet" 271 } else { 272 genName = "custom" 273 } 274 glog.V(logger.Info).Infof("Successfully established %s genesis block: %s", genName, genesis.Hash().Hex()) 275 glog.D(logger.Warn).Infof("Genesis block: %s (%s)", logger.ColorGreen(genesis.Hash().Hex()), genName) 276 277 if config.ChainConfig == nil { 278 return nil, errors.New("missing chain config") 279 } 280 281 eth.chainConfig = config.ChainConfig 282 283 eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux()) 284 if err != nil { 285 if err == core.ErrNoGenesis { 286 return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`) 287 } 288 return nil, err 289 } 290 // Configure enabled atxi for blockchain 291 if config.UseAddrTxIndex { 292 eth.blockchain.SetAtxi(&core.AtxiT{ 293 Db: eth.indexesDb, 294 }) 295 } 296 297 eth.gpo = NewGasPriceOracle(eth) 298 299 newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) 300 eth.txPool = newPool 301 302 m := downloader.FullSync 303 if config.FastSync { 304 m = downloader.FastSync 305 } 306 if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, m, uint64(config.NetworkId), eth.eventMux, eth.txPool, eth.pow, eth.blockchain, chainDb); err != nil { 307 return nil, err 308 } 309 eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.pow) 310 if err = eth.miner.SetGasPrice(config.GasPrice); err != nil { 311 return nil, err 312 } 313 314 return eth, nil 315 } 316 317 // APIs returns the collection of RPC services the ethereum package offers. 318 // NOTE, some of these services probably need to be moved to somewhere else. 319 func (s *Ethereum) APIs() []rpc.API { 320 return []rpc.API{ 321 { 322 Namespace: "eth", 323 Version: "1.0", 324 Service: NewPublicEthereumAPI(s), 325 Public: true, 326 }, { 327 Namespace: "eth", 328 Version: "1.0", 329 Service: NewPublicAccountAPI(s.accountManager), 330 Public: true, 331 }, { 332 Namespace: "personal", 333 Version: "1.0", 334 Service: NewPrivateAccountAPI(s), 335 Public: false, 336 }, { 337 Namespace: "eth", 338 Version: "1.0", 339 Service: NewPublicBlockChainAPI(s.chainConfig, s.blockchain, s.miner, s.chainDb, s.gpo, s.eventMux, s.accountManager), 340 Public: true, 341 }, { 342 Namespace: "eth", 343 Version: "1.0", 344 Service: NewPublicTransactionPoolAPI(s), 345 Public: true, 346 }, { 347 Namespace: "eth", 348 Version: "1.0", 349 Service: NewPublicMinerAPI(s), 350 Public: true, 351 }, { 352 Namespace: "eth", 353 Version: "1.0", 354 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 355 Public: true, 356 }, { 357 Namespace: "miner", 358 Version: "1.0", 359 Service: NewPrivateMinerAPI(s), 360 Public: false, 361 }, { 362 Namespace: "txpool", 363 Version: "1.0", 364 Service: NewPublicTxPoolAPI(s), 365 Public: true, 366 }, { 367 Namespace: "eth", 368 Version: "1.0", 369 Service: filters.NewPublicFilterAPI(s.chainDb, s.eventMux), 370 Public: true, 371 }, { 372 Namespace: "admin", 373 Version: "1.0", 374 Service: NewPrivateAdminAPI(s), 375 }, { 376 Namespace: "debug", 377 Version: "1.0", 378 Service: NewPublicDebugAPI(s), 379 Public: true, 380 }, { 381 Namespace: "net", 382 Version: "1.0", 383 Service: s.netRPCService, 384 Public: true, 385 }, { 386 Namespace: "admin", 387 Version: "1.0", 388 Service: ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager), 389 }, { 390 Namespace: "geth", 391 Version: "1.0", 392 Service: NewPublicGethAPI(s), 393 Public: true, 394 }, 395 } 396 } 397 398 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 399 s.blockchain.ResetWithGenesisBlock(gb) 400 } 401 402 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 403 eb = s.etherbase 404 if eb.IsEmpty() { 405 firstAccount, err := s.AccountManager().AccountByIndex(0) 406 eb = firstAccount.Address 407 if err != nil { 408 return eb, fmt.Errorf("etherbase address must be explicitly specified") 409 } 410 } 411 return eb, nil 412 } 413 414 // set in js console via admin interface or wrapper from cli flags 415 func (self *Ethereum) SetEtherbase(etherbase common.Address) { 416 self.etherbase = etherbase 417 self.miner.SetEtherbase(etherbase) 418 } 419 420 func (s *Ethereum) StopMining() { s.miner.Stop() } 421 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 422 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 423 424 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 425 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 426 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 427 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 428 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 429 func (s *Ethereum) DappDb() ethdb.Database { return s.dappDb } 430 func (s *Ethereum) IsListening() bool { return true } // Always listening 431 func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 432 func (s *Ethereum) NetVersion() int { return s.netVersionId } 433 func (s *Ethereum) ChainConfig() *core.ChainConfig { return s.chainConfig } 434 func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 435 436 // Protocols implements node.Service, returning all the currently configured 437 // network protocols to start. 438 func (s *Ethereum) Protocols() []p2p.Protocol { 439 return s.protocolManager.SubProtocols 440 } 441 442 // Start implements node.Service, starting all internal goroutines needed by the 443 // Ethereum protocol implementation. 444 func (s *Ethereum) Start(srvr *p2p.Server) error { 445 if s.AutoDAG { 446 s.StartAutoDAG() 447 } 448 s.protocolManager.Start(s.config.MaxPeers) 449 s.netRPCService = NewPublicNetAPI(srvr, s.NetVersion()) 450 return nil 451 } 452 453 // Stop implements node.Service, terminating all internal goroutines used by the 454 // Ethereum protocol. 455 func (s *Ethereum) Stop() error { 456 s.blockchain.Stop() 457 s.protocolManager.Stop() 458 s.txPool.Stop() 459 s.miner.Stop() 460 s.eventMux.Stop() 461 462 s.StopAutoDAG() 463 464 s.chainDb.Close() 465 s.dappDb.Close() 466 close(s.shutdownChan) 467 468 return nil 469 } 470 471 // This function will wait for a shutdown and resumes main thread execution 472 func (s *Ethereum) WaitForShutdown() { 473 <-s.shutdownChan 474 } 475 476 // StartAutoDAG() spawns a go routine that checks the DAG every autoDAGcheckInterval 477 // by default that is 10 times per epoch 478 // in epoch n, if we past autoDAGepochHeight within-epoch blocks, 479 // it calls ethash.MakeDAG to pregenerate the DAG for the next epoch n+1 480 // if it does not exist yet as well as remove the DAG for epoch n-1 481 // the loop quits if autodagquit channel is closed, it can safely restart and 482 // stop any number of times. 483 // For any more sophisticated pattern of DAG generation, use CLI subcommand 484 // makedag 485 func (self *Ethereum) StartAutoDAG() { 486 if self.autodagquit != nil { 487 return // already started 488 } 489 go func() { 490 glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG ON (ethash dir: %s)", ethash.DefaultDir) 491 var nextEpoch uint64 492 timer := time.After(0) 493 self.autodagquit = make(chan bool) 494 for { 495 select { 496 case <-timer: 497 glog.V(logger.Info).Infof("checking DAG (ethash dir: %s)", ethash.DefaultDir) 498 currentBlock := self.BlockChain().CurrentBlock().NumberU64() 499 thisEpoch := currentBlock / epochLength 500 if nextEpoch <= thisEpoch { 501 if currentBlock%epochLength > autoDAGepochHeight { 502 if thisEpoch > 0 { 503 previousDag, previousDagFull := dagFiles(thisEpoch - 1) 504 os.Remove(filepath.Join(ethash.DefaultDir, previousDag)) 505 os.Remove(filepath.Join(ethash.DefaultDir, previousDagFull)) 506 glog.V(logger.Info).Infof("removed DAG for epoch %d (%s)", thisEpoch-1, previousDag) 507 } 508 nextEpoch = thisEpoch + 1 509 dag, _ := dagFiles(nextEpoch) 510 if _, err := os.Stat(dag); os.IsNotExist(err) { 511 glog.V(logger.Info).Infof("Pregenerating DAG for epoch %d (%s)", nextEpoch, dag) 512 err := ethash.MakeDAG(nextEpoch*epochLength, "") // "" -> ethash.DefaultDir 513 if err != nil { 514 glog.V(logger.Error).Infof("Error generating DAG for epoch %d (%s)", nextEpoch, dag) 515 return 516 } 517 } else { 518 glog.V(logger.Error).Infof("DAG for epoch %d (%s)", nextEpoch, dag) 519 } 520 } 521 } 522 timer = time.After(autoDAGcheckInterval) 523 case <-self.autodagquit: 524 return 525 } 526 } 527 }() 528 } 529 530 // stopAutoDAG stops automatic DAG pregeneration by quitting the loop 531 func (self *Ethereum) StopAutoDAG() { 532 if self.autodagquit != nil { 533 close(self.autodagquit) 534 self.autodagquit = nil 535 } 536 glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG: OFF (ethash dir: %s)", ethash.DefaultDir) 537 } 538 539 // HTTPClient returns the light http client used for fetching offchain docs 540 // (natspec, source for verification) 541 func (self *Ethereum) HTTPClient() *httpclient.HTTPClient { 542 return self.httpclient 543 } 544 545 func (self *Ethereum) Solc() (*compiler.Solidity, error) { 546 var err error 547 if self.solc == nil { 548 self.solc, err = compiler.New(self.SolcPath) 549 } 550 return self.solc, err 551 } 552 553 // set in js console via admin interface or wrapper from cli flags 554 func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) { 555 self.SolcPath = solcPath 556 self.solc = nil 557 return self.Solc() 558 } 559 560 // dagFiles(epoch) returns the two alternative DAG filenames (not a path) 561 // 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])> 562 func dagFiles(epoch uint64) (string, string) { 563 seedHash, _ := ethash.GetSeedHash(epoch * epochLength) 564 dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8]) 565 return dag, "full-R" + dag 566 } 567 568 // upgradeChainDatabase ensures that the chain database stores block split into 569 // separate header and body entries. 570 func upgradeChainDatabase(db ethdb.Database) error { 571 // Short circuit if the head block is stored already as separate header and body 572 data, err := db.Get([]byte("LastBlock")) 573 if err != nil { 574 return nil 575 } 576 head := common.BytesToHash(data) 577 578 if block := core.GetBlockByHashOld(db, head); block == nil { 579 return nil 580 } 581 // At least some of the database is still the old format, upgrade (skip the head block!) 582 glog.V(logger.Info).Info("Old database detected, upgrading...") 583 584 if db, ok := db.(*ethdb.LDBDatabase); ok { 585 blockPrefix := []byte("block-hash-") 586 for it := db.NewIterator(); it.Next(); { 587 // Skip anything other than a combined block 588 if !bytes.HasPrefix(it.Key(), blockPrefix) { 589 continue 590 } 591 // Skip the head block (merge last to signal upgrade completion) 592 if bytes.HasSuffix(it.Key(), head.Bytes()) { 593 continue 594 } 595 // Load the block, split and serialize (order!) 596 block := core.GetBlockByHashOld(db, common.BytesToHash(bytes.TrimPrefix(it.Key(), blockPrefix))) 597 598 if err := core.WriteTd(db, block.Hash(), block.DeprecatedTd()); err != nil { 599 return err 600 } 601 if err := core.WriteBody(db, block.Hash(), block.Body()); err != nil { 602 return err 603 } 604 if err := core.WriteHeader(db, block.Header()); err != nil { 605 return err 606 } 607 if err := db.Delete(it.Key()); err != nil { 608 return err 609 } 610 } 611 // Lastly, upgrade the head block, disabling the upgrade mechanism 612 current := core.GetBlockByHashOld(db, head) 613 614 if err := core.WriteTd(db, current.Hash(), current.DeprecatedTd()); err != nil { 615 return err 616 } 617 if err := core.WriteBody(db, current.Hash(), current.Body()); err != nil { 618 return err 619 } 620 if err := core.WriteHeader(db, current.Header()); err != nil { 621 return err 622 } 623 } 624 return nil 625 } 626 627 func addMipmapBloomBins(db ethdb.Database) (err error) { 628 const mipmapVersion uint = 2 629 630 // check if the version is set. We ignore data for now since there's 631 // only one version so we can easily ignore it for now 632 var data []byte 633 data, _ = db.Get([]byte("setting-mipmap-version")) 634 if len(data) > 0 { 635 var version uint 636 if err := rlp.DecodeBytes(data, &version); err == nil && version == mipmapVersion { 637 return nil 638 } 639 } 640 641 defer func() { 642 if err == nil { 643 var val []byte 644 val, err = rlp.EncodeToBytes(mipmapVersion) 645 if err == nil { 646 err = db.Put([]byte("setting-mipmap-version"), val) 647 } 648 return 649 } 650 }() 651 latestBlock := core.GetBlock(db, core.GetHeadBlockHash(db)) 652 if latestBlock == nil { // clean database 653 return 654 } 655 656 tstart := time.Now() 657 glog.V(logger.Info).Infoln("upgrading db log bloom bins") 658 for i := uint64(0); i <= latestBlock.NumberU64(); i++ { 659 hash := core.GetCanonicalHash(db, i) 660 if (hash == common.Hash{}) { 661 return fmt.Errorf("chain db corrupted. Could not find block %d.", i) 662 } 663 err := core.WriteMipmapBloom(db, i, core.GetBlockReceipts(db, hash)) 664 if err != nil { 665 return err 666 } 667 } 668 glog.V(logger.Info).Infoln("upgrade completed in", time.Since(tstart)) 669 return nil 670 }