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