gitlab.com/flarenetwork/coreth@v0.1.1/eth/backend.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2014 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  // Package eth implements the Ethereum protocol.
    28  package eth
    29  
    30  import (
    31  	"errors"
    32  	"fmt"
    33  	"sync"
    34  	"time"
    35  
    36  	"github.com/ethereum/go-ethereum/common"
    37  	"github.com/ethereum/go-ethereum/eth/downloader"
    38  	"github.com/ethereum/go-ethereum/ethdb"
    39  	"github.com/ethereum/go-ethereum/event"
    40  	"github.com/ethereum/go-ethereum/log"
    41  	"gitlab.com/flarenetwork/coreth/accounts"
    42  	"gitlab.com/flarenetwork/coreth/consensus"
    43  	"gitlab.com/flarenetwork/coreth/consensus/dummy"
    44  	"gitlab.com/flarenetwork/coreth/core"
    45  	"gitlab.com/flarenetwork/coreth/core/bloombits"
    46  	"gitlab.com/flarenetwork/coreth/core/rawdb"
    47  	"gitlab.com/flarenetwork/coreth/core/types"
    48  	"gitlab.com/flarenetwork/coreth/core/vm"
    49  	"gitlab.com/flarenetwork/coreth/eth/ethconfig"
    50  	"gitlab.com/flarenetwork/coreth/eth/filters"
    51  	"gitlab.com/flarenetwork/coreth/eth/gasprice"
    52  	"gitlab.com/flarenetwork/coreth/eth/tracers"
    53  	"gitlab.com/flarenetwork/coreth/internal/ethapi"
    54  	"gitlab.com/flarenetwork/coreth/miner"
    55  	"gitlab.com/flarenetwork/coreth/node"
    56  	"gitlab.com/flarenetwork/coreth/params"
    57  	"gitlab.com/flarenetwork/coreth/rpc"
    58  )
    59  
    60  // Config contains the configuration options of the ETH protocol.
    61  // Deprecated: use ethconfig.Config instead.
    62  type Config = ethconfig.Config
    63  
    64  var (
    65  	DefaultSettings Settings = Settings{MaxBlocksPerRequest: 2000}
    66  )
    67  
    68  type Settings struct {
    69  	MaxBlocksPerRequest int64 // Maximum number of blocks to serve per getLogs request
    70  }
    71  
    72  // Ethereum implements the Ethereum full node service.
    73  type Ethereum struct {
    74  	config *Config
    75  
    76  	// Handlers
    77  	txPool     *core.TxPool
    78  	blockchain *core.BlockChain
    79  
    80  	// DB interfaces
    81  	chainDb ethdb.Database // Block chain database
    82  
    83  	eventMux       *event.TypeMux
    84  	engine         consensus.Engine
    85  	accountManager *accounts.Manager
    86  
    87  	bloomRequests     chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
    88  	bloomIndexer      *core.ChainIndexer             // Bloom indexer operating during block imports
    89  	closeBloomHandler chan struct{}
    90  
    91  	APIBackend *EthAPIBackend
    92  
    93  	miner     *miner.Miner
    94  	etherbase common.Address
    95  
    96  	networkID     uint64
    97  	netRPCService *ethapi.PublicNetAPI
    98  
    99  	lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
   100  
   101  	settings Settings // Settings for Ethereum API
   102  }
   103  
   104  // New creates a new Ethereum object (including the
   105  // initialisation of the common Ethereum object)
   106  func New(stack *node.Node, config *Config,
   107  	cb *dummy.ConsensusCallbacks,
   108  	chainDb ethdb.Database,
   109  	settings Settings,
   110  	lastAcceptedHash common.Hash,
   111  ) (*Ethereum, error) {
   112  	if chainDb == nil {
   113  		return nil, errors.New("chainDb cannot be nil")
   114  	}
   115  	if !config.Pruning && config.TrieDirtyCache > 0 {
   116  		// If snapshots are enabled, allocate 2/5 of the TrieDirtyCache memory cap to the snapshot cache
   117  		if config.SnapshotCache > 0 {
   118  			config.TrieCleanCache += config.TrieDirtyCache * 3 / 5
   119  			config.SnapshotCache += config.TrieDirtyCache * 2 / 5
   120  		} else {
   121  			// If snapshots are disabled, the TrieDirtyCache will be written through to the clean cache
   122  			// so move the cache allocation from the dirty cache to the clean cache
   123  			config.TrieCleanCache += config.TrieDirtyCache
   124  			config.TrieDirtyCache = 0
   125  		}
   126  	}
   127  	log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
   128  
   129  	chainConfig, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
   130  	if genesisErr != nil {
   131  		return nil, genesisErr
   132  	}
   133  	log.Info("Initialised chain configuration", "config", chainConfig)
   134  
   135  	// FIXME RecoverPruning once that package is migrated over
   136  	// if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil {
   137  	//             log.Error("Failed to recover state", "error", err)
   138  	// }
   139  	eth := &Ethereum{
   140  		config:            config,
   141  		chainDb:           chainDb,
   142  		eventMux:          stack.EventMux(),
   143  		accountManager:    stack.AccountManager(),
   144  		engine:            dummy.NewDummyEngine(cb),
   145  		closeBloomHandler: make(chan struct{}),
   146  		networkID:         config.NetworkId,
   147  		etherbase:         config.Miner.Etherbase,
   148  		bloomRequests:     make(chan chan *bloombits.Retrieval),
   149  		bloomIndexer:      core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
   150  		settings:          settings,
   151  	}
   152  
   153  	bcVersion := rawdb.ReadDatabaseVersion(chainDb)
   154  	var dbVer = "<nil>"
   155  	if bcVersion != nil {
   156  		dbVer = fmt.Sprintf("%d", *bcVersion)
   157  	}
   158  	log.Info("Initialising Ethereum protocol", "network", config.NetworkId, "dbversion", dbVer)
   159  
   160  	if !config.SkipBcVersionCheck {
   161  		if bcVersion != nil && *bcVersion > core.BlockChainVersion {
   162  			return nil, fmt.Errorf("database version is v%d, Coreth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion)
   163  		} else if bcVersion == nil || *bcVersion < core.BlockChainVersion {
   164  			log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion)
   165  			rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion)
   166  		}
   167  	}
   168  	var (
   169  		vmConfig = vm.Config{
   170  			EnablePreimageRecording: config.EnablePreimageRecording,
   171  			AllowUnfinalizedQueries: config.AllowUnfinalizedQueries,
   172  		}
   173  		cacheConfig = &core.CacheConfig{
   174  			TrieCleanLimit: config.TrieCleanCache,
   175  			TrieDirtyLimit: config.TrieDirtyCache,
   176  			Pruning:        config.Pruning,
   177  			SnapshotLimit:  config.SnapshotCache,
   178  			SnapshotAsync:  config.SnapshotAsync,
   179  			SnapshotVerify: config.SnapshotVerify,
   180  			Preimages:      config.Preimages,
   181  		}
   182  	)
   183  	var err error
   184  	eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, lastAcceptedHash)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	eth.bloomIndexer.Start(eth.blockchain)
   189  
   190  	// Original code (requires disk):
   191  	// if config.TxPool.Journal != "" {
   192  	// 	config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal)
   193  	// }
   194  	config.TxPool.Journal = ""
   195  	eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain)
   196  
   197  	eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine)
   198  
   199  	// FIXME use node config to pass in config param on whether or not to allow unprotected
   200  	// currently defaults to false.
   201  	allowUnprotectedTxs := false
   202  	eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), false, eth, nil}
   203  	if allowUnprotectedTxs {
   204  		log.Info("Unprotected transactions allowed")
   205  	}
   206  	gpoParams := config.GPO
   207  	eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
   208  
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	// Start the RPC service
   214  	eth.netRPCService = ethapi.NewPublicNetAPI(eth.NetVersion())
   215  
   216  	// Register the backend on the node
   217  	stack.RegisterAPIs(eth.APIs())
   218  
   219  	return eth, nil
   220  }
   221  
   222  // APIs return the collection of RPC services the ethereum package offers.
   223  // NOTE, some of these services probably need to be moved to somewhere else.
   224  func (s *Ethereum) APIs() []rpc.API {
   225  	apis := ethapi.GetAPIs(s.APIBackend)
   226  
   227  	// Append tracing APIs
   228  	apis = append(apis, tracers.APIs(s.APIBackend)...)
   229  
   230  	// Append any APIs exposed explicitly by the consensus engine
   231  	apis = append(apis, s.engine.APIs(s.BlockChain())...)
   232  
   233  	// Append all the local APIs and return
   234  	return append(apis, []rpc.API{
   235  		{
   236  			Namespace: "eth",
   237  			Version:   "1.0",
   238  			Service:   NewPublicEthereumAPI(s),
   239  			Public:    true,
   240  		}, {
   241  			Namespace: "eth",
   242  			Version:   "1.0",
   243  			Service:   filters.NewPublicFilterAPI(s.APIBackend, false, 5*time.Minute),
   244  			Public:    true,
   245  		}, {
   246  			Namespace: "admin",
   247  			Version:   "1.0",
   248  			Service:   NewPrivateAdminAPI(s),
   249  		}, {
   250  			Namespace: "debug",
   251  			Version:   "1.0",
   252  			Service:   NewPublicDebugAPI(s),
   253  			Public:    true,
   254  		}, {
   255  			Namespace: "debug",
   256  			Version:   "1.0",
   257  			Service:   NewPrivateDebugAPI(s),
   258  		}, {
   259  			Namespace: "net",
   260  			Version:   "1.0",
   261  			Service:   s.netRPCService,
   262  			Public:    true,
   263  		},
   264  	}...)
   265  }
   266  
   267  func (s *Ethereum) Etherbase() (eb common.Address, err error) {
   268  	s.lock.RLock()
   269  	etherbase := s.etherbase
   270  	s.lock.RUnlock()
   271  
   272  	if etherbase != (common.Address{}) {
   273  		return etherbase, nil
   274  	}
   275  	if wallets := s.AccountManager().Wallets(); len(wallets) > 0 {
   276  		if accounts := wallets[0].Accounts(); len(accounts) > 0 {
   277  			etherbase := accounts[0].Address
   278  
   279  			s.lock.Lock()
   280  			s.etherbase = etherbase
   281  			s.lock.Unlock()
   282  
   283  			log.Info("Etherbase automatically configured", "address", etherbase)
   284  			return etherbase, nil
   285  		}
   286  	}
   287  	return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
   288  }
   289  
   290  // SetEtherbase sets the mining reward address.
   291  func (s *Ethereum) SetEtherbase(etherbase common.Address) {
   292  	s.lock.Lock()
   293  	s.etherbase = etherbase
   294  	s.lock.Unlock()
   295  
   296  	s.miner.SetEtherbase(etherbase)
   297  }
   298  
   299  func (s *Ethereum) Miner() *miner.Miner { return s.miner }
   300  
   301  func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
   302  func (s *Ethereum) BlockChain() *core.BlockChain      { return s.blockchain }
   303  func (s *Ethereum) TxPool() *core.TxPool              { return s.txPool }
   304  func (s *Ethereum) EventMux() *event.TypeMux          { return s.eventMux }
   305  func (s *Ethereum) Engine() consensus.Engine          { return s.engine }
   306  func (s *Ethereum) ChainDb() ethdb.Database           { return s.chainDb }
   307  
   308  // FIXME remove NetVersion, IsListening, Downloader, and Synced
   309  func (s *Ethereum) IsListening() bool                  { return true } // Always listening
   310  func (s *Ethereum) NetVersion() uint64                 { return s.networkID }
   311  func (s *Ethereum) Downloader() *downloader.Downloader { return nil }  // s.protocolManager.downloader }
   312  func (s *Ethereum) Synced() bool                       { return true } // atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 }
   313  func (s *Ethereum) ArchiveMode() bool                  { return !s.config.Pruning }
   314  func (s *Ethereum) BloomIndexer() *core.ChainIndexer   { return s.bloomIndexer }
   315  
   316  // Start implements node.Lifecycle, starting all internal goroutines needed by the
   317  // Ethereum protocol implementation.
   318  func (s *Ethereum) Start() {
   319  	// Start the bloom bits servicing goroutines
   320  	s.startBloomHandlers(params.BloomBitsBlocks)
   321  }
   322  
   323  // Stop implements node.Lifecycle, terminating all internal goroutines used by the
   324  // Ethereum protocol.
   325  // FIXME remove error from type if this will never return an error
   326  func (s *Ethereum) Stop() error {
   327  	s.bloomIndexer.Close()
   328  	close(s.closeBloomHandler)
   329  	s.txPool.Stop()
   330  	s.blockchain.Stop()
   331  	s.engine.Close()
   332  	s.chainDb.Close()
   333  	s.eventMux.Stop()
   334  	return nil
   335  }
   336  
   337  func (s *Ethereum) LastAcceptedBlock() *types.Block {
   338  	return s.blockchain.LastAcceptedBlock()
   339  }