github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/les/backend.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum 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 "sync" 23 "time" 24 25 "github.com/SmartMeshFoundation/Spectrum/accounts" 26 "github.com/SmartMeshFoundation/Spectrum/common" 27 "github.com/SmartMeshFoundation/Spectrum/common/hexutil" 28 "github.com/SmartMeshFoundation/Spectrum/consensus" 29 "github.com/SmartMeshFoundation/Spectrum/core" 30 "github.com/SmartMeshFoundation/Spectrum/core/bloombits" 31 "github.com/SmartMeshFoundation/Spectrum/core/types" 32 "github.com/SmartMeshFoundation/Spectrum/eth" 33 "github.com/SmartMeshFoundation/Spectrum/eth/downloader" 34 "github.com/SmartMeshFoundation/Spectrum/eth/filters" 35 "github.com/SmartMeshFoundation/Spectrum/eth/gasprice" 36 "github.com/SmartMeshFoundation/Spectrum/ethdb" 37 "github.com/SmartMeshFoundation/Spectrum/event" 38 "github.com/SmartMeshFoundation/Spectrum/internal/ethapi" 39 "github.com/SmartMeshFoundation/Spectrum/light" 40 "github.com/SmartMeshFoundation/Spectrum/log" 41 "github.com/SmartMeshFoundation/Spectrum/node" 42 "github.com/SmartMeshFoundation/Spectrum/p2p" 43 "github.com/SmartMeshFoundation/Spectrum/p2p/discv5" 44 "github.com/SmartMeshFoundation/Spectrum/params" 45 rpc "github.com/SmartMeshFoundation/Spectrum/rpc" 46 ) 47 48 type LightEthereum struct { 49 odr *LesOdr 50 relay *LesTxRelay 51 chainConfig *params.ChainConfig 52 // Channel for shutting down the service 53 shutdownChan chan bool 54 // Handlers 55 peers *peerSet 56 txPool *light.TxPool 57 blockchain *light.LightChain 58 protocolManager *ProtocolManager 59 serverPool *serverPool 60 reqDist *requestDistributor 61 retriever *retrieveManager 62 // DB interfaces 63 chainDb ethdb.Database // Block chain database 64 65 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 66 bloomIndexer, chtIndexer, bloomTrieIndexer *core.ChainIndexer 67 68 ApiBackend *LesApiBackend 69 70 eventMux *event.TypeMux 71 engine consensus.Engine 72 accountManager *accounts.Manager 73 74 networkId uint64 75 netRPCService *ethapi.PublicNetAPI 76 77 wg sync.WaitGroup 78 } 79 80 func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { 81 chainDb, err := eth.CreateDB(ctx, config, "lightchaindata") 82 if err != nil { 83 return nil, err 84 } 85 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 86 if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { 87 return nil, genesisErr 88 } 89 log.Info("Initialised chain configuration", "config", chainConfig) 90 91 peers := newPeerSet() 92 quitSync := make(chan struct{}) 93 94 leth := &LightEthereum{ 95 chainConfig: chainConfig, 96 chainDb: chainDb, 97 eventMux: ctx.EventMux, 98 peers: peers, 99 reqDist: newRequestDistributor(peers, quitSync), 100 accountManager: ctx.AccountManager, 101 engine: eth.CreateConsensusEngine(ctx, &config.Ethash, chainConfig, chainDb), 102 shutdownChan: make(chan bool), 103 networkId: config.NetworkId, 104 bloomRequests: make(chan chan *bloombits.Retrieval), 105 bloomIndexer: eth.NewBloomIndexer(chainDb, light.BloomTrieFrequency), 106 chtIndexer: light.NewChtIndexer(chainDb, true), 107 bloomTrieIndexer: light.NewBloomTrieIndexer(chainDb, true), 108 } 109 110 leth.relay = NewLesTxRelay(peers, leth.reqDist) 111 leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg) 112 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 113 leth.odr = NewLesOdr(chainDb, leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer, leth.retriever) 114 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil { 115 return nil, err 116 } 117 leth.bloomIndexer.Start(leth.blockchain) 118 // Rewind the chain in case of an incompatible config upgrade. 119 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 120 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 121 leth.blockchain.SetHead(compat.RewindTo) 122 core.WriteChainConfig(chainDb, genesisHash, chainConfig) 123 } 124 125 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 126 if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, true, ClientProtocolVersions, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, quitSync, &leth.wg); err != nil { 127 return nil, err 128 } 129 leth.ApiBackend = &LesApiBackend{leth, nil} 130 gpoParams := config.GPO 131 if gpoParams.Default == nil { 132 gpoParams.Default = config.GasPrice 133 } 134 leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) 135 return leth, nil 136 } 137 138 func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic { 139 var name string 140 switch protocolVersion { 141 case lpv1: 142 name = "LES" 143 case lpv2: 144 name = "LES2" 145 default: 146 panic(nil) 147 } 148 return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8])) 149 } 150 151 type LightDummyAPI struct{} 152 153 // Etherbase is the address that mining rewards will be send to 154 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 155 return common.Address{}, fmt.Errorf("not supported") 156 } 157 158 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 159 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 160 return common.Address{}, fmt.Errorf("not supported") 161 } 162 163 // Hashrate returns the POW hashrate 164 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 165 return 0 166 } 167 168 // Mining returns an indication if this node is currently mining. 169 func (s *LightDummyAPI) Mining() bool { 170 return false 171 } 172 173 // APIs returns the collection of RPC services the ethereum package offers. 174 // NOTE, some of these services probably need to be moved to somewhere else. 175 func (s *LightEthereum) APIs() []rpc.API { 176 return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{ 177 { 178 Namespace: "eth", 179 Version: "1.0", 180 Service: &LightDummyAPI{}, 181 Public: true, 182 }, { 183 Namespace: "eth", 184 Version: "1.0", 185 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 186 Public: true, 187 }, { 188 Namespace: "eth", 189 Version: "1.0", 190 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 191 Public: true, 192 }, { 193 Namespace: "net", 194 Version: "1.0", 195 Service: s.netRPCService, 196 Public: true, 197 }, 198 }...) 199 } 200 201 func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { 202 s.blockchain.ResetWithGenesisBlock(gb) 203 } 204 205 func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } 206 func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } 207 func (s *LightEthereum) Engine() consensus.Engine { return s.engine } 208 func (s *LightEthereum) LesVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 209 func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 210 func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } 211 212 // Protocols implements node.Service, returning all the currently configured 213 // network protocols to start. 214 func (s *LightEthereum) Protocols() []p2p.Protocol { 215 return s.protocolManager.SubProtocols 216 } 217 218 // Start implements node.Service, starting all internal goroutines needed by the 219 // Ethereum protocol implementation. 220 func (s *LightEthereum) Start(srvr *p2p.Server) error { 221 s.startBloomHandlers() 222 log.Warn("Light client mode is an experimental feature") 223 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId) 224 // search the topic belonging to the oldest supported protocol because 225 // servers always advertise all supported protocols 226 protocolVersion := ClientProtocolVersions[len(ClientProtocolVersions)-1] 227 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 228 s.protocolManager.Start() 229 return nil 230 } 231 232 // Stop implements node.Service, terminating all internal goroutines used by the 233 // Ethereum protocol. 234 func (s *LightEthereum) Stop() error { 235 s.odr.Stop() 236 if s.bloomIndexer != nil { 237 s.bloomIndexer.Close() 238 } 239 if s.chtIndexer != nil { 240 s.chtIndexer.Close() 241 } 242 if s.bloomTrieIndexer != nil { 243 s.bloomTrieIndexer.Close() 244 } 245 s.blockchain.Stop() 246 s.protocolManager.Stop() 247 s.txPool.Stop() 248 249 s.eventMux.Stop() 250 251 time.Sleep(time.Millisecond * 200) 252 s.chainDb.Close() 253 close(s.shutdownChan) 254 255 return nil 256 }