github.com/Openstars/go-ethereum@v1.9.7/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 23 "github.com/ethereum/go-ethereum/accounts" 24 "github.com/ethereum/go-ethereum/accounts/abi/bind" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/common/hexutil" 27 "github.com/ethereum/go-ethereum/common/mclock" 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/enode" 44 "github.com/ethereum/go-ethereum/params" 45 "github.com/ethereum/go-ethereum/rpc" 46 ) 47 48 type LightEthereum struct { 49 lesCommons 50 51 reqDist *requestDistributor 52 retriever *retrieveManager 53 odr *LesOdr 54 relay *lesTxRelay 55 handler *clientHandler 56 txPool *light.TxPool 57 blockchain *light.LightChain 58 serverPool *serverPool 59 60 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 61 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 62 63 ApiBackend *LesApiBackend 64 eventMux *event.TypeMux 65 engine consensus.Engine 66 accountManager *accounts.Manager 67 netRPCService *ethapi.PublicNetAPI 68 } 69 70 func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { 71 chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/") 72 if err != nil { 73 return nil, err 74 } 75 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideIstanbul) 76 if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { 77 return nil, genesisErr 78 } 79 log.Info("Initialised chain configuration", "config", chainConfig) 80 81 peers := newPeerSet() 82 leth := &LightEthereum{ 83 lesCommons: lesCommons{ 84 genesis: genesisHash, 85 config: config, 86 chainConfig: chainConfig, 87 iConfig: light.DefaultClientIndexerConfig, 88 chainDb: chainDb, 89 peers: peers, 90 closeCh: make(chan struct{}), 91 }, 92 eventMux: ctx.EventMux, 93 reqDist: newRequestDistributor(peers, &mclock.System{}), 94 accountManager: ctx.AccountManager, 95 engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb), 96 bloomRequests: make(chan chan *bloombits.Retrieval), 97 bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), 98 serverPool: newServerPool(chainDb, config.UltraLightServers), 99 } 100 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 101 leth.relay = newLesTxRelay(peers, leth.retriever) 102 103 leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) 104 leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequency, params.HelperTrieConfirmations) 105 leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency) 106 leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) 107 108 checkpoint := config.Checkpoint 109 if checkpoint == nil { 110 checkpoint = params.TrustedCheckpoints[genesisHash] 111 } 112 // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with 113 // indexers already set but not started yet 114 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil { 115 return nil, err 116 } 117 leth.chainReader = leth.blockchain 118 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 119 120 // Set up checkpoint oracle. 121 oracle := config.CheckpointOracle 122 if oracle == nil { 123 oracle = params.CheckpointOracles[genesisHash] 124 } 125 leth.oracle = newCheckpointOracle(oracle, leth.localCheckpoint) 126 127 // Note: AddChildIndexer starts the update process for the child 128 leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer) 129 leth.chtIndexer.Start(leth.blockchain) 130 leth.bloomIndexer.Start(leth.blockchain) 131 132 leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth) 133 if leth.handler.ulc != nil { 134 log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction) 135 leth.blockchain.DisableCheckFreq() 136 } 137 // Rewind the chain in case of an incompatible config upgrade. 138 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 139 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 140 leth.blockchain.SetHead(compat.RewindTo) 141 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 142 } 143 144 leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil} 145 gpoParams := config.GPO 146 if gpoParams.Default == nil { 147 gpoParams.Default = config.Miner.GasPrice 148 } 149 leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) 150 151 return leth, nil 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("mining is not supported in light mode") 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("mining is not supported in light mode") 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.handler.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 Namespace: "les", 202 Version: "1.0", 203 Service: NewPrivateLightAPI(&s.lesCommons), 204 Public: false, 205 }, 206 }...) 207 } 208 209 func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { 210 s.blockchain.ResetWithGenesisBlock(gb) 211 } 212 213 func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } 214 func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } 215 func (s *LightEthereum) Engine() consensus.Engine { return s.engine } 216 func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } 217 func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader } 218 func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } 219 220 // Protocols implements node.Service, returning all the currently configured 221 // network protocols to start. 222 func (s *LightEthereum) Protocols() []p2p.Protocol { 223 return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} { 224 if p := s.peers.Peer(peerIdToString(id)); p != nil { 225 return p.Info() 226 } 227 return nil 228 }) 229 } 230 231 // Start implements node.Service, starting all internal goroutines needed by the 232 // light ethereum protocol implementation. 233 func (s *LightEthereum) Start(srvr *p2p.Server) error { 234 log.Warn("Light client mode is an experimental feature") 235 236 // Start bloom request workers. 237 s.wg.Add(bloomServiceThreads) 238 s.startBloomHandlers(params.BloomBitsBlocksClient) 239 240 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId) 241 242 // clients are searching for the first advertised protocol in the list 243 protocolVersion := AdvertiseProtocolVersions[0] 244 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 245 return nil 246 } 247 248 // Stop implements node.Service, terminating all internal goroutines used by the 249 // Ethereum protocol. 250 func (s *LightEthereum) Stop() error { 251 close(s.closeCh) 252 s.peers.Close() 253 s.reqDist.close() 254 s.odr.Stop() 255 s.relay.Stop() 256 s.bloomIndexer.Close() 257 s.chtIndexer.Close() 258 s.blockchain.Stop() 259 s.handler.stop() 260 s.txPool.Stop() 261 s.engine.Close() 262 s.eventMux.Stop() 263 s.serverPool.stop() 264 s.chainDb.Close() 265 s.wg.Wait() 266 log.Info("Light ethereum stopped") 267 return nil 268 } 269 270 // SetClient sets the rpc client and binds the registrar contract. 271 func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) { 272 if s.oracle == nil { 273 return 274 } 275 s.oracle.start(backend) 276 }