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