github.com/pavelkrolevets/ton618@v1.9.26-0.20220108073458-82e0736ad23d/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/pavelkrolevets/ton618/accounts" 25 "github.com/pavelkrolevets/ton618/common" 26 "github.com/pavelkrolevets/ton618/common/hexutil" 27 "github.com/pavelkrolevets/ton618/common/mclock" 28 "github.com/pavelkrolevets/ton618/consensus" 29 "github.com/pavelkrolevets/ton618/core" 30 "github.com/pavelkrolevets/ton618/core/bloombits" 31 "github.com/pavelkrolevets/ton618/core/rawdb" 32 "github.com/pavelkrolevets/ton618/core/types" 33 "github.com/pavelkrolevets/ton618/eth" 34 "github.com/pavelkrolevets/ton618/eth/downloader" 35 "github.com/pavelkrolevets/ton618/eth/filters" 36 "github.com/pavelkrolevets/ton618/eth/gasprice" 37 "github.com/pavelkrolevets/ton618/event" 38 "github.com/pavelkrolevets/ton618/internal/ethapi" 39 lpc "github.com/pavelkrolevets/ton618/les/lespay/client" 40 "github.com/pavelkrolevets/ton618/light" 41 "github.com/pavelkrolevets/ton618/log" 42 "github.com/pavelkrolevets/ton618/node" 43 "github.com/pavelkrolevets/ton618/p2p" 44 "github.com/pavelkrolevets/ton618/p2p/enode" 45 "github.com/pavelkrolevets/ton618/params" 46 "github.com/pavelkrolevets/ton618/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, leth.config.NetworkId) 175 176 // Register the backend on the node 177 stack.RegisterAPIs(leth.APIs()) 178 stack.RegisterProtocols(leth.Protocols()) 179 stack.RegisterLifecycle(leth) 180 181 return leth, nil 182 } 183 184 // vtSubscription implements serverPeerSubscriber 185 type vtSubscription lpc.ValueTracker 186 187 // registerPeer implements serverPeerSubscriber 188 func (v *vtSubscription) registerPeer(p *serverPeer) { 189 vt := (*lpc.ValueTracker)(v) 190 p.setValueTracker(vt, vt.Register(p.ID())) 191 p.updateVtParams() 192 } 193 194 // unregisterPeer implements serverPeerSubscriber 195 func (v *vtSubscription) unregisterPeer(p *serverPeer) { 196 vt := (*lpc.ValueTracker)(v) 197 vt.Unregister(p.ID()) 198 p.setValueTracker(nil, nil) 199 } 200 201 type LightDummyAPI struct{} 202 203 // Etherbase is the address that mining rewards will be send to 204 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 205 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 206 } 207 208 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 209 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 210 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 211 } 212 213 // Hashrate returns the POW hashrate 214 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 215 return 0 216 } 217 218 // Mining returns an indication if this node is currently mining. 219 func (s *LightDummyAPI) Mining() bool { 220 return false 221 } 222 223 // APIs returns the collection of RPC services the ethereum package offers. 224 // NOTE, some of these services probably need to be moved to somewhere else. 225 func (s *LightEthereum) APIs() []rpc.API { 226 apis := ethapi.GetAPIs(s.ApiBackend) 227 apis = append(apis, s.engine.APIs(s.BlockChain().HeaderChain())...) 228 return append(apis, []rpc.API{ 229 { 230 Namespace: "eth", 231 Version: "1.0", 232 Service: &LightDummyAPI{}, 233 Public: true, 234 }, { 235 Namespace: "eth", 236 Version: "1.0", 237 Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), 238 Public: true, 239 }, { 240 Namespace: "eth", 241 Version: "1.0", 242 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 243 Public: true, 244 }, { 245 Namespace: "net", 246 Version: "1.0", 247 Service: s.netRPCService, 248 Public: true, 249 }, { 250 Namespace: "les", 251 Version: "1.0", 252 Service: NewPrivateLightAPI(&s.lesCommons), 253 Public: false, 254 }, { 255 Namespace: "lespay", 256 Version: "1.0", 257 Service: lpc.NewPrivateClientAPI(s.valueTracker), 258 Public: false, 259 }, 260 }...) 261 } 262 263 func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { 264 s.blockchain.ResetWithGenesisBlock(gb) 265 } 266 267 func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } 268 func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } 269 func (s *LightEthereum) Engine() consensus.Engine { return s.engine } 270 func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } 271 func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader } 272 func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } 273 274 // Protocols returns all the currently configured network protocols to start. 275 func (s *LightEthereum) Protocols() []p2p.Protocol { 276 return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} { 277 if p := s.peers.peer(id.String()); p != nil { 278 return p.Info() 279 } 280 return nil 281 }, s.dialCandidates) 282 } 283 284 // Start implements node.Lifecycle, starting all internal goroutines needed by the 285 // light ethereum protocol implementation. 286 func (s *LightEthereum) Start() error { 287 log.Warn("Light client mode is an experimental feature") 288 289 s.serverPool.start() 290 // Start bloom request workers. 291 s.wg.Add(bloomServiceThreads) 292 s.startBloomHandlers(params.BloomBitsBlocksClient) 293 s.handler.start() 294 295 return nil 296 } 297 298 // Stop implements node.Lifecycle, terminating all internal goroutines used by the 299 // Ethereum protocol. 300 func (s *LightEthereum) Stop() error { 301 close(s.closeCh) 302 s.serverPool.stop() 303 s.valueTracker.Stop() 304 s.peers.close() 305 s.reqDist.close() 306 s.odr.Stop() 307 s.relay.Stop() 308 s.bloomIndexer.Close() 309 s.chtIndexer.Close() 310 s.blockchain.Stop() 311 s.handler.stop() 312 s.txPool.Stop() 313 s.engine.Close() 314 s.pruner.close() 315 s.eventMux.Stop() 316 s.chainDb.Close() 317 s.wg.Wait() 318 log.Info("Light ethereum stopped") 319 return nil 320 }