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