github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/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  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"regexp"
    25  	"strings"
    26  	"sync"
    27  	"time"
    28  
    29  	"github.com/ethereum/go-ethereum/accounts"
    30  	"github.com/ethereum/go-ethereum/common"
    31  	"github.com/ethereum/go-ethereum/core"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/core/vm"
    34  	"github.com/ethereum/go-ethereum/eth/downloader"
    35  	"github.com/ethereum/go-ethereum/eth/filters"
    36  	"github.com/ethereum/go-ethereum/eth/gasprice"
    37  	"github.com/ethereum/go-ethereum/ethdb"
    38  	"github.com/ethereum/go-ethereum/event"
    39  	"github.com/ethereum/go-ethereum/internal/ethapi"
    40  	"github.com/ethereum/go-ethereum/log"
    41  	"github.com/ethereum/go-ethereum/miner"
    42  	"github.com/ethereum/go-ethereum/node"
    43  	"github.com/ethereum/go-ethereum/p2p"
    44  	"github.com/ethereum/go-ethereum/params"
    45  	"github.com/ethereum/go-ethereum/pow"
    46  	"github.com/ethereum/go-ethereum/rpc"
    47  )
    48  
    49  const (
    50  	epochLength    = 30000
    51  	ethashRevision = 23
    52  
    53  	autoDAGcheckInterval = 10 * time.Hour
    54  	autoDAGepochHeight   = epochLength / 2
    55  )
    56  
    57  var (
    58  	datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true}
    59  	portInUseErrRE     = regexp.MustCompile("address already in use")
    60  )
    61  
    62  type Config struct {
    63  	ChainConfig *params.ChainConfig // chain configuration
    64  
    65  	NetworkId  int    // Network ID to use for selecting peers to connect to
    66  	Genesis    string // Genesis JSON to seed the chain database with
    67  	FastSync   bool   // Enables the state download based fast synchronisation algorithm
    68  	LightMode  bool   // Running in light client mode
    69  	LightServ  int    // Maximum percentage of time allowed for serving LES requests
    70  	LightPeers int    // Maximum number of LES client peers
    71  	MaxPeers   int    // Maximum number of global peers
    72  
    73  	SkipBcVersionCheck bool // e.g. blockchain export
    74  	DatabaseCache      int
    75  	DatabaseHandles    int
    76  
    77  	DocRoot   string
    78  	PowFake   bool
    79  	PowTest   bool
    80  	PowShared bool
    81  	ExtraData []byte
    82  
    83  	EthashCacheDir       string
    84  	EthashCachesInMem    int
    85  	EthashCachesOnDisk   int
    86  	EthashDatasetDir     string
    87  	EthashDatasetsInMem  int
    88  	EthashDatasetsOnDisk int
    89  
    90  	Etherbase    common.Address
    91  	GasPrice     *big.Int
    92  	MinerThreads int
    93  	SolcPath     string
    94  
    95  	GpoMinGasPrice          *big.Int
    96  	GpoMaxGasPrice          *big.Int
    97  	GpoFullBlockRatio       int
    98  	GpobaseStepDown         int
    99  	GpobaseStepUp           int
   100  	GpobaseCorrectionFactor int
   101  
   102  	EnablePreimageRecording bool
   103  
   104  	TestGenesisBlock *types.Block   // Genesis block to seed the chain database with (testing only!)
   105  	TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!)
   106  }
   107  
   108  type LesServer interface {
   109  	Start(srvr *p2p.Server)
   110  	Stop()
   111  	Protocols() []p2p.Protocol
   112  }
   113  
   114  // Ethereum implements the Ethereum full node service.
   115  type Ethereum struct {
   116  	chainConfig *params.ChainConfig
   117  	// Channel for shutting down the service
   118  	shutdownChan  chan bool // Channel for shutting down the ethereum
   119  	stopDbUpgrade func()    // stop chain db sequential key upgrade
   120  	// Handlers
   121  	txPool          *core.TxPool
   122  	txMu            sync.Mutex
   123  	blockchain      *core.BlockChain
   124  	protocolManager *ProtocolManager
   125  	lesServer       LesServer
   126  	// DB interfaces
   127  	chainDb ethdb.Database // Block chain database
   128  
   129  	eventMux       *event.TypeMux
   130  	pow            pow.PoW
   131  	accountManager *accounts.Manager
   132  
   133  	ApiBackend *EthApiBackend
   134  
   135  	miner        *miner.Miner
   136  	Mining       bool
   137  	MinerThreads int
   138  	etherbase    common.Address
   139  	solcPath     string
   140  
   141  	netVersionId  int
   142  	netRPCService *ethapi.PublicNetAPI
   143  }
   144  
   145  func (s *Ethereum) AddLesServer(ls LesServer) {
   146  	s.lesServer = ls
   147  	s.protocolManager.lesServer = ls
   148  }
   149  
   150  // New creates a new Ethereum object (including the
   151  // initialisation of the common Ethereum object)
   152  func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
   153  	chainDb, err := CreateDB(ctx, config, "chaindata")
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	stopDbUpgrade := upgradeSequentialKeys(chainDb)
   158  	if err := SetupGenesisBlock(&chainDb, config); err != nil {
   159  		return nil, err
   160  	}
   161  	eth := &Ethereum{
   162  		chainDb:        chainDb,
   163  		eventMux:       ctx.EventMux,
   164  		accountManager: ctx.AccountManager,
   165  		pow:            CreatePoW(ctx, config),
   166  		shutdownChan:   make(chan bool),
   167  		stopDbUpgrade:  stopDbUpgrade,
   168  		netVersionId:   config.NetworkId,
   169  		etherbase:      config.Etherbase,
   170  		MinerThreads:   config.MinerThreads,
   171  		solcPath:       config.SolcPath,
   172  	}
   173  
   174  	if err := addMipmapBloomBins(chainDb); err != nil {
   175  		return nil, err
   176  	}
   177  	log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId)
   178  
   179  	if !config.SkipBcVersionCheck {
   180  		bcVersion := core.GetBlockChainVersion(chainDb)
   181  		if bcVersion != core.BlockChainVersion && bcVersion != 0 {
   182  			return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, core.BlockChainVersion)
   183  		}
   184  		core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
   185  	}
   186  
   187  	// load the genesis block or write a new one if no genesis
   188  	// block is prenent in the database.
   189  	genesis := core.GetBlock(chainDb, core.GetCanonicalHash(chainDb, 0), 0)
   190  	if genesis == nil {
   191  		genesis, err = core.WriteDefaultGenesisBlock(chainDb)
   192  		if err != nil {
   193  			return nil, err
   194  		}
   195  		log.Warn("Wrote default Ethereum genesis block")
   196  	}
   197  
   198  	if config.ChainConfig == nil {
   199  		return nil, errors.New("missing chain config")
   200  	}
   201  	core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
   202  
   203  	eth.chainConfig = config.ChainConfig
   204  
   205  	log.Info("Initialised chain configuration", "config", eth.chainConfig)
   206  
   207  	eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux(), vm.Config{EnablePreimageRecording: config.EnablePreimageRecording})
   208  	if err != nil {
   209  		if err == core.ErrNoGenesis {
   210  			return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`)
   211  		}
   212  		return nil, err
   213  	}
   214  	newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
   215  	eth.txPool = newPool
   216  
   217  	maxPeers := config.MaxPeers
   218  	if config.LightServ > 0 {
   219  		// if we are running a light server, limit the number of ETH peers so that we reserve some space for incoming LES connections
   220  		// temporary solution until the new peer connectivity API is finished
   221  		halfPeers := maxPeers / 2
   222  		maxPeers -= config.LightPeers
   223  		if maxPeers < halfPeers {
   224  			maxPeers = halfPeers
   225  		}
   226  	}
   227  
   228  	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.FastSync, config.NetworkId, maxPeers, eth.eventMux, eth.txPool, eth.pow, eth.blockchain, chainDb); err != nil {
   229  		return nil, err
   230  	}
   231  	eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.pow)
   232  	eth.miner.SetGasPrice(config.GasPrice)
   233  	eth.miner.SetExtra(config.ExtraData)
   234  
   235  	gpoParams := &gasprice.GpoParams{
   236  		GpoMinGasPrice:          config.GpoMinGasPrice,
   237  		GpoMaxGasPrice:          config.GpoMaxGasPrice,
   238  		GpoFullBlockRatio:       config.GpoFullBlockRatio,
   239  		GpobaseStepDown:         config.GpobaseStepDown,
   240  		GpobaseStepUp:           config.GpobaseStepUp,
   241  		GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
   242  	}
   243  	gpo := gasprice.NewGasPriceOracle(eth.blockchain, chainDb, eth.eventMux, gpoParams)
   244  	eth.ApiBackend = &EthApiBackend{eth, gpo}
   245  
   246  	return eth, nil
   247  }
   248  
   249  // CreateDB creates the chain database.
   250  func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Database, error) {
   251  	db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles)
   252  	if db, ok := db.(*ethdb.LDBDatabase); ok {
   253  		db.Meter("eth/db/chaindata/")
   254  	}
   255  	return db, err
   256  }
   257  
   258  // SetupGenesisBlock initializes the genesis block for an Ethereum service
   259  func SetupGenesisBlock(chainDb *ethdb.Database, config *Config) error {
   260  	// Load up any custom genesis block if requested
   261  	if len(config.Genesis) > 0 {
   262  		block, err := core.WriteGenesisBlock(*chainDb, strings.NewReader(config.Genesis))
   263  		if err != nil {
   264  			return err
   265  		}
   266  		log.Info("Successfully wrote custom genesis block", "hash", block.Hash())
   267  	}
   268  	// Load up a test setup if directly injected
   269  	if config.TestGenesisState != nil {
   270  		*chainDb = config.TestGenesisState
   271  	}
   272  	if config.TestGenesisBlock != nil {
   273  		core.WriteTd(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64(), config.TestGenesisBlock.Difficulty())
   274  		core.WriteBlock(*chainDb, config.TestGenesisBlock)
   275  		core.WriteCanonicalHash(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64())
   276  		core.WriteHeadBlockHash(*chainDb, config.TestGenesisBlock.Hash())
   277  	}
   278  	return nil
   279  }
   280  
   281  // CreatePoW creates the required type of PoW instance for an Ethereum service
   282  func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
   283  	switch {
   284  	case config.PowFake:
   285  		log.Warn("Ethash used in fake mode")
   286  		return pow.FakePow{}
   287  	case config.PowTest:
   288  		log.Warn("Ethash used in test mode")
   289  		return pow.NewTestEthash()
   290  	case config.PowShared:
   291  		log.Warn("Ethash used in shared mode")
   292  		return pow.NewSharedEthash()
   293  	default:
   294  		return pow.NewFullEthash(ctx.ResolvePath(config.EthashCacheDir), config.EthashCachesInMem, config.EthashCachesOnDisk,
   295  			config.EthashDatasetDir, config.EthashDatasetsInMem, config.EthashDatasetsOnDisk)
   296  	}
   297  }
   298  
   299  // APIs returns the collection of RPC services the ethereum package offers.
   300  // NOTE, some of these services probably need to be moved to somewhere else.
   301  func (s *Ethereum) APIs() []rpc.API {
   302  	return append(ethapi.GetAPIs(s.ApiBackend, s.solcPath), []rpc.API{
   303  		{
   304  			Namespace: "eth",
   305  			Version:   "1.0",
   306  			Service:   NewPublicEthereumAPI(s),
   307  			Public:    true,
   308  		}, {
   309  			Namespace: "eth",
   310  			Version:   "1.0",
   311  			Service:   NewPublicMinerAPI(s),
   312  			Public:    true,
   313  		}, {
   314  			Namespace: "eth",
   315  			Version:   "1.0",
   316  			Service:   downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
   317  			Public:    true,
   318  		}, {
   319  			Namespace: "miner",
   320  			Version:   "1.0",
   321  			Service:   NewPrivateMinerAPI(s),
   322  			Public:    false,
   323  		}, {
   324  			Namespace: "eth",
   325  			Version:   "1.0",
   326  			Service:   filters.NewPublicFilterAPI(s.ApiBackend, false),
   327  			Public:    true,
   328  		}, {
   329  			Namespace: "admin",
   330  			Version:   "1.0",
   331  			Service:   NewPrivateAdminAPI(s),
   332  		}, {
   333  			Namespace: "debug",
   334  			Version:   "1.0",
   335  			Service:   NewPublicDebugAPI(s),
   336  			Public:    true,
   337  		}, {
   338  			Namespace: "debug",
   339  			Version:   "1.0",
   340  			Service:   NewPrivateDebugAPI(s.chainConfig, s),
   341  		}, {
   342  			Namespace: "net",
   343  			Version:   "1.0",
   344  			Service:   s.netRPCService,
   345  			Public:    true,
   346  		},
   347  	}...)
   348  }
   349  
   350  func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
   351  	s.blockchain.ResetWithGenesisBlock(gb)
   352  }
   353  
   354  func (s *Ethereum) Etherbase() (eb common.Address, err error) {
   355  	if s.etherbase != (common.Address{}) {
   356  		return s.etherbase, nil
   357  	}
   358  	if wallets := s.AccountManager().Wallets(); len(wallets) > 0 {
   359  		if accounts := wallets[0].Accounts(); len(accounts) > 0 {
   360  			return accounts[0].Address, nil
   361  		}
   362  	}
   363  	return common.Address{}, fmt.Errorf("etherbase address must be explicitly specified")
   364  }
   365  
   366  // set in js console via admin interface or wrapper from cli flags
   367  func (self *Ethereum) SetEtherbase(etherbase common.Address) {
   368  	self.etherbase = etherbase
   369  	self.miner.SetEtherbase(etherbase)
   370  }
   371  
   372  func (s *Ethereum) StartMining(threads int) error {
   373  	eb, err := s.Etherbase()
   374  	if err != nil {
   375  		log.Error("Cannot start mining without etherbase", "err", err)
   376  		return fmt.Errorf("etherbase missing: %v", err)
   377  	}
   378  	go s.miner.Start(eb, threads)
   379  	return nil
   380  }
   381  
   382  func (s *Ethereum) StopMining()         { s.miner.Stop() }
   383  func (s *Ethereum) IsMining() bool      { return s.miner.Mining() }
   384  func (s *Ethereum) Miner() *miner.Miner { return s.miner }
   385  
   386  func (s *Ethereum) AccountManager() *accounts.Manager  { return s.accountManager }
   387  func (s *Ethereum) BlockChain() *core.BlockChain       { return s.blockchain }
   388  func (s *Ethereum) TxPool() *core.TxPool               { return s.txPool }
   389  func (s *Ethereum) EventMux() *event.TypeMux           { return s.eventMux }
   390  func (s *Ethereum) Pow() pow.PoW                       { return s.pow }
   391  func (s *Ethereum) ChainDb() ethdb.Database            { return s.chainDb }
   392  func (s *Ethereum) IsListening() bool                  { return true } // Always listening
   393  func (s *Ethereum) EthVersion() int                    { return int(s.protocolManager.SubProtocols[0].Version) }
   394  func (s *Ethereum) NetVersion() int                    { return s.netVersionId }
   395  func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
   396  
   397  // Protocols implements node.Service, returning all the currently configured
   398  // network protocols to start.
   399  func (s *Ethereum) Protocols() []p2p.Protocol {
   400  	if s.lesServer == nil {
   401  		return s.protocolManager.SubProtocols
   402  	} else {
   403  		return append(s.protocolManager.SubProtocols, s.lesServer.Protocols()...)
   404  	}
   405  }
   406  
   407  // Start implements node.Service, starting all internal goroutines needed by the
   408  // Ethereum protocol implementation.
   409  func (s *Ethereum) Start(srvr *p2p.Server) error {
   410  	s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion())
   411  
   412  	s.protocolManager.Start()
   413  	if s.lesServer != nil {
   414  		s.lesServer.Start(srvr)
   415  	}
   416  	return nil
   417  }
   418  
   419  // Stop implements node.Service, terminating all internal goroutines used by the
   420  // Ethereum protocol.
   421  func (s *Ethereum) Stop() error {
   422  	if s.stopDbUpgrade != nil {
   423  		s.stopDbUpgrade()
   424  	}
   425  	s.blockchain.Stop()
   426  	s.protocolManager.Stop()
   427  	if s.lesServer != nil {
   428  		s.lesServer.Stop()
   429  	}
   430  	s.txPool.Stop()
   431  	s.miner.Stop()
   432  	s.eventMux.Stop()
   433  
   434  	s.chainDb.Close()
   435  	close(s.shutdownChan)
   436  
   437  	return nil
   438  }
   439  
   440  // This function will wait for a shutdown and resumes main thread execution
   441  func (s *Ethereum) WaitForShutdown() {
   442  	<-s.shutdownChan
   443  }