github.com/Debrief-BC/go-debrief@v0.0.0-20200420203408-0c26ca968123/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/Debrief-BC/go-debrief/accounts" 24 "github.com/Debrief-BC/go-debrief/accounts/abi/bind" 25 "github.com/Debrief-BC/go-debrief/common" 26 "github.com/Debrief-BC/go-debrief/common/hexutil" 27 "github.com/Debrief-BC/go-debrief/common/mclock" 28 "github.com/Debrief-BC/go-debrief/consensus" 29 "github.com/Debrief-BC/go-debrief/core" 30 "github.com/Debrief-BC/go-debrief/core/bloombits" 31 "github.com/Debrief-BC/go-debrief/core/rawdb" 32 "github.com/Debrief-BC/go-debrief/core/types" 33 "github.com/Debrief-BC/go-debrief/eth" 34 "github.com/Debrief-BC/go-debrief/eth/downloader" 35 "github.com/Debrief-BC/go-debrief/eth/filters" 36 "github.com/Debrief-BC/go-debrief/eth/gasprice" 37 "github.com/Debrief-BC/go-debrief/event" 38 "github.com/Debrief-BC/go-debrief/internal/ethapi" 39 "github.com/Debrief-BC/go-debrief/les/checkpointoracle" 40 "github.com/Debrief-BC/go-debrief/light" 41 "github.com/Debrief-BC/go-debrief/log" 42 "github.com/Debrief-BC/go-debrief/node" 43 "github.com/Debrief-BC/go-debrief/p2p" 44 "github.com/Debrief-BC/go-debrief/p2p/enode" 45 "github.com/Debrief-BC/go-debrief/params" 46 "github.com/Debrief-BC/go-debrief/rpc" 47 ) 48 49 type LightEthereum struct { 50 lesCommons 51 52 peers *serverPeerSet 53 reqDist *requestDistributor 54 retriever *retrieveManager 55 odr *LesOdr 56 relay *lesTxRelay 57 handler *clientHandler 58 txPool *light.TxPool 59 blockchain *light.LightChain 60 serverPool *serverPool 61 62 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 63 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 64 65 ApiBackend *LesApiBackend 66 eventMux *event.TypeMux 67 engine consensus.Engine 68 accountManager *accounts.Manager 69 netRPCService *ethapi.PublicNetAPI 70 } 71 72 func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { 73 chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/") 74 if err != nil { 75 return nil, err 76 } 77 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, 78 config.OverrideIstanbul, config.OverrideMuirGlacier) 79 if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { 80 return nil, genesisErr 81 } 82 log.Info("Initialised chain configuration", "config", chainConfig) 83 84 peers := newServerPeerSet() 85 leth := &LightEthereum{ 86 lesCommons: lesCommons{ 87 genesis: genesisHash, 88 config: config, 89 chainConfig: chainConfig, 90 iConfig: light.DefaultClientIndexerConfig, 91 chainDb: chainDb, 92 closeCh: make(chan struct{}), 93 }, 94 peers: peers, 95 eventMux: ctx.EventMux, 96 reqDist: newRequestDistributor(peers, &mclock.System{}), 97 accountManager: ctx.AccountManager, 98 engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb), 99 bloomRequests: make(chan chan *bloombits.Retrieval), 100 bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), 101 serverPool: newServerPool(chainDb, config.UltraLightServers), 102 } 103 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 104 leth.relay = newLesTxRelay(peers, leth.retriever) 105 106 leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) 107 leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequency, params.HelperTrieConfirmations) 108 leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency) 109 leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) 110 111 checkpoint := config.Checkpoint 112 if checkpoint == nil { 113 checkpoint = params.TrustedCheckpoints[genesisHash] 114 } 115 // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with 116 // indexers already set but not started yet 117 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil { 118 return nil, err 119 } 120 leth.chainReader = leth.blockchain 121 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 122 123 // Set up checkpoint oracle. 124 oracle := config.CheckpointOracle 125 if oracle == nil { 126 oracle = params.CheckpointOracles[genesisHash] 127 } 128 leth.oracle = checkpointoracle.New(oracle, leth.localCheckpoint) 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 leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth) 136 if leth.handler.ulc != nil { 137 log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction) 138 leth.blockchain.DisableCheckFreq() 139 } 140 // Rewind the chain in case of an incompatible config upgrade. 141 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 142 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 143 leth.blockchain.SetHead(compat.RewindTo) 144 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 145 } 146 147 leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil} 148 gpoParams := config.GPO 149 if gpoParams.Default == nil { 150 gpoParams.Default = config.Miner.GasPrice 151 } 152 leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) 153 154 return leth, nil 155 } 156 157 type LightDummyAPI struct{} 158 159 // Etherbase is the address that mining rewards will be send to 160 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 161 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 162 } 163 164 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 165 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 166 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 167 } 168 169 // Hashrate returns the POW hashrate 170 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 171 return 0 172 } 173 174 // Mining returns an indication if this node is currently mining. 175 func (s *LightDummyAPI) Mining() bool { 176 return false 177 } 178 179 // APIs returns the collection of RPC services the ethereum package offers. 180 // NOTE, some of these services probably need to be moved to somewhere else. 181 func (s *LightEthereum) APIs() []rpc.API { 182 apis := ethapi.GetAPIs(s.ApiBackend) 183 apis = append(apis, s.engine.APIs(s.BlockChain().HeaderChain())...) 184 return append(apis, []rpc.API{ 185 { 186 Namespace: "eth", 187 Version: "1.0", 188 Service: &LightDummyAPI{}, 189 Public: true, 190 }, { 191 Namespace: "eth", 192 Version: "1.0", 193 Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), 194 Public: true, 195 }, { 196 Namespace: "eth", 197 Version: "1.0", 198 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 199 Public: true, 200 }, { 201 Namespace: "net", 202 Version: "1.0", 203 Service: s.netRPCService, 204 Public: true, 205 }, { 206 Namespace: "les", 207 Version: "1.0", 208 Service: NewPrivateLightAPI(&s.lesCommons), 209 Public: false, 210 }, 211 }...) 212 } 213 214 func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { 215 s.blockchain.ResetWithGenesisBlock(gb) 216 } 217 218 func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } 219 func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } 220 func (s *LightEthereum) Engine() consensus.Engine { return s.engine } 221 func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } 222 func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader } 223 func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } 224 225 // Protocols implements node.Service, returning all the currently configured 226 // network protocols to start. 227 func (s *LightEthereum) Protocols() []p2p.Protocol { 228 return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} { 229 if p := s.peers.peer(peerIdToString(id)); p != nil { 230 return p.Info() 231 } 232 return nil 233 }) 234 } 235 236 // Start implements node.Service, starting all internal goroutines needed by the 237 // light ethereum protocol implementation. 238 func (s *LightEthereum) Start(srvr *p2p.Server) error { 239 log.Warn("Light client mode is an experimental feature") 240 241 // Start bloom request workers. 242 s.wg.Add(bloomServiceThreads) 243 s.startBloomHandlers(params.BloomBitsBlocksClient) 244 245 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId) 246 247 // clients are searching for the first advertised protocol in the list 248 protocolVersion := AdvertiseProtocolVersions[0] 249 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 250 return nil 251 } 252 253 // Stop implements node.Service, terminating all internal goroutines used by the 254 // Ethereum protocol. 255 func (s *LightEthereum) Stop() error { 256 close(s.closeCh) 257 s.peers.close() 258 s.reqDist.close() 259 s.odr.Stop() 260 s.relay.Stop() 261 s.bloomIndexer.Close() 262 s.chtIndexer.Close() 263 s.blockchain.Stop() 264 s.handler.stop() 265 s.txPool.Stop() 266 s.engine.Close() 267 s.eventMux.Stop() 268 s.serverPool.stop() 269 s.chainDb.Close() 270 s.wg.Wait() 271 log.Info("Light ethereum stopped") 272 return nil 273 } 274 275 // SetClient sets the rpc client and binds the registrar contract. 276 func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) { 277 if s.oracle == nil { 278 return 279 } 280 s.oracle.Start(backend) 281 }