github.com/letterj/go-ethereum@v1.8.22-0.20190204142846-520024dfd689/les/backend.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 "sync" 23 "time" 24 25 "github.com/ethereum/go-ethereum/accounts" 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/common/hexutil" 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/node" 42 "github.com/ethereum/go-ethereum/p2p" 43 "github.com/ethereum/go-ethereum/p2p/discv5" 44 "github.com/ethereum/go-ethereum/params" 45 rpc "github.com/ethereum/go-ethereum/rpc" 46 ) 47 48 type LightEthereum struct { 49 lesCommons 50 51 odr *LesOdr 52 relay *LesTxRelay 53 chainConfig *params.ChainConfig 54 // Channel for shutting down the service 55 shutdownChan chan bool 56 57 // Handlers 58 peers *peerSet 59 txPool *light.TxPool 60 blockchain *light.LightChain 61 serverPool *serverPool 62 reqDist *requestDistributor 63 retriever *retrieveManager 64 65 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 66 bloomIndexer *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.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.ConstantinopleOverride) 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 lesCommons: lesCommons{ 96 chainDb: chainDb, 97 config: config, 98 iConfig: light.DefaultClientIndexerConfig, 99 }, 100 chainConfig: chainConfig, 101 eventMux: ctx.EventMux, 102 peers: peers, 103 reqDist: newRequestDistributor(peers, quitSync), 104 accountManager: ctx.AccountManager, 105 engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb), 106 shutdownChan: make(chan bool), 107 networkId: config.NetworkId, 108 bloomRequests: make(chan chan *bloombits.Retrieval), 109 bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), 110 } 111 112 var trustedNodes []string 113 if leth.config.ULC != nil { 114 trustedNodes = leth.config.ULC.TrustedServers 115 } 116 leth.relay = NewLesTxRelay(peers, leth.reqDist) 117 leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg, trustedNodes) 118 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 119 120 leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) 121 leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequencyClient, params.HelperTrieConfirmations) 122 leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency) 123 leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) 124 125 // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with 126 // indexers already set but not started yet 127 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil { 128 return nil, err 129 } 130 // Note: AddChildIndexer starts the update process for the child 131 leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer) 132 leth.chtIndexer.Start(leth.blockchain) 133 leth.bloomIndexer.Start(leth.blockchain) 134 135 // Rewind the chain in case of an incompatible config upgrade. 136 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 137 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 138 leth.blockchain.SetHead(compat.RewindTo) 139 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 140 } 141 142 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 143 144 if leth.protocolManager, err = NewProtocolManager( 145 leth.chainConfig, 146 light.DefaultClientIndexerConfig, 147 true, 148 config.NetworkId, 149 leth.eventMux, 150 leth.engine, 151 leth.peers, 152 leth.blockchain, 153 nil, 154 chainDb, 155 leth.odr, 156 leth.relay, 157 leth.serverPool, 158 quitSync, 159 &leth.wg, 160 config.ULC); err != nil { 161 return nil, err 162 } 163 164 if leth.protocolManager.isULCEnabled() { 165 log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.protocolManager.ulc.trustedKeys), "minTrustedFraction", leth.protocolManager.ulc.minTrustedFraction) 166 leth.blockchain.DisableCheckFreq() 167 } 168 leth.ApiBackend = &LesApiBackend{leth, nil} 169 170 gpoParams := config.GPO 171 if gpoParams.Default == nil { 172 gpoParams.Default = config.MinerGasPrice 173 } 174 leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) 175 return leth, nil 176 } 177 178 func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic { 179 var name string 180 switch protocolVersion { 181 case lpv1: 182 name = "LES" 183 case lpv2: 184 name = "LES2" 185 default: 186 panic(nil) 187 } 188 return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8])) 189 } 190 191 type LightDummyAPI struct{} 192 193 // Etherbase is the address that mining rewards will be send to 194 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 195 return common.Address{}, fmt.Errorf("not supported") 196 } 197 198 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 199 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 200 return common.Address{}, fmt.Errorf("not supported") 201 } 202 203 // Hashrate returns the POW hashrate 204 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 205 return 0 206 } 207 208 // Mining returns an indication if this node is currently mining. 209 func (s *LightDummyAPI) Mining() bool { 210 return false 211 } 212 213 // APIs returns the collection of RPC services the ethereum package offers. 214 // NOTE, some of these services probably need to be moved to somewhere else. 215 func (s *LightEthereum) APIs() []rpc.API { 216 return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{ 217 { 218 Namespace: "eth", 219 Version: "1.0", 220 Service: &LightDummyAPI{}, 221 Public: true, 222 }, { 223 Namespace: "eth", 224 Version: "1.0", 225 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 226 Public: true, 227 }, { 228 Namespace: "eth", 229 Version: "1.0", 230 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 231 Public: true, 232 }, { 233 Namespace: "net", 234 Version: "1.0", 235 Service: s.netRPCService, 236 Public: true, 237 }, 238 }...) 239 } 240 241 func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { 242 s.blockchain.ResetWithGenesisBlock(gb) 243 } 244 245 func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } 246 func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } 247 func (s *LightEthereum) Engine() consensus.Engine { return s.engine } 248 func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } 249 func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 250 func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } 251 252 // Protocols implements node.Service, returning all the currently configured 253 // network protocols to start. 254 func (s *LightEthereum) Protocols() []p2p.Protocol { 255 return s.makeProtocols(ClientProtocolVersions) 256 } 257 258 // Start implements node.Service, starting all internal goroutines needed by the 259 // Ethereum protocol implementation. 260 func (s *LightEthereum) Start(srvr *p2p.Server) error { 261 log.Warn("Light client mode is an experimental feature") 262 s.startBloomHandlers(params.BloomBitsBlocksClient) 263 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId) 264 // clients are searching for the first advertised protocol in the list 265 protocolVersion := AdvertiseProtocolVersions[0] 266 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 267 s.protocolManager.Start(s.config.LightPeers) 268 return nil 269 } 270 271 // Stop implements node.Service, terminating all internal goroutines used by the 272 // Ethereum protocol. 273 func (s *LightEthereum) Stop() error { 274 s.odr.Stop() 275 s.bloomIndexer.Close() 276 s.chtIndexer.Close() 277 s.blockchain.Stop() 278 s.protocolManager.Stop() 279 s.txPool.Stop() 280 s.engine.Close() 281 282 s.eventMux.Stop() 283 284 time.Sleep(time.Millisecond * 200) 285 s.chainDb.Close() 286 close(s.shutdownChan) 287 288 return nil 289 }