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