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 }