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