github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/les/server.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 18 19 import ( 20 "crypto/ecdsa" 21 "sync" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/common/mclock" 25 "github.com/ethereum/go-ethereum/core" 26 "github.com/ethereum/go-ethereum/core/rawdb" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/eth" 29 "github.com/ethereum/go-ethereum/les/flowcontrol" 30 "github.com/ethereum/go-ethereum/light" 31 "github.com/ethereum/go-ethereum/log" 32 "github.com/ethereum/go-ethereum/p2p" 33 "github.com/ethereum/go-ethereum/p2p/discv5" 34 "github.com/ethereum/go-ethereum/params" 35 "github.com/ethereum/go-ethereum/rpc" 36 ) 37 38 const bufLimitRatio = 6000 // fixed bufLimit/MRR ratio 39 40 type LesServer struct { 41 lesCommons 42 43 fcManager *flowcontrol.ClientManager // nil if our node is client only 44 costTracker *costTracker 45 defParams flowcontrol.ServerParams 46 lesTopics []discv5.Topic 47 privateKey *ecdsa.PrivateKey 48 quitSync chan struct{} 49 onlyAnnounce bool 50 51 thcNormal, thcBlockProcessing int // serving thread count for normal operation and block processing mode 52 53 maxPeers int 54 freeClientCap uint64 55 freeClientPool *freeClientPool 56 priorityClientPool *priorityClientPool 57 } 58 59 func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { 60 quitSync := make(chan struct{}) 61 pm, err := NewProtocolManager( 62 eth.BlockChain().Config(), 63 light.DefaultServerIndexerConfig, 64 false, 65 config.NetworkId, 66 eth.EventMux(), 67 eth.Engine(), 68 newPeerSet(), 69 eth.BlockChain(), 70 eth.TxPool(), 71 eth.ChainDb(), 72 nil, 73 nil, 74 nil, 75 quitSync, 76 new(sync.WaitGroup), 77 config.ULC) 78 if err != nil { 79 return nil, err 80 } 81 82 lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions)) 83 for i, pv := range AdvertiseProtocolVersions { 84 lesTopics[i] = lesTopic(eth.BlockChain().Genesis().Hash(), pv) 85 } 86 87 srv := &LesServer{ 88 lesCommons: lesCommons{ 89 config: config, 90 chainDb: eth.ChainDb(), 91 iConfig: light.DefaultServerIndexerConfig, 92 chtIndexer: light.NewChtIndexer(eth.ChainDb(), nil, params.CHTFrequency, params.HelperTrieProcessConfirmations), 93 bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency), 94 protocolManager: pm, 95 }, 96 costTracker: newCostTracker(eth.ChainDb(), config), 97 quitSync: quitSync, 98 lesTopics: lesTopics, 99 onlyAnnounce: config.OnlyAnnounce, 100 } 101 102 logger := log.New() 103 pm.server = srv 104 srv.thcNormal = config.LightServ * 4 / 100 105 if srv.thcNormal < 4 { 106 srv.thcNormal = 4 107 } 108 srv.thcBlockProcessing = config.LightServ/100 + 1 109 srv.fcManager = flowcontrol.NewClientManager(nil, &mclock.System{}) 110 111 chtSectionCount, _, _ := srv.chtIndexer.Sections() 112 if chtSectionCount != 0 { 113 chtLastSection := chtSectionCount - 1 114 chtSectionHead := srv.chtIndexer.SectionHead(chtLastSection) 115 chtRoot := light.GetChtRoot(pm.chainDb, chtLastSection, chtSectionHead) 116 logger.Info("Loaded CHT", "section", chtLastSection, "head", chtSectionHead, "root", chtRoot) 117 } 118 bloomTrieSectionCount, _, _ := srv.bloomTrieIndexer.Sections() 119 if bloomTrieSectionCount != 0 { 120 bloomTrieLastSection := bloomTrieSectionCount - 1 121 bloomTrieSectionHead := srv.bloomTrieIndexer.SectionHead(bloomTrieLastSection) 122 bloomTrieRoot := light.GetBloomTrieRoot(pm.chainDb, bloomTrieLastSection, bloomTrieSectionHead) 123 logger.Info("Loaded bloom trie", "section", bloomTrieLastSection, "head", bloomTrieSectionHead, "root", bloomTrieRoot) 124 } 125 126 srv.chtIndexer.Start(eth.BlockChain()) 127 return srv, nil 128 } 129 130 func (s *LesServer) APIs() []rpc.API { 131 return []rpc.API{ 132 { 133 Namespace: "les", 134 Version: "1.0", 135 Service: NewPrivateLightServerAPI(s), 136 Public: false, 137 }, 138 } 139 } 140 141 // startEventLoop starts an event handler loop that updates the recharge curve of 142 // the client manager and adjusts the client pool's size according to the total 143 // capacity updates coming from the client manager 144 func (s *LesServer) startEventLoop() { 145 s.protocolManager.wg.Add(1) 146 147 var processing bool 148 blockProcFeed := make(chan bool, 100) 149 s.protocolManager.blockchain.(*core.BlockChain).SubscribeBlockProcessingEvent(blockProcFeed) 150 totalRechargeCh := make(chan uint64, 100) 151 totalRecharge := s.costTracker.subscribeTotalRecharge(totalRechargeCh) 152 totalCapacityCh := make(chan uint64, 100) 153 updateRecharge := func() { 154 if processing { 155 s.protocolManager.servingQueue.setThreads(s.thcBlockProcessing) 156 s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge, totalRecharge}}) 157 } else { 158 s.protocolManager.servingQueue.setThreads(s.thcNormal) 159 s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge / 10, totalRecharge}, {totalRecharge, totalRecharge}}) 160 } 161 } 162 updateRecharge() 163 totalCapacity := s.fcManager.SubscribeTotalCapacity(totalCapacityCh) 164 s.priorityClientPool.setLimits(s.maxPeers, totalCapacity) 165 166 go func() { 167 for { 168 select { 169 case processing = <-blockProcFeed: 170 updateRecharge() 171 case totalRecharge = <-totalRechargeCh: 172 updateRecharge() 173 case totalCapacity = <-totalCapacityCh: 174 s.priorityClientPool.setLimits(s.maxPeers, totalCapacity) 175 case <-s.protocolManager.quitSync: 176 s.protocolManager.wg.Done() 177 return 178 } 179 } 180 }() 181 } 182 183 func (s *LesServer) Protocols() []p2p.Protocol { 184 return s.makeProtocols(ServerProtocolVersions) 185 } 186 187 // Start starts the LES server 188 func (s *LesServer) Start(srvr *p2p.Server) { 189 s.maxPeers = s.config.LightPeers 190 totalRecharge := s.costTracker.totalRecharge() 191 if s.maxPeers > 0 { 192 s.freeClientCap = minCapacity //totalRecharge / uint64(s.maxPeers) 193 if s.freeClientCap < minCapacity { 194 s.freeClientCap = minCapacity 195 } 196 if s.freeClientCap > 0 { 197 s.defParams = flowcontrol.ServerParams{ 198 BufLimit: s.freeClientCap * bufLimitRatio, 199 MinRecharge: s.freeClientCap, 200 } 201 } 202 } 203 freePeers := int(totalRecharge / s.freeClientCap) 204 if freePeers < s.maxPeers { 205 log.Warn("Light peer count limited", "specified", s.maxPeers, "allowed", freePeers) 206 } 207 208 s.freeClientPool = newFreeClientPool(s.chainDb, s.freeClientCap, 10000, mclock.System{}, func(id string) { go s.protocolManager.removePeer(id) }) 209 s.priorityClientPool = newPriorityClientPool(s.freeClientCap, s.protocolManager.peers, s.freeClientPool) 210 211 s.protocolManager.peers.notify(s.priorityClientPool) 212 s.startEventLoop() 213 s.protocolManager.Start(s.config.LightPeers) 214 if srvr.DiscV5 != nil { 215 for _, topic := range s.lesTopics { 216 topic := topic 217 go func() { 218 logger := log.New("topic", topic) 219 logger.Info("Starting topic registration") 220 defer logger.Info("Terminated topic registration") 221 222 srvr.DiscV5.RegisterTopic(topic, s.quitSync) 223 }() 224 } 225 } 226 s.privateKey = srvr.PrivateKey 227 s.protocolManager.blockLoop() 228 } 229 230 func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { 231 bloomIndexer.AddChildIndexer(s.bloomTrieIndexer) 232 } 233 234 // Stop stops the LES service 235 func (s *LesServer) Stop() { 236 s.chtIndexer.Close() 237 // bloom trie indexer is closed by parent bloombits indexer 238 go func() { 239 <-s.protocolManager.noMorePeers 240 }() 241 s.freeClientPool.stop() 242 s.costTracker.stop() 243 s.protocolManager.Stop() 244 } 245 246 func (pm *ProtocolManager) blockLoop() { 247 pm.wg.Add(1) 248 headCh := make(chan core.ChainHeadEvent, 10) 249 headSub := pm.blockchain.SubscribeChainHeadEvent(headCh) 250 go func() { 251 var lastHead *types.Header 252 lastBroadcastTd := common.Big0 253 for { 254 select { 255 case ev := <-headCh: 256 peers := pm.peers.AllPeers() 257 if len(peers) > 0 { 258 header := ev.Block.Header() 259 hash := header.Hash() 260 number := header.Number.Uint64() 261 td := rawdb.ReadTd(pm.chainDb, hash, number) 262 if td != nil && td.Cmp(lastBroadcastTd) > 0 { 263 var reorg uint64 264 if lastHead != nil { 265 reorg = lastHead.Number.Uint64() - rawdb.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64() 266 } 267 lastHead = header 268 lastBroadcastTd = td 269 270 log.Debug("Announcing block to peers", "number", number, "hash", hash, "td", td, "reorg", reorg) 271 272 announce := announceData{Hash: hash, Number: number, Td: td, ReorgDepth: reorg} 273 var ( 274 signed bool 275 signedAnnounce announceData 276 ) 277 278 for _, p := range peers { 279 p := p 280 switch p.announceType { 281 case announceTypeSimple: 282 p.queueSend(func() { p.SendAnnounce(announce) }) 283 case announceTypeSigned: 284 if !signed { 285 signedAnnounce = announce 286 signedAnnounce.sign(pm.server.privateKey) 287 signed = true 288 } 289 p.queueSend(func() { p.SendAnnounce(signedAnnounce) }) 290 } 291 } 292 } 293 } 294 case <-pm.quitSync: 295 headSub.Unsubscribe() 296 pm.wg.Done() 297 return 298 } 299 } 300 }() 301 }