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