github.com/CommerciumBlockchain/go-commercium@v0.0.0-20220709212705-b46438a77516/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  	"time"
    23  
    24  	"github.com/CommerciumBlockchain/go-commercium/accounts"
    25  	"github.com/CommerciumBlockchain/go-commercium/common"
    26  	"github.com/CommerciumBlockchain/go-commercium/common/hexutil"
    27  	"github.com/CommerciumBlockchain/go-commercium/common/mclock"
    28  	"github.com/CommerciumBlockchain/go-commercium/consensus"
    29  	"github.com/CommerciumBlockchain/go-commercium/core"
    30  	"github.com/CommerciumBlockchain/go-commercium/core/bloombits"
    31  	"github.com/CommerciumBlockchain/go-commercium/core/rawdb"
    32  	"github.com/CommerciumBlockchain/go-commercium/core/types"
    33  	"github.com/CommerciumBlockchain/go-commercium/eth"
    34  	"github.com/CommerciumBlockchain/go-commercium/eth/downloader"
    35  	"github.com/CommerciumBlockchain/go-commercium/eth/filters"
    36  	"github.com/CommerciumBlockchain/go-commercium/eth/gasprice"
    37  	"github.com/CommerciumBlockchain/go-commercium/event"
    38  	"github.com/CommerciumBlockchain/go-commercium/internal/ethapi"
    39  	lpc "github.com/CommerciumBlockchain/go-commercium/les/lespay/client"
    40  	"github.com/CommerciumBlockchain/go-commercium/light"
    41  	"github.com/CommerciumBlockchain/go-commercium/log"
    42  	"github.com/CommerciumBlockchain/go-commercium/node"
    43  	"github.com/CommerciumBlockchain/go-commercium/p2p"
    44  	"github.com/CommerciumBlockchain/go-commercium/p2p/enode"
    45  	"github.com/CommerciumBlockchain/go-commercium/params"
    46  	"github.com/CommerciumBlockchain/go-commercium/rpc"
    47  )
    48  
    49  type LightEthereum struct {
    50  	lesCommons
    51  
    52  	peers          *serverPeerSet
    53  	reqDist        *requestDistributor
    54  	retriever      *retrieveManager
    55  	odr            *LesOdr
    56  	relay          *lesTxRelay
    57  	handler        *clientHandler
    58  	txPool         *light.TxPool
    59  	blockchain     *light.LightChain
    60  	serverPool     *serverPool
    61  	valueTracker   *lpc.ValueTracker
    62  	dialCandidates enode.Iterator
    63  	pruner         *pruner
    64  
    65  	bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
    66  	bloomIndexer  *core.ChainIndexer             // Bloom indexer operating during block imports
    67  
    68  	ApiBackend     *LesApiBackend
    69  	eventMux       *event.TypeMux
    70  	engine         consensus.Engine
    71  	accountManager *accounts.Manager
    72  	netRPCService  *ethapi.PublicNetAPI
    73  
    74  	p2pServer *p2p.Server
    75  }
    76  
    77  // New creates an instance of the light client.
    78  func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
    79  	chainDb, err := stack.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	lespayDb, err := stack.OpenDatabase("lespay", 0, 0, "eth/db/lespay")
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
    88  	if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
    89  		return nil, genesisErr
    90  	}
    91  	log.Info("Initialised chain configuration", "config", chainConfig)
    92  
    93  	peers := newServerPeerSet()
    94  	leth := &LightEthereum{
    95  		lesCommons: lesCommons{
    96  			genesis:     genesisHash,
    97  			config:      config,
    98  			chainConfig: chainConfig,
    99  			iConfig:     light.DefaultClientIndexerConfig,
   100  			chainDb:     chainDb,
   101  			closeCh:     make(chan struct{}),
   102  		},
   103  		peers:          peers,
   104  		eventMux:       stack.EventMux(),
   105  		reqDist:        newRequestDistributor(peers, &mclock.System{}),
   106  		accountManager: stack.AccountManager(),
   107  		engine:         eth.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, chainDb),
   108  		bloomRequests:  make(chan chan *bloombits.Retrieval),
   109  		bloomIndexer:   eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
   110  		valueTracker:   lpc.NewValueTracker(lespayDb, &mclock.System{}, requestList, time.Minute, 1/float64(time.Hour), 1/float64(time.Hour*100), 1/float64(time.Hour*1000)),
   111  		p2pServer:      stack.Server(),
   112  	}
   113  	peers.subscribe((*vtSubscription)(leth.valueTracker))
   114  
   115  	dnsdisc, err := leth.setupDiscovery()
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	leth.serverPool = newServerPool(lespayDb, []byte("serverpool:"), leth.valueTracker, dnsdisc, time.Second, nil, &mclock.System{}, config.UltraLightServers)
   120  	peers.subscribe(leth.serverPool)
   121  	leth.dialCandidates = leth.serverPool.dialIterator
   122  
   123  	leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool.getTimeout)
   124  	leth.relay = newLesTxRelay(peers, leth.retriever)
   125  
   126  	leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever)
   127  	leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequency, params.HelperTrieConfirmations, config.LightNoPrune)
   128  	leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency, config.LightNoPrune)
   129  	leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer)
   130  
   131  	checkpoint := config.Checkpoint
   132  	if checkpoint == nil {
   133  		checkpoint = params.TrustedCheckpoints[genesisHash]
   134  	}
   135  	// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
   136  	// indexers already set but not started yet
   137  	if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil {
   138  		return nil, err
   139  	}
   140  	leth.chainReader = leth.blockchain
   141  	leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay)
   142  
   143  	// Set up checkpoint oracle.
   144  	leth.oracle = leth.setupOracle(stack, genesisHash, config)
   145  
   146  	// Note: AddChildIndexer starts the update process for the child
   147  	leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer)
   148  	leth.chtIndexer.Start(leth.blockchain)
   149  	leth.bloomIndexer.Start(leth.blockchain)
   150  
   151  	// Start a light chain pruner to delete useless historical data.
   152  	leth.pruner = newPruner(chainDb, leth.chtIndexer, leth.bloomTrieIndexer)
   153  
   154  	// Rewind the chain in case of an incompatible config upgrade.
   155  	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
   156  		log.Warn("Rewinding chain to upgrade configuration", "err", compat)
   157  		leth.blockchain.SetHead(compat.RewindTo)
   158  		rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
   159  	}
   160  
   161  	leth.ApiBackend = &LesApiBackend{stack.Config().ExtRPCEnabled(), leth, nil}
   162  	gpoParams := config.GPO
   163  	if gpoParams.Default == nil {
   164  		gpoParams.Default = config.Miner.GasPrice
   165  	}
   166  	leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
   167  
   168  	leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth)
   169  	if leth.handler.ulc != nil {
   170  		log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction)
   171  		leth.blockchain.DisableCheckFreq()
   172  	}
   173  
   174  	leth.netRPCService = ethapi.NewPublicNetAPI(leth.p2pServer)
   175  
   176  	// Register the backend on the node
   177  	stack.RegisterAPIs(leth.APIs())
   178  	stack.RegisterProtocols(leth.Protocols())
   179  	stack.RegisterLifecycle(leth)
   180  
   181  	// Check for unclean shutdown
   182  	if uncleanShutdowns, discards, err := rawdb.PushUncleanShutdownMarker(chainDb); err != nil {
   183  		log.Error("Could not update unclean-shutdown-marker list", "error", err)
   184  	} else {
   185  		if discards > 0 {
   186  			log.Warn("Old unclean shutdowns found", "count", discards)
   187  		}
   188  		for _, tstamp := range uncleanShutdowns {
   189  			t := time.Unix(int64(tstamp), 0)
   190  			log.Warn("Unclean shutdown detected", "booted", t,
   191  				"age", common.PrettyAge(t))
   192  		}
   193  	}
   194  	return leth, nil
   195  }
   196  
   197  // vtSubscription implements serverPeerSubscriber
   198  type vtSubscription lpc.ValueTracker
   199  
   200  // registerPeer implements serverPeerSubscriber
   201  func (v *vtSubscription) registerPeer(p *serverPeer) {
   202  	vt := (*lpc.ValueTracker)(v)
   203  	p.setValueTracker(vt, vt.Register(p.ID()))
   204  	p.updateVtParams()
   205  }
   206  
   207  // unregisterPeer implements serverPeerSubscriber
   208  func (v *vtSubscription) unregisterPeer(p *serverPeer) {
   209  	vt := (*lpc.ValueTracker)(v)
   210  	vt.Unregister(p.ID())
   211  	p.setValueTracker(nil, nil)
   212  }
   213  
   214  type LightDummyAPI struct{}
   215  
   216  // Etherbase is the address that mining rewards will be send to
   217  func (s *LightDummyAPI) Etherbase() (common.Address, error) {
   218  	return common.Address{}, fmt.Errorf("mining is not supported in light mode")
   219  }
   220  
   221  // Coinbase is the address that mining rewards will be send to (alias for Etherbase)
   222  func (s *LightDummyAPI) Coinbase() (common.Address, error) {
   223  	return common.Address{}, fmt.Errorf("mining is not supported in light mode")
   224  }
   225  
   226  // Hashrate returns the POW hashrate
   227  func (s *LightDummyAPI) Hashrate() hexutil.Uint {
   228  	return 0
   229  }
   230  
   231  // Mining returns an indication if this node is currently mining.
   232  func (s *LightDummyAPI) Mining() bool {
   233  	return false
   234  }
   235  
   236  // APIs returns the collection of RPC services the ethereum package offers.
   237  // NOTE, some of these services probably need to be moved to somewhere else.
   238  func (s *LightEthereum) APIs() []rpc.API {
   239  	apis := ethapi.GetAPIs(s.ApiBackend)
   240  	apis = append(apis, s.engine.APIs(s.BlockChain().HeaderChain())...)
   241  	return append(apis, []rpc.API{
   242  		{
   243  			Namespace: "eth",
   244  			Version:   "1.0",
   245  			Service:   &LightDummyAPI{},
   246  			Public:    true,
   247  		}, {
   248  			Namespace: "eth",
   249  			Version:   "1.0",
   250  			Service:   downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux),
   251  			Public:    true,
   252  		}, {
   253  			Namespace: "eth",
   254  			Version:   "1.0",
   255  			Service:   filters.NewPublicFilterAPI(s.ApiBackend, true),
   256  			Public:    true,
   257  		}, {
   258  			Namespace: "net",
   259  			Version:   "1.0",
   260  			Service:   s.netRPCService,
   261  			Public:    true,
   262  		}, {
   263  			Namespace: "les",
   264  			Version:   "1.0",
   265  			Service:   NewPrivateLightAPI(&s.lesCommons),
   266  			Public:    false,
   267  		}, {
   268  			Namespace: "lespay",
   269  			Version:   "1.0",
   270  			Service:   lpc.NewPrivateClientAPI(s.valueTracker),
   271  			Public:    false,
   272  		},
   273  	}...)
   274  }
   275  
   276  func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) {
   277  	s.blockchain.ResetWithGenesisBlock(gb)
   278  }
   279  
   280  func (s *LightEthereum) BlockChain() *light.LightChain      { return s.blockchain }
   281  func (s *LightEthereum) TxPool() *light.TxPool              { return s.txPool }
   282  func (s *LightEthereum) Engine() consensus.Engine           { return s.engine }
   283  func (s *LightEthereum) LesVersion() int                    { return int(ClientProtocolVersions[0]) }
   284  func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader }
   285  func (s *LightEthereum) EventMux() *event.TypeMux           { return s.eventMux }
   286  
   287  // Protocols returns all the currently configured network protocols to start.
   288  func (s *LightEthereum) Protocols() []p2p.Protocol {
   289  	return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
   290  		if p := s.peers.peer(id.String()); p != nil {
   291  			return p.Info()
   292  		}
   293  		return nil
   294  	}, s.dialCandidates)
   295  }
   296  
   297  // Start implements node.Lifecycle, starting all internal goroutines needed by the
   298  // light ethereum protocol implementation.
   299  func (s *LightEthereum) Start() error {
   300  	log.Warn("Light client mode is an experimental feature")
   301  
   302  	s.serverPool.start()
   303  	// Start bloom request workers.
   304  	s.wg.Add(bloomServiceThreads)
   305  	s.startBloomHandlers(params.BloomBitsBlocksClient)
   306  	s.handler.start()
   307  
   308  	return nil
   309  }
   310  
   311  // Stop implements node.Lifecycle, terminating all internal goroutines used by the
   312  // Ethereum protocol.
   313  func (s *LightEthereum) Stop() error {
   314  	close(s.closeCh)
   315  	s.serverPool.stop()
   316  	s.valueTracker.Stop()
   317  	s.peers.close()
   318  	s.reqDist.close()
   319  	s.odr.Stop()
   320  	s.relay.Stop()
   321  	s.bloomIndexer.Close()
   322  	s.chtIndexer.Close()
   323  	s.blockchain.Stop()
   324  	s.handler.stop()
   325  	s.txPool.Stop()
   326  	s.engine.Close()
   327  	s.pruner.close()
   328  	s.eventMux.Stop()
   329  	rawdb.PopUncleanShutdownMarker(s.chainDb)
   330  	s.chainDb.Close()
   331  	s.wg.Wait()
   332  	log.Info("Light ethereum stopped")
   333  	return nil
   334  }