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  }