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