github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/les/client.go (about) 1 // Copyright 2019 The ebakus/go-ebakus Authors 2 // This file is part of the ebakus/go-ebakus library. 3 // 4 // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package les implements the Light Ebakus Subprotocol. 18 package les 19 20 import ( 21 "fmt" 22 23 "github.com/ebakus/go-ebakus/accounts" 24 "github.com/ebakus/go-ebakus/accounts/abi/bind" 25 "github.com/ebakus/go-ebakus/common" 26 "github.com/ebakus/go-ebakus/common/hexutil" 27 "github.com/ebakus/go-ebakus/common/mclock" 28 "github.com/ebakus/go-ebakus/consensus" 29 "github.com/ebakus/go-ebakus/core" 30 "github.com/ebakus/go-ebakus/core/bloombits" 31 "github.com/ebakus/go-ebakus/core/rawdb" 32 "github.com/ebakus/go-ebakus/core/types" 33 "github.com/ebakus/go-ebakus/eth" 34 "github.com/ebakus/go-ebakus/eth/downloader" 35 "github.com/ebakus/go-ebakus/eth/filters" 36 "github.com/ebakus/go-ebakus/eth/gasprice" 37 "github.com/ebakus/go-ebakus/event" 38 "github.com/ebakus/go-ebakus/internal/ethapi" 39 "github.com/ebakus/go-ebakus/light" 40 "github.com/ebakus/go-ebakus/log" 41 "github.com/ebakus/go-ebakus/node" 42 "github.com/ebakus/go-ebakus/p2p" 43 "github.com/ebakus/go-ebakus/p2p/enode" 44 "github.com/ebakus/go-ebakus/params" 45 "github.com/ebakus/go-ebakus/rpc" 46 ) 47 48 type LightEbakus 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) (*LightEbakus, error) { 71 chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/") 72 if err != nil { 73 return nil, err 74 } 75 stateDb, err := eth.CreateEbakusDB(ctx, config, "state.db") 76 if err != nil { 77 return nil, err 78 } 79 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, stateDb, config.Genesis) 80 if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { 81 return nil, genesisErr 82 } 83 log.Info("Initialised chain configuration", "config", chainConfig) 84 85 peers := newPeerSet() 86 leth := &LightEbakus{ 87 lesCommons: lesCommons{ 88 genesis: genesisHash, 89 config: config, 90 chainConfig: chainConfig, 91 iConfig: light.DefaultClientIndexerConfig, 92 chainDb: chainDb, 93 peers: peers, 94 closeCh: make(chan struct{}), 95 }, 96 eventMux: ctx.EventMux, 97 reqDist: newRequestDistributor(peers, &mclock.System{}), 98 accountManager: ctx.AccountManager, 99 engine: eth.CreateConsensusEngine(ctx, &config.DPOS, chainConfig, chainDb, stateDb, config.Genesis), 100 bloomRequests: make(chan chan *bloombits.Retrieval), 101 bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), 102 serverPool: newServerPool(chainDb, config.UltraLightServers), 103 } 104 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 105 leth.relay = newLesTxRelay(peers, leth.retriever) 106 107 leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) 108 leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequency, params.HelperTrieConfirmations) 109 leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency) 110 leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) 111 112 checkpoint := config.Checkpoint 113 // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with 114 // indexers already set but not started yet 115 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil { 116 return nil, err 117 } 118 leth.chainReader = leth.blockchain 119 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 120 121 // Set up checkpoint oracle. 122 oracle := config.CheckpointOracle 123 leth.oracle = newCheckpointOracle(oracle, leth.localCheckpoint) 124 125 // Note: AddChildIndexer starts the update process for the child 126 leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer) 127 leth.chtIndexer.Start(leth.blockchain) 128 leth.bloomIndexer.Start(leth.blockchain) 129 130 leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth) 131 if leth.handler.ulc != nil { 132 log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction) 133 leth.blockchain.DisableCheckFreq() 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.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil} 143 gpoParams := config.GPO 144 if gpoParams.Default == nil { 145 gpoParams.Default = &config.Miner.GasPrice 146 } 147 leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) 148 149 return leth, nil 150 } 151 152 type LightDummyAPI struct{} 153 154 // Etherbase is the address that mining rewards will be send to 155 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 156 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 157 } 158 159 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 160 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 161 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 162 } 163 164 // Hashrate returns the POW hashrate 165 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 166 return 0 167 } 168 169 // Mining returns an indication if this node is currently mining. 170 func (s *LightDummyAPI) Mining() bool { 171 return false 172 } 173 174 // APIs returns the collection of RPC services the ebakus package offers. 175 // NOTE, some of these services probably need to be moved to somewhere else. 176 func (s *LightEbakus) APIs() []rpc.API { 177 return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{ 178 { 179 Namespace: "eth", 180 Version: "1.0", 181 Service: &LightDummyAPI{}, 182 Public: true, 183 }, { 184 Namespace: "eth", 185 Version: "1.0", 186 Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), 187 Public: true, 188 }, { 189 Namespace: "eth", 190 Version: "1.0", 191 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 192 Public: true, 193 }, { 194 Namespace: "net", 195 Version: "1.0", 196 Service: s.netRPCService, 197 Public: true, 198 }, { 199 Namespace: "les", 200 Version: "1.0", 201 Service: NewPrivateLightAPI(&s.lesCommons), 202 Public: false, 203 }, 204 }...) 205 } 206 207 func (s *LightEbakus) ResetWithGenesisBlock(gb *types.Block) { 208 s.blockchain.ResetWithGenesisBlock(gb) 209 } 210 211 func (s *LightEbakus) BlockChain() *light.LightChain { return s.blockchain } 212 func (s *LightEbakus) TxPool() *light.TxPool { return s.txPool } 213 func (s *LightEbakus) Engine() consensus.Engine { return s.engine } 214 func (s *LightEbakus) LesVersion() int { return int(ClientProtocolVersions[0]) } 215 func (s *LightEbakus) Downloader() *downloader.Downloader { return s.handler.downloader } 216 func (s *LightEbakus) EventMux() *event.TypeMux { return s.eventMux } 217 218 // Protocols implements node.Service, returning all the currently configured 219 // network protocols to start. 220 func (s *LightEbakus) Protocols() []p2p.Protocol { 221 return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} { 222 if p := s.peers.Peer(peerIdToString(id)); p != nil { 223 return p.Info() 224 } 225 return nil 226 }) 227 } 228 229 // Start implements node.Service, starting all internal goroutines needed by the 230 // light ebakus protocol implementation. 231 func (s *LightEbakus) Start(srvr *p2p.Server) error { 232 log.Warn("Light client mode is an experimental feature") 233 234 // Start bloom request workers. 235 s.wg.Add(bloomServiceThreads) 236 s.startBloomHandlers(params.BloomBitsBlocksClient) 237 238 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId) 239 240 // clients are searching for the first advertised protocol in the list 241 protocolVersion := AdvertiseProtocolVersions[0] 242 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 243 return nil 244 } 245 246 // Stop implements node.Service, terminating all internal goroutines used by the 247 // Ebakus protocol. 248 func (s *LightEbakus) Stop() error { 249 close(s.closeCh) 250 s.peers.Close() 251 s.reqDist.close() 252 s.odr.Stop() 253 s.relay.Stop() 254 s.bloomIndexer.Close() 255 s.chtIndexer.Close() 256 s.blockchain.Stop() 257 s.handler.stop() 258 s.txPool.Stop() 259 s.engine.Close() 260 s.eventMux.Stop() 261 s.serverPool.stop() 262 s.chainDb.Close() 263 s.wg.Wait() 264 log.Info("Light ebakus stopped") 265 return nil 266 } 267 268 // SetClient sets the rpc client and binds the registrar contract. 269 func (s *LightEbakus) SetContractBackend(backend bind.ContractBackend) { 270 if s.oracle == nil { 271 return 272 } 273 s.oracle.start(backend) 274 }