github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/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 "encoding/binary" 22 "math" 23 "sync" 24 "time" 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/rlp" 36 "github.com/ethereum/go-ethereum/trie" 37 ) 38 39 type LesServer struct { 40 protocolManager *ProtocolManager 41 fcManager *flowcontrol.ClientManager // nil if our node is client only 42 fcCostStats *requestCostStats 43 defParams *flowcontrol.ServerParams 44 stopped bool 45 } 46 47 func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { 48 pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Engine(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil) 49 if err != nil { 50 return nil, err 51 } 52 pm.blockLoop() 53 54 srv := &LesServer{protocolManager: pm} 55 pm.server = srv 56 57 srv.defParams = &flowcontrol.ServerParams{ 58 BufLimit: 300000000, 59 MinRecharge: 50000, 60 } 61 srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000) 62 srv.fcCostStats = newCostStats(eth.ChainDb()) 63 return srv, nil 64 } 65 66 func (s *LesServer) Protocols() []p2p.Protocol { 67 return s.protocolManager.SubProtocols 68 } 69 70 // Start starts the LES server 71 func (s *LesServer) Start(srvr *p2p.Server) { 72 s.protocolManager.Start(srvr) 73 } 74 75 // Stop stops the LES service 76 func (s *LesServer) Stop() { 77 s.fcCostStats.store() 78 s.fcManager.Stop() 79 go func() { 80 <-s.protocolManager.noMorePeers 81 }() 82 s.protocolManager.Stop() 83 } 84 85 type requestCosts struct { 86 baseCost, reqCost uint64 87 } 88 89 type requestCostTable map[uint64]*requestCosts 90 91 type RequestCostList []struct { 92 MsgCode, BaseCost, ReqCost uint64 93 } 94 95 func (list RequestCostList) decode() requestCostTable { 96 table := make(requestCostTable) 97 for _, e := range list { 98 table[e.MsgCode] = &requestCosts{ 99 baseCost: e.BaseCost, 100 reqCost: e.ReqCost, 101 } 102 } 103 return table 104 } 105 106 func (table requestCostTable) encode() RequestCostList { 107 list := make(RequestCostList, len(table)) 108 for idx, code := range reqList { 109 list[idx].MsgCode = code 110 list[idx].BaseCost = table[code].baseCost 111 list[idx].ReqCost = table[code].reqCost 112 } 113 return list 114 } 115 116 type linReg struct { 117 sumX, sumY, sumXX, sumXY float64 118 cnt uint64 119 } 120 121 const linRegMaxCnt = 100000 122 123 func (l *linReg) add(x, y float64) { 124 if l.cnt >= linRegMaxCnt { 125 sub := float64(l.cnt+1-linRegMaxCnt) / linRegMaxCnt 126 l.sumX -= l.sumX * sub 127 l.sumY -= l.sumY * sub 128 l.sumXX -= l.sumXX * sub 129 l.sumXY -= l.sumXY * sub 130 l.cnt = linRegMaxCnt - 1 131 } 132 l.cnt++ 133 l.sumX += x 134 l.sumY += y 135 l.sumXX += x * x 136 l.sumXY += x * y 137 } 138 139 func (l *linReg) calc() (b, m float64) { 140 if l.cnt == 0 { 141 return 0, 0 142 } 143 cnt := float64(l.cnt) 144 d := cnt*l.sumXX - l.sumX*l.sumX 145 if d < 0.001 { 146 return l.sumY / cnt, 0 147 } 148 m = (cnt*l.sumXY - l.sumX*l.sumY) / d 149 b = (l.sumY / cnt) - (m * l.sumX / cnt) 150 return b, m 151 } 152 153 func (l *linReg) toBytes() []byte { 154 var arr [40]byte 155 binary.BigEndian.PutUint64(arr[0:8], math.Float64bits(l.sumX)) 156 binary.BigEndian.PutUint64(arr[8:16], math.Float64bits(l.sumY)) 157 binary.BigEndian.PutUint64(arr[16:24], math.Float64bits(l.sumXX)) 158 binary.BigEndian.PutUint64(arr[24:32], math.Float64bits(l.sumXY)) 159 binary.BigEndian.PutUint64(arr[32:40], l.cnt) 160 return arr[:] 161 } 162 163 func linRegFromBytes(data []byte) *linReg { 164 if len(data) != 40 { 165 return nil 166 } 167 l := &linReg{} 168 l.sumX = math.Float64frombits(binary.BigEndian.Uint64(data[0:8])) 169 l.sumY = math.Float64frombits(binary.BigEndian.Uint64(data[8:16])) 170 l.sumXX = math.Float64frombits(binary.BigEndian.Uint64(data[16:24])) 171 l.sumXY = math.Float64frombits(binary.BigEndian.Uint64(data[24:32])) 172 l.cnt = binary.BigEndian.Uint64(data[32:40]) 173 return l 174 } 175 176 type requestCostStats struct { 177 lock sync.RWMutex 178 db ethdb.Database 179 stats map[uint64]*linReg 180 } 181 182 type requestCostStatsRlp []struct { 183 MsgCode uint64 184 Data []byte 185 } 186 187 var rcStatsKey = []byte("_requestCostStats") 188 189 func newCostStats(db ethdb.Database) *requestCostStats { 190 stats := make(map[uint64]*linReg) 191 for _, code := range reqList { 192 stats[code] = &linReg{cnt: 100} 193 } 194 195 if db != nil { 196 data, err := db.Get(rcStatsKey) 197 var statsRlp requestCostStatsRlp 198 if err == nil { 199 err = rlp.DecodeBytes(data, &statsRlp) 200 } 201 if err == nil { 202 for _, r := range statsRlp { 203 if stats[r.MsgCode] != nil { 204 if l := linRegFromBytes(r.Data); l != nil { 205 stats[r.MsgCode] = l 206 } 207 } 208 } 209 } 210 } 211 212 return &requestCostStats{ 213 db: db, 214 stats: stats, 215 } 216 } 217 218 func (s *requestCostStats) store() { 219 s.lock.Lock() 220 defer s.lock.Unlock() 221 222 statsRlp := make(requestCostStatsRlp, len(reqList)) 223 for i, code := range reqList { 224 statsRlp[i].MsgCode = code 225 statsRlp[i].Data = s.stats[code].toBytes() 226 } 227 228 if data, err := rlp.EncodeToBytes(statsRlp); err == nil { 229 s.db.Put(rcStatsKey, data) 230 } 231 } 232 233 func (s *requestCostStats) getCurrentList() RequestCostList { 234 s.lock.Lock() 235 defer s.lock.Unlock() 236 237 list := make(RequestCostList, len(reqList)) 238 //fmt.Println("RequestCostList") 239 for idx, code := range reqList { 240 b, m := s.stats[code].calc() 241 //fmt.Println(code, s.stats[code].cnt, b/1000000, m/1000000) 242 if m < 0 { 243 b += m 244 m = 0 245 } 246 if b < 0 { 247 b = 0 248 } 249 250 list[idx].MsgCode = code 251 list[idx].BaseCost = uint64(b * 2) 252 list[idx].ReqCost = uint64(m * 2) 253 } 254 return list 255 } 256 257 func (s *requestCostStats) update(msgCode, reqCnt, cost uint64) { 258 s.lock.Lock() 259 defer s.lock.Unlock() 260 261 c, ok := s.stats[msgCode] 262 if !ok || reqCnt == 0 { 263 return 264 } 265 c.add(float64(reqCnt), float64(cost)) 266 } 267 268 func (pm *ProtocolManager) blockLoop() { 269 pm.wg.Add(1) 270 sub := pm.eventMux.Subscribe(core.ChainHeadEvent{}) 271 newCht := make(chan struct{}, 10) 272 newCht <- struct{}{} 273 go func() { 274 var mu sync.Mutex 275 var lastHead *types.Header 276 lastBroadcastTd := common.Big0 277 for { 278 select { 279 case ev := <-sub.Chan(): 280 peers := pm.peers.AllPeers() 281 if len(peers) > 0 { 282 header := ev.Data.(core.ChainHeadEvent).Block.Header() 283 hash := header.Hash() 284 number := header.Number.Uint64() 285 td := core.GetTd(pm.chainDb, hash, number) 286 if td != nil && td.Cmp(lastBroadcastTd) > 0 { 287 var reorg uint64 288 if lastHead != nil { 289 reorg = lastHead.Number.Uint64() - core.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64() 290 } 291 lastHead = header 292 lastBroadcastTd = td 293 294 log.Debug("Announcing block to peers", "number", number, "hash", hash, "td", td, "reorg", reorg) 295 296 announce := announceData{Hash: hash, Number: number, Td: td, ReorgDepth: reorg} 297 for _, p := range peers { 298 select { 299 case p.announceChn <- announce: 300 default: 301 pm.removePeer(p.id) 302 } 303 } 304 } 305 } 306 newCht <- struct{}{} 307 case <-newCht: 308 go func() { 309 mu.Lock() 310 more := makeCht(pm.chainDb) 311 mu.Unlock() 312 if more { 313 time.Sleep(time.Millisecond * 10) 314 newCht <- struct{}{} 315 } 316 }() 317 case <-pm.quitSync: 318 sub.Unsubscribe() 319 pm.wg.Done() 320 return 321 } 322 } 323 }() 324 } 325 326 var ( 327 lastChtKey = []byte("LastChtNumber") // chtNum (uint64 big endian) 328 chtPrefix = []byte("cht") // chtPrefix + chtNum (uint64 big endian) -> trie root hash 329 ) 330 331 func getChtRoot(db ethdb.Database, num uint64) common.Hash { 332 var encNumber [8]byte 333 binary.BigEndian.PutUint64(encNumber[:], num) 334 data, _ := db.Get(append(chtPrefix, encNumber[:]...)) 335 return common.BytesToHash(data) 336 } 337 338 func storeChtRoot(db ethdb.Database, num uint64, root common.Hash) { 339 var encNumber [8]byte 340 binary.BigEndian.PutUint64(encNumber[:], num) 341 db.Put(append(chtPrefix, encNumber[:]...), root[:]) 342 } 343 344 func makeCht(db ethdb.Database) bool { 345 headHash := core.GetHeadBlockHash(db) 346 headNum := core.GetBlockNumber(db, headHash) 347 348 var newChtNum uint64 349 if headNum > light.ChtConfirmations { 350 newChtNum = (headNum - light.ChtConfirmations) / light.ChtFrequency 351 } 352 353 var lastChtNum uint64 354 data, _ := db.Get(lastChtKey) 355 if len(data) == 8 { 356 lastChtNum = binary.BigEndian.Uint64(data[:]) 357 } 358 if newChtNum <= lastChtNum { 359 return false 360 } 361 362 var t *trie.Trie 363 if lastChtNum > 0 { 364 var err error 365 t, err = trie.New(getChtRoot(db, lastChtNum), db) 366 if err != nil { 367 lastChtNum = 0 368 } 369 } 370 if lastChtNum == 0 { 371 t, _ = trie.New(common.Hash{}, db) 372 } 373 374 for num := lastChtNum * light.ChtFrequency; num < (lastChtNum+1)*light.ChtFrequency; num++ { 375 hash := core.GetCanonicalHash(db, num) 376 if hash == (common.Hash{}) { 377 panic("Canonical hash not found") 378 } 379 td := core.GetTd(db, hash, num) 380 if td == nil { 381 panic("TD not found") 382 } 383 var encNumber [8]byte 384 binary.BigEndian.PutUint64(encNumber[:], num) 385 var node light.ChtNode 386 node.Hash = hash 387 node.Td = td 388 data, _ := rlp.EncodeToBytes(node) 389 t.Update(encNumber[:], data) 390 } 391 392 root, err := t.Commit() 393 if err != nil { 394 lastChtNum = 0 395 } else { 396 lastChtNum++ 397 398 log.Trace("Generated CHT", "number", lastChtNum, "root", root.Hex()) 399 400 storeChtRoot(db, lastChtNum, root) 401 var data [8]byte 402 binary.BigEndian.PutUint64(data[:], lastChtNum) 403 db.Put(lastChtKey, data[:]) 404 } 405 406 return newChtNum > lastChtNum 407 }