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