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