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