github.com/bloxroute-labs/bor@v0.1.4/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/maticnetwork/bor/accounts" 26 "github.com/maticnetwork/bor/accounts/abi/bind" 27 "github.com/maticnetwork/bor/common" 28 "github.com/maticnetwork/bor/common/hexutil" 29 "github.com/maticnetwork/bor/common/mclock" 30 "github.com/maticnetwork/bor/consensus" 31 "github.com/maticnetwork/bor/core" 32 "github.com/maticnetwork/bor/core/bloombits" 33 "github.com/maticnetwork/bor/core/rawdb" 34 "github.com/maticnetwork/bor/core/types" 35 "github.com/maticnetwork/bor/eth" 36 "github.com/maticnetwork/bor/eth/downloader" 37 "github.com/maticnetwork/bor/eth/filters" 38 "github.com/maticnetwork/bor/eth/gasprice" 39 "github.com/maticnetwork/bor/event" 40 "github.com/maticnetwork/bor/internal/ethapi" 41 "github.com/maticnetwork/bor/light" 42 "github.com/maticnetwork/bor/log" 43 "github.com/maticnetwork/bor/node" 44 "github.com/maticnetwork/bor/p2p" 45 "github.com/maticnetwork/bor/p2p/discv5" 46 "github.com/maticnetwork/bor/params" 47 "github.com/maticnetwork/bor/rpc" 48 ) 49 50 type LightEthereum struct { 51 lesCommons 52 53 odr *LesOdr 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 relay *lesTxRelay 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 chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/") 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 lesCommons: lesCommons{ 98 chainDb: chainDb, 99 config: config, 100 iConfig: light.DefaultClientIndexerConfig, 101 }, 102 chainConfig: chainConfig, 103 eventMux: ctx.EventMux, 104 peers: peers, 105 reqDist: newRequestDistributor(peers, quitSync, &mclock.System{}), 106 accountManager: ctx.AccountManager, 107 engine: nil, 108 shutdownChan: make(chan bool), 109 networkId: config.NetworkId, 110 bloomRequests: make(chan chan *bloombits.Retrieval), 111 bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), 112 } 113 leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg, leth.config.UltraLightServers) 114 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 115 leth.relay = newLesTxRelay(peers, leth.retriever) 116 117 leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) 118 leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequency, params.HelperTrieConfirmations) 119 leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency) 120 leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) 121 122 checkpoint := config.Checkpoint 123 if checkpoint == nil { 124 checkpoint = params.TrustedCheckpoints[genesisHash] 125 } 126 // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with 127 // indexers already set but not started yet 128 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil { 129 return nil, err 130 } 131 // Note: AddChildIndexer starts the update process for the child 132 leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer) 133 leth.chtIndexer.Start(leth.blockchain) 134 leth.bloomIndexer.Start(leth.blockchain) 135 136 // Rewind the chain in case of an incompatible config upgrade. 137 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 138 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 139 leth.blockchain.SetHead(compat.RewindTo) 140 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 141 } 142 143 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 144 leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil} 145 146 gpoParams := config.GPO 147 if gpoParams.Default == nil { 148 gpoParams.Default = config.Miner.GasPrice 149 } 150 leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) 151 152 oracle := config.CheckpointOracle 153 if oracle == nil { 154 oracle = params.CheckpointOracles[genesisHash] 155 } 156 registrar := newCheckpointOracle(oracle, leth.getLocalCheckpoint) 157 if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, checkpoint, light.DefaultClientIndexerConfig, config.UltraLightServers, config.UltraLightFraction, true, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.serverPool, registrar, quitSync, &leth.wg, nil); err != nil { 158 return nil, err 159 } 160 if leth.protocolManager.ulc != nil { 161 log.Warn("Ultra light client is enabled", "servers", len(config.UltraLightServers), "fraction", config.UltraLightFraction) 162 leth.blockchain.DisableCheckFreq() 163 } 164 return leth, nil 165 } 166 167 func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic { 168 var name string 169 switch protocolVersion { 170 case lpv2: 171 name = "LES2" 172 default: 173 panic(nil) 174 } 175 return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8])) 176 } 177 178 type LightDummyAPI struct{} 179 180 // Etherbase is the address that mining rewards will be send to 181 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 182 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 183 } 184 185 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 186 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 187 return common.Address{}, fmt.Errorf("mining is not supported in light mode") 188 } 189 190 // Hashrate returns the POW hashrate 191 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 192 return 0 193 } 194 195 // Mining returns an indication if this node is currently mining. 196 func (s *LightDummyAPI) Mining() bool { 197 return false 198 } 199 200 // APIs returns the collection of RPC services the ethereum package offers. 201 // NOTE, some of these services probably need to be moved to somewhere else. 202 func (s *LightEthereum) APIs() []rpc.API { 203 return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{ 204 { 205 Namespace: "eth", 206 Version: "1.0", 207 Service: &LightDummyAPI{}, 208 Public: true, 209 }, { 210 Namespace: "eth", 211 Version: "1.0", 212 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 213 Public: true, 214 }, { 215 Namespace: "eth", 216 Version: "1.0", 217 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 218 Public: true, 219 }, { 220 Namespace: "net", 221 Version: "1.0", 222 Service: s.netRPCService, 223 Public: true, 224 }, { 225 Namespace: "les", 226 Version: "1.0", 227 Service: NewPrivateLightAPI(&s.lesCommons, s.protocolManager.reg), 228 Public: false, 229 }, 230 }...) 231 } 232 233 func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { 234 s.blockchain.ResetWithGenesisBlock(gb) 235 } 236 237 func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } 238 func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } 239 func (s *LightEthereum) Engine() consensus.Engine { return s.engine } 240 func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } 241 func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 242 func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } 243 244 // Protocols implements node.Service, returning all the currently configured 245 // network protocols to start. 246 func (s *LightEthereum) Protocols() []p2p.Protocol { 247 return s.makeProtocols(ClientProtocolVersions) 248 } 249 250 // Start implements node.Service, starting all internal goroutines needed by the 251 // Ethereum protocol implementation. 252 func (s *LightEthereum) Start(srvr *p2p.Server) error { 253 log.Warn("Light client mode is an experimental feature") 254 s.startBloomHandlers(params.BloomBitsBlocksClient) 255 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId) 256 // clients are searching for the first advertised protocol in the list 257 protocolVersion := AdvertiseProtocolVersions[0] 258 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 259 s.protocolManager.Start(s.config.LightPeers) 260 return nil 261 } 262 263 // Stop implements node.Service, terminating all internal goroutines used by the 264 // Ethereum protocol. 265 func (s *LightEthereum) Stop() error { 266 s.odr.Stop() 267 s.relay.Stop() 268 s.bloomIndexer.Close() 269 s.chtIndexer.Close() 270 s.blockchain.Stop() 271 s.protocolManager.Stop() 272 s.txPool.Stop() 273 s.engine.Close() 274 275 s.eventMux.Stop() 276 277 time.Sleep(time.Millisecond * 200) 278 s.chainDb.Close() 279 close(s.shutdownChan) 280 281 return nil 282 } 283 284 // SetClient sets the rpc client and binds the registrar contract. 285 func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) { 286 // Short circuit if registrar is nil 287 if s.protocolManager.reg == nil { 288 return 289 } 290 s.protocolManager.reg.start(backend) 291 }