github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/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 istanbulBackend "github.com/ethereum/go-ethereum/consensus/istanbul/backend" 30 "github.com/ethereum/go-ethereum/contract_comm" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/bloombits" 33 "github.com/ethereum/go-ethereum/core/rawdb" 34 "github.com/ethereum/go-ethereum/core/types" 35 "github.com/ethereum/go-ethereum/eth" 36 "github.com/ethereum/go-ethereum/eth/downloader" 37 "github.com/ethereum/go-ethereum/eth/filters" 38 "github.com/ethereum/go-ethereum/event" 39 "github.com/ethereum/go-ethereum/internal/ethapi" 40 "github.com/ethereum/go-ethereum/light" 41 "github.com/ethereum/go-ethereum/log" 42 "github.com/ethereum/go-ethereum/node" 43 "github.com/ethereum/go-ethereum/p2p" 44 "github.com/ethereum/go-ethereum/p2p/discv5" 45 "github.com/ethereum/go-ethereum/params" 46 rpc "github.com/ethereum/go-ethereum/rpc" 47 ) 48 49 type LightEthereum struct { 50 lesCommons 51 52 odr *LesOdr 53 relay *LesTxRelay 54 chainConfig *params.ChainConfig 55 // Channel for shutting down the service 56 shutdownChan chan bool 57 58 // Handlers 59 peers *peerSet 60 txPool *light.TxPool 61 blockchain *light.LightChain 62 serverPool *serverPool 63 reqDist *requestDistributor 64 retriever *retrieveManager 65 chainreader *LightChainReader 66 67 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 68 bloomIndexer *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 var chainName string 84 syncMode := config.SyncMode 85 var fullChainAvailable bool 86 if syncMode == downloader.LightSync { 87 chainName = "lightchaindata" 88 fullChainAvailable = true 89 } else if syncMode == downloader.UltraLightSync { 90 chainName = "ultralightchaindata" 91 fullChainAvailable = false 92 } else { 93 panic("Unexpected sync mode: " + syncMode.String()) 94 } 95 chainDb, err := eth.CreateDB(ctx, config, chainName) 96 if err != nil { 97 return nil, err 98 } 99 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.ConstantinopleOverride) 100 if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { 101 return nil, genesisErr 102 } 103 log.Info("Initialised chain configuration", "config", chainConfig) 104 105 peers := newPeerSet() 106 quitSync := make(chan struct{}) 107 108 leth := &LightEthereum{ 109 lesCommons: lesCommons{ 110 chainDb: chainDb, 111 config: config, 112 iConfig: light.DefaultClientIndexerConfig, 113 }, 114 chainConfig: chainConfig, 115 eventMux: ctx.EventMux, 116 peers: peers, 117 reqDist: newRequestDistributor(peers, quitSync), 118 accountManager: ctx.AccountManager, 119 engine: eth.CreateConsensusEngine(ctx, chainConfig, config, nil, false, chainDb), 120 shutdownChan: make(chan bool), 121 networkId: config.NetworkId, 122 bloomRequests: make(chan chan *bloombits.Retrieval), 123 bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations, fullChainAvailable), 124 } 125 126 if syncMode == downloader.UltraLightSync && chainConfig.Istanbul == nil { 127 msg := fmt.Sprintf( 128 "To use UltraLightSync sync mode, run the node with Istanbul BFT consensus %v", chainConfig) 129 panic(msg) 130 } 131 132 leth.relay = NewLesTxRelay(peers, leth.reqDist) 133 leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg) 134 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 135 136 leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) 137 leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequencyClient, params.HelperTrieConfirmations, fullChainAvailable) 138 leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency, fullChainAvailable) 139 leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) 140 141 // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with 142 // indexers already set but not started yet 143 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil { 144 return nil, err 145 } 146 147 // Set the blockchain for the EVMHandler singleton that geth can use to make calls to smart contracts. 148 // Note that this should NOT be used when executing smart contract calls done via end user transactions. 149 contract_comm.SetInternalEVMHandler(leth.blockchain) 150 151 // Note: AddChildIndexer starts the update process for the child 152 leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer) 153 leth.chtIndexer.Start(leth.blockchain) 154 leth.bloomIndexer.Start(leth.blockchain) 155 156 // Rewind the chain in case of an incompatible config upgrade. 157 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 158 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 159 leth.blockchain.SetHead(compat.RewindTo) 160 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 161 } 162 163 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 164 leth.protocolManager, err = NewProtocolManager( 165 leth.chainConfig, light.DefaultClientIndexerConfig, syncMode, 166 config.NetworkId, leth.eventMux, leth.engine, leth.peers, 167 leth.blockchain, nil, chainDb, leth.odr, leth.relay, 168 leth.serverPool, quitSync, &leth.wg, config.Etherbase, config.GatewayFee, 169 ) 170 if err != nil { 171 return nil, err 172 } 173 leth.ApiBackend = &LesApiBackend{leth} 174 175 leth.chainreader = &LightChainReader{ 176 config: leth.chainConfig, 177 blockchain: leth.blockchain, 178 } 179 180 // If the engine is istanbul, then inject the blockchain 181 if istanbul, isIstanbul := leth.engine.(*istanbulBackend.Backend); isIstanbul { 182 istanbul.SetChain(leth.chainreader, nil) 183 } 184 185 return leth, nil 186 } 187 188 func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic { 189 var name string 190 switch protocolVersion { 191 case lpv1: 192 name = "LES" 193 case lpv2: 194 name = "LES2" 195 default: 196 panic(nil) 197 } 198 return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8])) 199 } 200 201 type LightDummyAPI struct{} 202 203 // Etherbase is the address that mining rewards will be send to 204 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 205 return common.Address{}, fmt.Errorf("not supported") 206 } 207 208 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 209 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 210 return common.Address{}, fmt.Errorf("not supported") 211 } 212 213 // Hashrate returns the POW hashrate 214 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 215 return 0 216 } 217 218 // Mining returns an indication if this node is currently mining. 219 func (s *LightDummyAPI) Mining() bool { 220 return false 221 } 222 223 // APIs returns the collection of RPC services the ethereum package offers. 224 // NOTE, some of these services probably need to be moved to somewhere else. 225 func (s *LightEthereum) APIs() []rpc.API { 226 return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{ 227 { 228 Namespace: "eth", 229 Version: "1.0", 230 Service: &LightDummyAPI{}, 231 Public: true, 232 }, { 233 Namespace: "eth", 234 Version: "1.0", 235 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 236 Public: true, 237 }, { 238 Namespace: "eth", 239 Version: "1.0", 240 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 241 Public: true, 242 }, { 243 Namespace: "net", 244 Version: "1.0", 245 Service: s.netRPCService, 246 Public: true, 247 }, 248 }...) 249 } 250 251 func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { 252 s.blockchain.ResetWithGenesisBlock(gb) 253 } 254 255 func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } 256 func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } 257 func (s *LightEthereum) Engine() consensus.Engine { return s.engine } 258 func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } 259 func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 260 func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } 261 262 // Protocols implements node.Service, returning all the currently configured 263 // network protocols to start. 264 func (s *LightEthereum) Protocols() []p2p.Protocol { 265 return s.makeProtocols(ClientProtocolVersions) 266 } 267 268 // Start implements node.Service, starting all internal goroutines needed by the 269 // Ethereum protocol implementation. 270 func (s *LightEthereum) Start(srvr *p2p.Server) error { 271 log.Warn("Light client mode is an experimental feature") 272 s.startBloomHandlers(params.BloomBitsBlocksClient) 273 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId) 274 // clients are searching for the first advertised protocol in the list 275 protocolVersion := AdvertiseProtocolVersions[0] 276 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 277 s.protocolManager.Start(s.config.LightPeers) 278 return nil 279 } 280 281 func (s *LightEthereum) GetRandomPeerEtherbase() common.Address { 282 return s.peers.randomPeerEtherbase() 283 } 284 285 // Stop implements node.Service, terminating all internal goroutines used by the 286 // Ethereum protocol. 287 func (s *LightEthereum) Stop() error { 288 s.odr.Stop() 289 s.bloomIndexer.Close() 290 s.chtIndexer.Close() 291 s.blockchain.Stop() 292 s.protocolManager.Stop() 293 s.txPool.Stop() 294 s.engine.Close() 295 296 s.eventMux.Stop() 297 298 time.Sleep(time.Millisecond * 200) 299 s.chainDb.Close() 300 close(s.shutdownChan) 301 302 return nil 303 }