github.com/guiltylotus/go-ethereum@v1.9.7/les/client.go (about)

     1  // Copyright 2016 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 les implements the Light Ethereum Subprotocol.
    18  package les
    19  
    20  import (
    21  	"fmt"
    22  
    23  	"github.com/ethereum/go-ethereum/accounts"
    24  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/common/hexutil"
    27  	"github.com/ethereum/go-ethereum/common/mclock"
    28  	"github.com/ethereum/go-ethereum/consensus"
    29  	"github.com/ethereum/go-ethereum/core"
    30  	"github.com/ethereum/go-ethereum/core/bloombits"
    31  	"github.com/ethereum/go-ethereum/core/rawdb"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/eth"
    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/event"
    38  	"github.com/ethereum/go-ethereum/internal/ethapi"
    39  	"github.com/ethereum/go-ethereum/light"
    40  	"github.com/ethereum/go-ethereum/log"
    41  	"github.com/ethereum/go-ethereum/node"
    42  	"github.com/ethereum/go-ethereum/p2p"
    43  	"github.com/ethereum/go-ethereum/p2p/enode"
    44  	"github.com/ethereum/go-ethereum/params"
    45  	"github.com/ethereum/go-ethereum/rpc"
    46  )
    47  
    48  type LightEthereum struct {
    49  	lesCommons
    50  
    51  	reqDist    *requestDistributor
    52  	retriever  *retrieveManager
    53  	odr        *LesOdr
    54  	relay      *lesTxRelay
    55  	handler    *clientHandler
    56  	txPool     *light.TxPool
    57  	blockchain *light.LightChain
    58  	serverPool *serverPool
    59  
    60  	bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
    61  	bloomIndexer  *core.ChainIndexer             // Bloom indexer operating during block imports
    62  
    63  	ApiBackend     *LesApiBackend
    64  	eventMux       *event.TypeMux
    65  	engine         consensus.Engine
    66  	accountManager *accounts.Manager
    67  	netRPCService  *ethapi.PublicNetAPI
    68  }
    69  
    70  func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
    71  	chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideIstanbul)
    76  	if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
    77  		return nil, genesisErr
    78  	}
    79  	log.Info("Initialised chain configuration", "config", chainConfig)
    80  
    81  	peers := newPeerSet()
    82  	leth := &LightEthereum{
    83  		lesCommons: lesCommons{
    84  			genesis:     genesisHash,
    85  			config:      config,
    86  			chainConfig: chainConfig,
    87  			iConfig:     light.DefaultClientIndexerConfig,
    88  			chainDb:     chainDb,
    89  			peers:       peers,
    90  			closeCh:     make(chan struct{}),
    91  		},
    92  		eventMux:       ctx.EventMux,
    93  		reqDist:        newRequestDistributor(peers, &mclock.System{}),
    94  		accountManager: ctx.AccountManager,
    95  		engine:         eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb),
    96  		bloomRequests:  make(chan chan *bloombits.Retrieval),
    97  		bloomIndexer:   eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
    98  		serverPool:     newServerPool(chainDb, config.UltraLightServers),
    99  	}
   100  	leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool)
   101  	leth.relay = newLesTxRelay(peers, leth.retriever)
   102  
   103  	leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever)
   104  	leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequency, params.HelperTrieConfirmations)
   105  	leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency)
   106  	leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer)
   107  
   108  	checkpoint := config.Checkpoint
   109  	if checkpoint == nil {
   110  		checkpoint = params.TrustedCheckpoints[genesisHash]
   111  	}
   112  	// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
   113  	// indexers already set but not started yet
   114  	if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil {
   115  		return nil, err
   116  	}
   117  	leth.chainReader = leth.blockchain
   118  	leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay)
   119  
   120  	// Set up checkpoint oracle.
   121  	oracle := config.CheckpointOracle
   122  	if oracle == nil {
   123  		oracle = params.CheckpointOracles[genesisHash]
   124  	}
   125  	leth.oracle = newCheckpointOracle(oracle, leth.localCheckpoint)
   126  
   127  	// Note: AddChildIndexer starts the update process for the child
   128  	leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer)
   129  	leth.chtIndexer.Start(leth.blockchain)
   130  	leth.bloomIndexer.Start(leth.blockchain)
   131  
   132  	leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth)
   133  	if leth.handler.ulc != nil {
   134  		log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction)
   135  		leth.blockchain.DisableCheckFreq()
   136  	}
   137  	// Rewind the chain in case of an incompatible config upgrade.
   138  	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
   139  		log.Warn("Rewinding chain to upgrade configuration", "err", compat)
   140  		leth.blockchain.SetHead(compat.RewindTo)
   141  		rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
   142  	}
   143  
   144  	leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil}
   145  	gpoParams := config.GPO
   146  	if gpoParams.Default == nil {
   147  		gpoParams.Default = config.Miner.GasPrice
   148  	}
   149  	leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
   150  
   151  	return leth, nil
   152  }
   153  
   154  type LightDummyAPI struct{}
   155  
   156  // Etherbase is the address that mining rewards will be send to
   157  func (s *LightDummyAPI) Etherbase() (common.Address, error) {
   158  	return common.Address{}, fmt.Errorf("mining is not supported in light mode")
   159  }
   160  
   161  // Coinbase is the address that mining rewards will be send to (alias for Etherbase)
   162  func (s *LightDummyAPI) Coinbase() (common.Address, error) {
   163  	return common.Address{}, fmt.Errorf("mining is not supported in light mode")
   164  }
   165  
   166  // Hashrate returns the POW hashrate
   167  func (s *LightDummyAPI) Hashrate() hexutil.Uint {
   168  	return 0
   169  }
   170  
   171  // Mining returns an indication if this node is currently mining.
   172  func (s *LightDummyAPI) Mining() bool {
   173  	return false
   174  }
   175  
   176  // APIs returns the collection of RPC services the ethereum package offers.
   177  // NOTE, some of these services probably need to be moved to somewhere else.
   178  func (s *LightEthereum) APIs() []rpc.API {
   179  	return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{
   180  		{
   181  			Namespace: "eth",
   182  			Version:   "1.0",
   183  			Service:   &LightDummyAPI{},
   184  			Public:    true,
   185  		}, {
   186  			Namespace: "eth",
   187  			Version:   "1.0",
   188  			Service:   downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux),
   189  			Public:    true,
   190  		}, {
   191  			Namespace: "eth",
   192  			Version:   "1.0",
   193  			Service:   filters.NewPublicFilterAPI(s.ApiBackend, true),
   194  			Public:    true,
   195  		}, {
   196  			Namespace: "net",
   197  			Version:   "1.0",
   198  			Service:   s.netRPCService,
   199  			Public:    true,
   200  		}, {
   201  			Namespace: "les",
   202  			Version:   "1.0",
   203  			Service:   NewPrivateLightAPI(&s.lesCommons),
   204  			Public:    false,
   205  		},
   206  	}...)
   207  }
   208  
   209  func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) {
   210  	s.blockchain.ResetWithGenesisBlock(gb)
   211  }
   212  
   213  func (s *LightEthereum) BlockChain() *light.LightChain      { return s.blockchain }
   214  func (s *LightEthereum) TxPool() *light.TxPool              { return s.txPool }
   215  func (s *LightEthereum) Engine() consensus.Engine           { return s.engine }
   216  func (s *LightEthereum) LesVersion() int                    { return int(ClientProtocolVersions[0]) }
   217  func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader }
   218  func (s *LightEthereum) EventMux() *event.TypeMux           { return s.eventMux }
   219  
   220  // Protocols implements node.Service, returning all the currently configured
   221  // network protocols to start.
   222  func (s *LightEthereum) Protocols() []p2p.Protocol {
   223  	return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
   224  		if p := s.peers.Peer(peerIdToString(id)); p != nil {
   225  			return p.Info()
   226  		}
   227  		return nil
   228  	})
   229  }
   230  
   231  // Start implements node.Service, starting all internal goroutines needed by the
   232  // light ethereum protocol implementation.
   233  func (s *LightEthereum) Start(srvr *p2p.Server) error {
   234  	log.Warn("Light client mode is an experimental feature")
   235  
   236  	// Start bloom request workers.
   237  	s.wg.Add(bloomServiceThreads)
   238  	s.startBloomHandlers(params.BloomBitsBlocksClient)
   239  
   240  	s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId)
   241  
   242  	// clients are searching for the first advertised protocol in the list
   243  	protocolVersion := AdvertiseProtocolVersions[0]
   244  	s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
   245  	return nil
   246  }
   247  
   248  // Stop implements node.Service, terminating all internal goroutines used by the
   249  // Ethereum protocol.
   250  func (s *LightEthereum) Stop() error {
   251  	close(s.closeCh)
   252  	s.peers.Close()
   253  	s.reqDist.close()
   254  	s.odr.Stop()
   255  	s.relay.Stop()
   256  	s.bloomIndexer.Close()
   257  	s.chtIndexer.Close()
   258  	s.blockchain.Stop()
   259  	s.handler.stop()
   260  	s.txPool.Stop()
   261  	s.engine.Close()
   262  	s.eventMux.Stop()
   263  	s.serverPool.stop()
   264  	s.chainDb.Close()
   265  	s.wg.Wait()
   266  	log.Info("Light ethereum stopped")
   267  	return nil
   268  }
   269  
   270  // SetClient sets the rpc client and binds the registrar contract.
   271  func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) {
   272  	if s.oracle == nil {
   273  		return
   274  	}
   275  	s.oracle.start(backend)
   276  }