github.com/MaynardMiner/ethereumprogpow@v1.8.23/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 implements the Light Ethereum Subprotocol. 18 package les 19 20 import ( 21 "crypto/ecdsa" 22 "encoding/binary" 23 "math" 24 "sync" 25 26 "github.com/ethereumprogpow/ethereumprogpow/common" 27 "github.com/ethereumprogpow/ethereumprogpow/core" 28 "github.com/ethereumprogpow/ethereumprogpow/core/rawdb" 29 "github.com/ethereumprogpow/ethereumprogpow/core/types" 30 "github.com/ethereumprogpow/ethereumprogpow/eth" 31 "github.com/ethereumprogpow/ethereumprogpow/ethdb" 32 "github.com/ethereumprogpow/ethereumprogpow/les/flowcontrol" 33 "github.com/ethereumprogpow/ethereumprogpow/light" 34 "github.com/ethereumprogpow/ethereumprogpow/log" 35 "github.com/ethereumprogpow/ethereumprogpow/p2p" 36 "github.com/ethereumprogpow/ethereumprogpow/p2p/discv5" 37 "github.com/ethereumprogpow/ethereumprogpow/params" 38 "github.com/ethereumprogpow/ethereumprogpow/rlp" 39 ) 40 41 type LesServer struct { 42 lesCommons 43 44 fcManager *flowcontrol.ClientManager // nil if our node is client only 45 fcCostStats *requestCostStats 46 defParams *flowcontrol.ServerParams 47 lesTopics []discv5.Topic 48 privateKey *ecdsa.PrivateKey 49 quitSync chan struct{} 50 } 51 52 func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { 53 quitSync := make(chan struct{}) 54 pm, err := NewProtocolManager(eth.BlockChain().Config(), light.DefaultServerIndexerConfig, false, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup)) 55 if err != nil { 56 return nil, err 57 } 58 59 lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions)) 60 for i, pv := range AdvertiseProtocolVersions { 61 lesTopics[i] = lesTopic(eth.BlockChain().Genesis().Hash(), pv) 62 } 63 64 srv := &LesServer{ 65 lesCommons: lesCommons{ 66 config: config, 67 chainDb: eth.ChainDb(), 68 iConfig: light.DefaultServerIndexerConfig, 69 chtIndexer: light.NewChtIndexer(eth.ChainDb(), nil, params.CHTFrequencyServer, params.HelperTrieProcessConfirmations), 70 bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency), 71 protocolManager: pm, 72 }, 73 quitSync: quitSync, 74 lesTopics: lesTopics, 75 } 76 77 logger := log.New() 78 79 chtV1SectionCount, _, _ := srv.chtIndexer.Sections() // indexer still uses LES/1 4k section size for backwards server compatibility 80 chtV2SectionCount := chtV1SectionCount / (params.CHTFrequencyClient / params.CHTFrequencyServer) 81 if chtV2SectionCount != 0 { 82 // convert to LES/2 section 83 chtLastSection := chtV2SectionCount - 1 84 // convert last LES/2 section index back to LES/1 index for chtIndexer.SectionHead 85 chtLastSectionV1 := (chtLastSection+1)*(params.CHTFrequencyClient/params.CHTFrequencyServer) - 1 86 chtSectionHead := srv.chtIndexer.SectionHead(chtLastSectionV1) 87 chtRoot := light.GetChtRoot(pm.chainDb, chtLastSectionV1, chtSectionHead) 88 logger.Info("Loaded CHT", "section", chtLastSection, "head", chtSectionHead, "root", chtRoot) 89 } 90 bloomTrieSectionCount, _, _ := srv.bloomTrieIndexer.Sections() 91 if bloomTrieSectionCount != 0 { 92 bloomTrieLastSection := bloomTrieSectionCount - 1 93 bloomTrieSectionHead := srv.bloomTrieIndexer.SectionHead(bloomTrieLastSection) 94 bloomTrieRoot := light.GetBloomTrieRoot(pm.chainDb, bloomTrieLastSection, bloomTrieSectionHead) 95 logger.Info("Loaded bloom trie", "section", bloomTrieLastSection, "head", bloomTrieSectionHead, "root", bloomTrieRoot) 96 } 97 98 srv.chtIndexer.Start(eth.BlockChain()) 99 pm.server = srv 100 101 srv.defParams = &flowcontrol.ServerParams{ 102 BufLimit: 300000000, 103 MinRecharge: 50000, 104 } 105 srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000) 106 srv.fcCostStats = newCostStats(eth.ChainDb()) 107 return srv, nil 108 } 109 110 func (s *LesServer) Protocols() []p2p.Protocol { 111 return s.makeProtocols(ServerProtocolVersions) 112 } 113 114 // Start starts the LES server 115 func (s *LesServer) Start(srvr *p2p.Server) { 116 s.protocolManager.Start(s.config.LightPeers) 117 if srvr.DiscV5 != nil { 118 for _, topic := range s.lesTopics { 119 topic := topic 120 go func() { 121 logger := log.New("topic", topic) 122 logger.Info("Starting topic registration") 123 defer logger.Info("Terminated topic registration") 124 125 srvr.DiscV5.RegisterTopic(topic, s.quitSync) 126 }() 127 } 128 } 129 s.privateKey = srvr.PrivateKey 130 s.protocolManager.blockLoop() 131 } 132 133 func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { 134 bloomIndexer.AddChildIndexer(s.bloomTrieIndexer) 135 } 136 137 // Stop stops the LES service 138 func (s *LesServer) Stop() { 139 s.chtIndexer.Close() 140 // bloom trie indexer is closed by parent bloombits indexer 141 s.fcCostStats.store() 142 s.fcManager.Stop() 143 go func() { 144 <-s.protocolManager.noMorePeers 145 }() 146 s.protocolManager.Stop() 147 } 148 149 type requestCosts struct { 150 baseCost, reqCost uint64 151 } 152 153 type requestCostTable map[uint64]*requestCosts 154 155 type RequestCostList []struct { 156 MsgCode, BaseCost, ReqCost uint64 157 } 158 159 func (list RequestCostList) decode() requestCostTable { 160 table := make(requestCostTable) 161 for _, e := range list { 162 table[e.MsgCode] = &requestCosts{ 163 baseCost: e.BaseCost, 164 reqCost: e.ReqCost, 165 } 166 } 167 return table 168 } 169 170 type linReg struct { 171 sumX, sumY, sumXX, sumXY float64 172 cnt uint64 173 } 174 175 const linRegMaxCnt = 100000 176 177 func (l *linReg) add(x, y float64) { 178 if l.cnt >= linRegMaxCnt { 179 sub := float64(l.cnt+1-linRegMaxCnt) / linRegMaxCnt 180 l.sumX -= l.sumX * sub 181 l.sumY -= l.sumY * sub 182 l.sumXX -= l.sumXX * sub 183 l.sumXY -= l.sumXY * sub 184 l.cnt = linRegMaxCnt - 1 185 } 186 l.cnt++ 187 l.sumX += x 188 l.sumY += y 189 l.sumXX += x * x 190 l.sumXY += x * y 191 } 192 193 func (l *linReg) calc() (b, m float64) { 194 if l.cnt == 0 { 195 return 0, 0 196 } 197 cnt := float64(l.cnt) 198 d := cnt*l.sumXX - l.sumX*l.sumX 199 if d < 0.001 { 200 return l.sumY / cnt, 0 201 } 202 m = (cnt*l.sumXY - l.sumX*l.sumY) / d 203 b = (l.sumY / cnt) - (m * l.sumX / cnt) 204 return b, m 205 } 206 207 func (l *linReg) toBytes() []byte { 208 var arr [40]byte 209 binary.BigEndian.PutUint64(arr[0:8], math.Float64bits(l.sumX)) 210 binary.BigEndian.PutUint64(arr[8:16], math.Float64bits(l.sumY)) 211 binary.BigEndian.PutUint64(arr[16:24], math.Float64bits(l.sumXX)) 212 binary.BigEndian.PutUint64(arr[24:32], math.Float64bits(l.sumXY)) 213 binary.BigEndian.PutUint64(arr[32:40], l.cnt) 214 return arr[:] 215 } 216 217 func linRegFromBytes(data []byte) *linReg { 218 if len(data) != 40 { 219 return nil 220 } 221 l := &linReg{} 222 l.sumX = math.Float64frombits(binary.BigEndian.Uint64(data[0:8])) 223 l.sumY = math.Float64frombits(binary.BigEndian.Uint64(data[8:16])) 224 l.sumXX = math.Float64frombits(binary.BigEndian.Uint64(data[16:24])) 225 l.sumXY = math.Float64frombits(binary.BigEndian.Uint64(data[24:32])) 226 l.cnt = binary.BigEndian.Uint64(data[32:40]) 227 return l 228 } 229 230 type requestCostStats struct { 231 lock sync.RWMutex 232 db ethdb.Database 233 stats map[uint64]*linReg 234 } 235 236 type requestCostStatsRlp []struct { 237 MsgCode uint64 238 Data []byte 239 } 240 241 var rcStatsKey = []byte("_requestCostStats") 242 243 func newCostStats(db ethdb.Database) *requestCostStats { 244 stats := make(map[uint64]*linReg) 245 for _, code := range reqList { 246 stats[code] = &linReg{cnt: 100} 247 } 248 249 if db != nil { 250 data, err := db.Get(rcStatsKey) 251 var statsRlp requestCostStatsRlp 252 if err == nil { 253 err = rlp.DecodeBytes(data, &statsRlp) 254 } 255 if err == nil { 256 for _, r := range statsRlp { 257 if stats[r.MsgCode] != nil { 258 if l := linRegFromBytes(r.Data); l != nil { 259 stats[r.MsgCode] = l 260 } 261 } 262 } 263 } 264 } 265 266 return &requestCostStats{ 267 db: db, 268 stats: stats, 269 } 270 } 271 272 func (s *requestCostStats) store() { 273 s.lock.Lock() 274 defer s.lock.Unlock() 275 276 statsRlp := make(requestCostStatsRlp, len(reqList)) 277 for i, code := range reqList { 278 statsRlp[i].MsgCode = code 279 statsRlp[i].Data = s.stats[code].toBytes() 280 } 281 282 if data, err := rlp.EncodeToBytes(statsRlp); err == nil { 283 s.db.Put(rcStatsKey, data) 284 } 285 } 286 287 func (s *requestCostStats) getCurrentList() RequestCostList { 288 s.lock.Lock() 289 defer s.lock.Unlock() 290 291 list := make(RequestCostList, len(reqList)) 292 //fmt.Println("RequestCostList") 293 for idx, code := range reqList { 294 b, m := s.stats[code].calc() 295 //fmt.Println(code, s.stats[code].cnt, b/1000000, m/1000000) 296 if m < 0 { 297 b += m 298 m = 0 299 } 300 if b < 0 { 301 b = 0 302 } 303 304 list[idx].MsgCode = code 305 list[idx].BaseCost = uint64(b * 2) 306 list[idx].ReqCost = uint64(m * 2) 307 } 308 return list 309 } 310 311 func (s *requestCostStats) update(msgCode, reqCnt, cost uint64) { 312 s.lock.Lock() 313 defer s.lock.Unlock() 314 315 c, ok := s.stats[msgCode] 316 if !ok || reqCnt == 0 { 317 return 318 } 319 c.add(float64(reqCnt), float64(cost)) 320 } 321 322 func (pm *ProtocolManager) blockLoop() { 323 pm.wg.Add(1) 324 headCh := make(chan core.ChainHeadEvent, 10) 325 headSub := pm.blockchain.SubscribeChainHeadEvent(headCh) 326 go func() { 327 var lastHead *types.Header 328 lastBroadcastTd := common.Big0 329 for { 330 select { 331 case ev := <-headCh: 332 peers := pm.peers.AllPeers() 333 if len(peers) > 0 { 334 header := ev.Block.Header() 335 hash := header.Hash() 336 number := header.Number.Uint64() 337 td := rawdb.ReadTd(pm.chainDb, hash, number) 338 if td != nil && td.Cmp(lastBroadcastTd) > 0 { 339 var reorg uint64 340 if lastHead != nil { 341 reorg = lastHead.Number.Uint64() - rawdb.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64() 342 } 343 lastHead = header 344 lastBroadcastTd = td 345 346 log.Debug("Announcing block to peers", "number", number, "hash", hash, "td", td, "reorg", reorg) 347 348 announce := announceData{Hash: hash, Number: number, Td: td, ReorgDepth: reorg} 349 var ( 350 signed bool 351 signedAnnounce announceData 352 ) 353 354 for _, p := range peers { 355 switch p.announceType { 356 357 case announceTypeSimple: 358 select { 359 case p.announceChn <- announce: 360 default: 361 pm.removePeer(p.id) 362 } 363 364 case announceTypeSigned: 365 if !signed { 366 signedAnnounce = announce 367 signedAnnounce.sign(pm.server.privateKey) 368 signed = true 369 } 370 371 select { 372 case p.announceChn <- signedAnnounce: 373 default: 374 pm.removePeer(p.id) 375 } 376 } 377 } 378 } 379 } 380 case <-pm.quitSync: 381 headSub.Unsubscribe() 382 pm.wg.Done() 383 return 384 } 385 } 386 }() 387 }