github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/les/client.go (about)

     1  // Copyright 2016 The go-simplechain Authors
     2  // This file is part of the go-simplechain library.
     3  //
     4  // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package les implements the Light SimpleService Subprotocol.
    18  package les
    19  
    20  import (
    21  	"fmt"
    22  
    23  	"github.com/bigzoro/my_simplechain/accounts"
    24  	"github.com/bigzoro/my_simplechain/accounts/abi/bind"
    25  	"github.com/bigzoro/my_simplechain/common"
    26  	"github.com/bigzoro/my_simplechain/common/hexutil"
    27  	"github.com/bigzoro/my_simplechain/common/mclock"
    28  	"github.com/bigzoro/my_simplechain/consensus"
    29  	"github.com/bigzoro/my_simplechain/core"
    30  	"github.com/bigzoro/my_simplechain/core/bloombits"
    31  	"github.com/bigzoro/my_simplechain/core/rawdb"
    32  	"github.com/bigzoro/my_simplechain/core/types"
    33  	"github.com/bigzoro/my_simplechain/eth"
    34  	"github.com/bigzoro/my_simplechain/eth/downloader"
    35  	"github.com/bigzoro/my_simplechain/eth/filters"
    36  	"github.com/bigzoro/my_simplechain/eth/gasprice"
    37  	"github.com/bigzoro/my_simplechain/event"
    38  	"github.com/bigzoro/my_simplechain/internal/ethapi"
    39  	"github.com/bigzoro/my_simplechain/light"
    40  	"github.com/bigzoro/my_simplechain/log"
    41  	"github.com/bigzoro/my_simplechain/node"
    42  	"github.com/bigzoro/my_simplechain/p2p"
    43  	"github.com/bigzoro/my_simplechain/p2p/enode"
    44  	"github.com/bigzoro/my_simplechain/params"
    45  	"github.com/bigzoro/my_simplechain/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.OverrideSingularity)
    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, 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  	apis := ethapi.GetAPIs(s.ApiBackend)
   180  	apis = append(apis, s.engine.APIs(s.BlockChain().HeaderChain())...)
   181  	return append(apis, []rpc.API{
   182  		{
   183  			Namespace: "eth",
   184  			Version:   "1.0",
   185  			Service:   &LightDummyAPI{},
   186  			Public:    true,
   187  		}, {
   188  			Namespace: "eth",
   189  			Version:   "1.0",
   190  			Service:   downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux),
   191  			Public:    true,
   192  		}, {
   193  			Namespace: "eth",
   194  			Version:   "1.0",
   195  			Service:   filters.NewPublicFilterAPI(s.ApiBackend, true),
   196  			Public:    true,
   197  		}, {
   198  			Namespace: "net",
   199  			Version:   "1.0",
   200  			Service:   s.netRPCService,
   201  			Public:    true,
   202  		}, {
   203  			Namespace: "les",
   204  			Version:   "1.0",
   205  			Service:   NewPrivateLightAPI(&s.lesCommons),
   206  			Public:    false,
   207  		},
   208  	}...)
   209  }
   210  
   211  func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) {
   212  	s.blockchain.ResetWithGenesisBlock(gb)
   213  }
   214  
   215  func (s *LightEthereum) BlockChain() *light.LightChain      { return s.blockchain }
   216  func (s *LightEthereum) TxPool() *light.TxPool              { return s.txPool }
   217  func (s *LightEthereum) Engine() consensus.Engine           { return s.engine }
   218  func (s *LightEthereum) LesVersion() int                    { return int(ClientProtocolVersions[0]) }
   219  func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader }
   220  func (s *LightEthereum) EventMux() *event.TypeMux           { return s.eventMux }
   221  
   222  // Protocols implements node.Service, returning all the currently configured
   223  // network protocols to start.
   224  func (s *LightEthereum) Protocols() []p2p.Protocol {
   225  	return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
   226  		if p := s.peers.Peer(peerIdToString(id)); p != nil {
   227  			return p.Info()
   228  		}
   229  		return nil
   230  	})
   231  }
   232  
   233  // Start implements node.Service, starting all internal goroutines needed by the
   234  // light ethereum protocol implementation.
   235  func (s *LightEthereum) Start(srvr *p2p.Server) error {
   236  	log.Warn("Light client mode is an experimental feature")
   237  
   238  	// Start bloom request workers.
   239  	s.wg.Add(bloomServiceThreads)
   240  	s.startBloomHandlers(params.BloomBitsBlocksClient)
   241  
   242  	s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId)
   243  
   244  	// clients are searching for the first advertised protocol in the list
   245  	protocolVersion := AdvertiseProtocolVersions[0]
   246  	s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
   247  	return nil
   248  }
   249  
   250  // Stop implements node.Service, terminating all internal goroutines used by the
   251  // SimpleService protocol.
   252  func (s *LightEthereum) Stop() error {
   253  	close(s.closeCh)
   254  	s.peers.Close()
   255  	s.reqDist.close()
   256  	s.odr.Stop()
   257  	s.relay.Stop()
   258  	s.bloomIndexer.Close()
   259  	s.chtIndexer.Close()
   260  	s.blockchain.Stop()
   261  	s.handler.stop()
   262  	s.txPool.Stop()
   263  	s.engine.Close()
   264  	s.eventMux.Stop()
   265  	s.serverPool.stop()
   266  	s.chainDb.Close()
   267  	s.wg.Wait()
   268  	log.Info("Light ethereum stopped")
   269  	return nil
   270  }
   271  
   272  // SetClient sets the rpc client and binds the registrar contract.
   273  func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) {
   274  	if s.oracle == nil {
   275  		return
   276  	}
   277  	s.oracle.start(backend)
   278  }