github.com/core-coin/go-core/v2@v2.1.9/les/client.go (about) 1 // Copyright 2019 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package les implements the Light Core Subprotocol. 18 package les 19 20 import ( 21 "fmt" 22 "time" 23 24 "github.com/core-coin/go-core/v2/xcb/energyprice" 25 26 "github.com/core-coin/go-core/v2/internal/xcbapi" 27 28 "github.com/core-coin/go-core/v2/accounts" 29 "github.com/core-coin/go-core/v2/common" 30 "github.com/core-coin/go-core/v2/common/hexutil" 31 "github.com/core-coin/go-core/v2/common/mclock" 32 "github.com/core-coin/go-core/v2/consensus" 33 "github.com/core-coin/go-core/v2/core" 34 "github.com/core-coin/go-core/v2/core/bloombits" 35 "github.com/core-coin/go-core/v2/core/rawdb" 36 "github.com/core-coin/go-core/v2/core/types" 37 "github.com/core-coin/go-core/v2/event" 38 lpc "github.com/core-coin/go-core/v2/les/lespay/client" 39 "github.com/core-coin/go-core/v2/light" 40 "github.com/core-coin/go-core/v2/log" 41 "github.com/core-coin/go-core/v2/node" 42 "github.com/core-coin/go-core/v2/p2p" 43 "github.com/core-coin/go-core/v2/p2p/enode" 44 "github.com/core-coin/go-core/v2/params" 45 "github.com/core-coin/go-core/v2/rpc" 46 "github.com/core-coin/go-core/v2/xcb" 47 "github.com/core-coin/go-core/v2/xcb/downloader" 48 "github.com/core-coin/go-core/v2/xcb/filters" 49 ) 50 51 type LightCore struct { 52 lesCommons 53 54 peers *serverPeerSet 55 reqDist *requestDistributor 56 retriever *retrieveManager 57 odr *LesOdr 58 relay *lesTxRelay 59 handler *clientHandler 60 txPool *light.TxPool 61 blockchain *light.LightChain 62 serverPool *serverPool 63 valueTracker *lpc.ValueTracker 64 dialCandidates enode.Iterator 65 pruner *pruner 66 67 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 68 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 69 70 ApiBackend *LesApiBackend 71 eventMux *event.TypeMux 72 engine consensus.Engine 73 accountManager *accounts.Manager 74 netRPCService *xcbapi.PublicNetAPI 75 76 p2pServer *p2p.Server 77 } 78 79 // New creates an instance of the light client. 80 func New(stack *node.Node, config *xcb.Config) (*LightCore, error) { 81 chainDb, err := stack.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "xcb/db/chaindata/") 82 if err != nil { 83 return nil, err 84 } 85 lespayDb, err := stack.OpenDatabase("lespay", 0, 0, "xcb/db/lespay") 86 if err != nil { 87 return nil, err 88 } 89 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 90 if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { 91 return nil, genesisErr 92 } 93 log.Info("Initialised chain configuration", "config", chainConfig) 94 95 peers := newServerPeerSet() 96 lxcb := &LightCore{ 97 lesCommons: lesCommons{ 98 genesis: genesisHash, 99 config: config, 100 chainConfig: chainConfig, 101 iConfig: light.DefaultClientIndexerConfig, 102 chainDb: chainDb, 103 closeCh: make(chan struct{}), 104 }, 105 peers: peers, 106 eventMux: stack.EventMux(), 107 reqDist: newRequestDistributor(peers, &mclock.System{}), 108 accountManager: stack.AccountManager(), 109 engine: xcb.CreateConsensusEngine(stack, chainConfig, &config.Cryptore, nil, false, chainDb), 110 bloomRequests: make(chan chan *bloombits.Retrieval), 111 bloomIndexer: xcb.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), 112 valueTracker: lpc.NewValueTracker(lespayDb, &mclock.System{}, requestList, time.Minute, 1/float64(time.Hour), 1/float64(time.Hour*100), 1/float64(time.Hour*1000)), 113 p2pServer: stack.Server(), 114 } 115 peers.subscribe((*vtSubscription)(lxcb.valueTracker)) 116 117 dnsdisc, err := lxcb.setupDiscovery() 118 if err != nil { 119 return nil, err 120 } 121 lxcb.serverPool = newServerPool(lespayDb, []byte("serverpool:"), lxcb.valueTracker, dnsdisc, time.Second, nil, &mclock.System{}, config.UltraLightServers) 122 peers.subscribe(lxcb.serverPool) 123 lxcb.dialCandidates = lxcb.serverPool.dialIterator 124 125 lxcb.retriever = newRetrieveManager(peers, lxcb.reqDist, lxcb.serverPool.getTimeout) 126 lxcb.relay = newLesTxRelay(peers, lxcb.retriever) 127 128 lxcb.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, lxcb.retriever) 129 lxcb.chtIndexer = light.NewChtIndexer(chainDb, lxcb.odr, params.CHTFrequency, params.HelperTrieConfirmations, config.LightNoPrune) 130 lxcb.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, lxcb.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency, config.LightNoPrune) 131 lxcb.odr.SetIndexers(lxcb.chtIndexer, lxcb.bloomTrieIndexer, lxcb.bloomIndexer) 132 133 checkpoint := config.Checkpoint 134 if checkpoint == nil { 135 checkpoint = params.TrustedCheckpoints[genesisHash] 136 } 137 // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with 138 // indexers already set but not started yet 139 if lxcb.blockchain, err = light.NewLightChain(lxcb.odr, lxcb.chainConfig, lxcb.engine, checkpoint); err != nil { 140 return nil, err 141 } 142 lxcb.chainReader = lxcb.blockchain 143 lxcb.txPool = light.NewTxPool(lxcb.chainConfig, lxcb.blockchain, lxcb.relay) 144 145 // Set up checkpoint oracle. 146 lxcb.oracle = lxcb.setupOracle(stack, genesisHash, config) 147 148 // Note: AddChildIndexer starts the update process for the child 149 lxcb.bloomIndexer.AddChildIndexer(lxcb.bloomTrieIndexer) 150 lxcb.chtIndexer.Start(lxcb.blockchain) 151 lxcb.bloomIndexer.Start(lxcb.blockchain) 152 153 // Start a light chain pruner to delete useless historical data. 154 lxcb.pruner = newPruner(chainDb, lxcb.chtIndexer, lxcb.bloomTrieIndexer) 155 156 // Rewind the chain in case of an incompatible config upgrade. 157 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 158 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 159 lxcb.blockchain.SetHead(compat.RewindTo) 160 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 161 } 162 163 lxcb.ApiBackend = &LesApiBackend{stack.Config().ExtRPCEnabled(), lxcb, nil} 164 gpoParams := config.GPO 165 if gpoParams.Default == nil { 166 gpoParams.Default = config.Miner.EnergyPrice 167 } 168 lxcb.ApiBackend.gpo = energyprice.NewOracle(lxcb.ApiBackend, gpoParams) 169 170 lxcb.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, lxcb) 171 if lxcb.handler.ulc != nil { 172 log.Warn("Ultra light client is enabled", "trustedNodes", len(lxcb.handler.ulc.keys), "minTrustedFraction", lxcb.handler.ulc.fraction) 173 lxcb.blockchain.DisableCheckFreq() 174 } 175 176 lxcb.netRPCService = xcbapi.NewPublicNetAPI(lxcb.p2pServer, lxcb.config.NetworkId) 177 178 // Register the backend on the node 179 stack.RegisterAPIs(lxcb.APIs()) 180 stack.RegisterProtocols(lxcb.Protocols()) 181 stack.RegisterLifecycle(lxcb) 182 183 return lxcb, nil 184 } 185 186 // vtSubscription implements serverPeerSubscriber 187 type vtSubscription lpc.ValueTracker 188 189 // registerPeer implements serverPeerSubscriber 190 func (v *vtSubscription) registerPeer(p *serverPeer) { 191 vt := (*lpc.ValueTracker)(v) 192 p.setValueTracker(vt, vt.Register(p.ID())) 193 p.updateVtParams() 194 } 195 196 // unregisterPeer implements serverPeerSubscriber 197 func (v *vtSubscription) unregisterPeer(p *serverPeer) { 198 vt := (*lpc.ValueTracker)(v) 199 vt.Unregister(p.ID()) 200 p.setValueTracker(nil, nil) 201 } 202 203 type LightDummyAPI struct{} 204 205 // Corebase is the address that mining rewards will be send to 206 func (s *LightDummyAPI) Corebase() (common.Address, error) { 207 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 208 } 209 210 // Coinbase is the address that mining rewards will be send to (alias for Corebase) 211 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 212 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 213 } 214 215 // Hashrate returns the POW hashrate 216 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 217 return 0 218 } 219 220 // Mining returns an indication if this node is currently mining. 221 func (s *LightDummyAPI) Mining() bool { 222 return false 223 } 224 225 // APIs returns the collection of RPC services the core package offers. 226 // NOTE, some of these services probably need to be moved to somewhere else. 227 func (s *LightCore) APIs() []rpc.API { 228 apis := xcbapi.GetAPIs(s.ApiBackend) 229 apis = append(apis, s.engine.APIs(s.BlockChain().HeaderChain())...) 230 return append(apis, []rpc.API{ 231 { 232 Namespace: "xcb", 233 Version: "1.0", 234 Service: &LightDummyAPI{}, 235 Public: true, 236 }, { 237 Namespace: "xcb", 238 Version: "1.0", 239 Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), 240 Public: true, 241 }, { 242 Namespace: "xcb", 243 Version: "1.0", 244 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 245 Public: true, 246 }, { 247 Namespace: "net", 248 Version: "1.0", 249 Service: s.netRPCService, 250 Public: true, 251 }, { 252 Namespace: "les", 253 Version: "1.0", 254 Service: NewPrivateLightAPI(&s.lesCommons), 255 Public: false, 256 }, { 257 Namespace: "lespay", 258 Version: "1.0", 259 Service: lpc.NewPrivateClientAPI(s.valueTracker), 260 Public: false, 261 }, 262 }...) 263 } 264 265 func (s *LightCore) ResetWithGenesisBlock(gb *types.Block) { 266 s.blockchain.ResetWithGenesisBlock(gb) 267 } 268 269 func (s *LightCore) BlockChain() *light.LightChain { return s.blockchain } 270 func (s *LightCore) TxPool() *light.TxPool { return s.txPool } 271 func (s *LightCore) Engine() consensus.Engine { return s.engine } 272 func (s *LightCore) LesVersion() int { return int(ClientProtocolVersions[0]) } 273 func (s *LightCore) Downloader() *downloader.Downloader { return s.handler.downloader } 274 func (s *LightCore) EventMux() *event.TypeMux { return s.eventMux } 275 276 // Protocols returns all the currently configured network protocols to start. 277 func (s *LightCore) Protocols() []p2p.Protocol { 278 return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} { 279 if p := s.peers.peer(id.String()); p != nil { 280 return p.Info() 281 } 282 return nil 283 }, s.dialCandidates) 284 } 285 286 // Start implements node.Lifecycle, starting all internal goroutines needed by the 287 // light core protocol implementation. 288 func (s *LightCore) Start() error { 289 log.Warn("Light client mode is an experimental feature") 290 291 s.serverPool.start() 292 // Start bloom request workers. 293 s.wg.Add(bloomServiceThreads) 294 s.startBloomHandlers(params.BloomBitsBlocksClient) 295 s.handler.start() 296 297 return nil 298 } 299 300 // Stop implements node.Lifecycle, terminating all internal goroutines used by the 301 // Core protocol. 302 func (s *LightCore) Stop() error { 303 close(s.closeCh) 304 s.serverPool.stop() 305 s.valueTracker.Stop() 306 s.peers.close() 307 s.reqDist.close() 308 s.odr.Stop() 309 s.relay.Stop() 310 s.bloomIndexer.Close() 311 s.chtIndexer.Close() 312 s.blockchain.Stop() 313 s.handler.stop() 314 s.txPool.Stop() 315 s.engine.Close() 316 s.pruner.close() 317 s.eventMux.Stop() 318 s.chainDb.Close() 319 s.wg.Wait() 320 log.Info("Light core stopped") 321 return nil 322 }