github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/p2pserver/sync/main/block_sync.go (about) 1 package miansync 2 3 import ( 4 // "fmt" 5 "math" 6 "sort" 7 "sync" 8 "time" 9 10 "github.com/sixexorg/magnetic-ring/common" 11 "github.com/sixexorg/magnetic-ring/core/mainchain/types" 12 ledger "github.com/sixexorg/magnetic-ring/store/mainchain/storages" 13 "github.com/sixexorg/magnetic-ring/store/mainchain/validation" 14 15 "fmt" 16 "reflect" 17 18 "github.com/sixexorg/magnetic-ring/log" 19 p2pComm "github.com/sixexorg/magnetic-ring/p2pserver/common" 20 msgpack "github.com/sixexorg/magnetic-ring/p2pserver/message" 21 "github.com/sixexorg/magnetic-ring/p2pserver/peer" 22 "github.com/sixexorg/magnetic-ring/p2pserver/sync/p2pserprotocol" 23 "github.com/sixexorg/magnetic-ring/radar/mainchain" 24 ) 25 26 const ( 27 SYNC_MAX_HEADER_FORWARD_SIZE = 500 //keep CurrentHeaderHeight - CurrentBlockHeight <= SYNC_MAX_HEADER_FORWARD_SIZE 28 SYNC_MAX_FLIGHT_HEADER_SIZE = 1 //Number of headers on flight 29 SYNC_MAX_FLIGHT_BLOCK_SIZE = 50 //Number of blocks on flight 30 SYNC_MAX_BLOCK_CACHE_SIZE = 500 //Cache size of block wait to commit to ledger 31 SYNC_HEADER_REQUEST_TIMEOUT = 2 //s, Request header timeout time. If header haven't receive after SYNC_HEADER_REQUEST_TIMEOUT second, retry 32 SYNC_BLOCK_REQUEST_TIMEOUT = 2 //s, Request block timeout time. If block haven't received after SYNC_BLOCK_REQUEST_TIMEOUT second, retry 33 SYNC_NEXT_BLOCK_TIMES = 3 //Request times of next height block 34 SYNC_NEXT_BLOCKS_HEIGHT = 2 //for current block height plus next 35 SYNC_NODE_RECORD_SPEED_CNT = 3 //Record speed count for accuracy 36 SYNC_NODE_RECORD_TIME_CNT = 3 //Record request time for accuracy 37 SYNC_NODE_SPEED_INIT = 100 * 1024 //Init a big speed (100MB/s) for every node in first round 38 SYNC_MAX_ERROR_RESP_TIMES = 5 //Max error headers/blocks response times, if reaches, delete it 39 SYNC_MAX_HEIGHT_OFFSET = 5 //Offset of the max height and current height 40 ) 41 42 //NodeWeight record some params of node, using for sort 43 type NodeWeight struct { 44 id uint64 //NodeID 45 speed []float32 //Record node request-response speed, using for calc the avg speed, unit kB/s 46 timeoutCnt int //Node response timeout count 47 errorRespCnt int //Node response error data count 48 reqTime []int64 //Record request time, using for calc the avg req time interval, unit millisecond 49 } 50 51 //NewNodeWeight new a nodeweight 52 func NewNodeWeight(id uint64) *NodeWeight { 53 s := make([]float32, 0, SYNC_NODE_RECORD_SPEED_CNT) 54 for i := 0; i < SYNC_NODE_RECORD_SPEED_CNT; i++ { 55 s = append(s, float32(SYNC_NODE_SPEED_INIT)) 56 } 57 r := make([]int64, 0, SYNC_NODE_RECORD_TIME_CNT) 58 now := time.Now().UnixNano() / int64(time.Millisecond) 59 for i := 0; i < SYNC_NODE_RECORD_TIME_CNT; i++ { 60 r = append(r, now) 61 } 62 return &NodeWeight{ 63 id: id, 64 speed: s, 65 timeoutCnt: 0, 66 errorRespCnt: 0, 67 reqTime: r, 68 } 69 } 70 71 //AddTimeoutCnt incre timeout count 72 func (that *NodeWeight) AddTimeoutCnt() { 73 that.timeoutCnt++ 74 } 75 76 //AddErrorRespCnt incre receive error header/block count 77 func (that *NodeWeight) AddErrorRespCnt() { 78 that.errorRespCnt++ 79 } 80 81 //GetErrorRespCnt get the error response count 82 func (that *NodeWeight) GetErrorRespCnt() int { 83 return that.errorRespCnt 84 } 85 86 //AppendNewReqTime append new request time 87 func (that *NodeWeight) AppendNewReqtime() { 88 copy(that.reqTime[0:SYNC_NODE_RECORD_TIME_CNT-1], that.reqTime[1:]) 89 that.reqTime[SYNC_NODE_RECORD_TIME_CNT-1] = time.Now().UnixNano() / int64(time.Millisecond) 90 } 91 92 //addNewSpeed apend the new speed to tail, remove the oldest one 93 func (that *NodeWeight) AppendNewSpeed(s float32) { 94 copy(that.speed[0:SYNC_NODE_RECORD_SPEED_CNT-1], that.speed[1:]) 95 that.speed[SYNC_NODE_RECORD_SPEED_CNT-1] = s 96 } 97 98 //Weight calculate node's weight for sort. Highest weight node will be accessed first for next request. 99 func (that *NodeWeight) Weight() float32 { 100 avgSpeed := float32(0.0) 101 for _, s := range that.speed { 102 avgSpeed += s 103 } 104 avgSpeed = avgSpeed / float32(len(that.speed)) 105 106 avgInterval := float32(0.0) 107 now := time.Now().UnixNano() / int64(time.Millisecond) 108 for _, t := range that.reqTime { 109 avgInterval += float32(now - t) 110 } 111 avgInterval = avgInterval / float32(len(that.reqTime)) 112 w := avgSpeed + avgInterval 113 return w 114 } 115 116 //NodeWeights implement sorting 117 type NodeWeights []*NodeWeight 118 119 func (nws NodeWeights) Len() int { 120 return len(nws) 121 } 122 123 func (nws NodeWeights) Swap(i, j int) { 124 nws[i], nws[j] = nws[j], nws[i] 125 } 126 func (nws NodeWeights) Less(i, j int) bool { 127 ni := nws[i] 128 nj := nws[j] 129 return ni.Weight() < nj.Weight() && ni.errorRespCnt >= nj.errorRespCnt && ni.timeoutCnt >= nj.timeoutCnt 130 } 131 132 //SyncFlightInfo record the info of fight object(header or block) 133 type SyncFlightInfo struct { 134 Height uint64 //BlockHeight of HeaderHeight 135 nodeId uint64 //The current node to send msg 136 startTime time.Time //Request start time 137 failedNodes map[uint64]int //Map nodeId => timeout times 138 totalFailed int //Total timeout times 139 lock sync.RWMutex 140 } 141 142 //NewSyncFlightInfo return a new SyncFlightInfo instance 143 func NewSyncFlightInfo(height uint64, nodeId uint64) *SyncFlightInfo { 144 return &SyncFlightInfo{ 145 Height: height, 146 nodeId: nodeId, 147 startTime: time.Now(), 148 failedNodes: make(map[uint64]int, 0), 149 } 150 } 151 152 //GetNodeId return current node id for sending msg 153 func (that *SyncFlightInfo) GetNodeId() uint64 { 154 that.lock.RLock() 155 defer that.lock.RUnlock() 156 return that.nodeId 157 } 158 159 //SetNodeId set a new node id 160 func (that *SyncFlightInfo) SetNodeId(nodeId uint64) { 161 that.lock.Lock() 162 defer that.lock.Unlock() 163 that.nodeId = nodeId 164 } 165 166 //MarkFailedNode mark node failed, after request timeout 167 func (that *SyncFlightInfo) MarkFailedNode() { 168 that.lock.Lock() 169 defer that.lock.Unlock() 170 that.failedNodes[that.nodeId] += 1 171 that.totalFailed++ 172 } 173 174 //GetFailedTimes return failed times of a node 175 func (that *SyncFlightInfo) GetFailedTimes(nodeId uint64) int { 176 that.lock.RLock() 177 defer that.lock.RUnlock() 178 times, ok := that.failedNodes[nodeId] 179 if !ok { 180 return 0 181 } 182 return times 183 } 184 185 //GetTotalFailedTimes return the total failed times of request 186 func (that *SyncFlightInfo) GetTotalFailedTimes() int { 187 that.lock.RLock() 188 defer that.lock.RUnlock() 189 return that.totalFailed 190 } 191 192 //ResetStartTime 193 func (that *SyncFlightInfo) ResetStartTime() { 194 that.lock.Lock() 195 defer that.lock.Unlock() 196 that.startTime = time.Now() 197 } 198 199 //GetStartTime return the start time of request 200 func (that *SyncFlightInfo) GetStartTime() time.Time { 201 that.lock.RLock() 202 defer that.lock.RUnlock() 203 return that.startTime 204 } 205 206 //BlockInfo is used for saving block information in cache 207 type BlockInfo struct { 208 nodeID uint64 209 block *types.Block 210 } 211 212 //BlockSyncMgr is the manager class to deal with block sync 213 type BlockSyncMgr struct { 214 flightBlocks map[common.Hash][]*SyncFlightInfo //Map BlockHash => []SyncFlightInfo, using for manager all of those block flights 215 flightHeaders map[uint64]*SyncFlightInfo //Map HeaderHeight => SyncFlightInfo, using for manager all of those header flights 216 blocksCache map[uint64]*BlockInfo //Map BlockHash => BlockInfo, using for cache the blocks receive from net, and waiting for commit to ledger 217 server p2pserprotocol.SyncP2PSer //Pointer to the local node 218 syncBlockLock bool //Help to avoid send block sync request duplicate 219 syncHeaderLock bool //Help to avoid send header sync request duplicate 220 saveBlockLock bool //Help to avoid saving block concurrently 221 exitCh chan interface{} //ExitCh to receive exit signal 222 ledger *ledger.LedgerStoreImp //ledger 223 radar *mainchain.LeagueConsumers //ladar 224 lock sync.RWMutex //lock 225 nodeWeights map[uint64]*NodeWeight //Map NodeID => NodeStatus, using for getNextNode 226 syncStatus bool //lock or not sync header info 227 lockBlkHeight uint64 //should lock block height not save 228 } 229 230 //NewBlockSyncMgr return a BlockSyncMgr instance 231 func NewBlockSyncMgr(server p2pserprotocol.SyncP2PSer) *BlockSyncMgr { 232 return &BlockSyncMgr{ 233 flightBlocks: make(map[common.Hash][]*SyncFlightInfo, 0), 234 flightHeaders: make(map[uint64]*SyncFlightInfo, 0), 235 blocksCache: make(map[uint64]*BlockInfo, 0), 236 server: server, 237 ledger: server.GetLedger(), 238 radar: mainchain.GetLeagueConsumersInstance(), 239 exitCh: make(chan interface{}, 1), 240 nodeWeights: make(map[uint64]*NodeWeight, 0), 241 } 242 } 243 244 //Start to sync 245 func (that *BlockSyncMgr) Start() { 246 go that.sync() 247 go that.printHeight() 248 ticker := time.NewTicker(time.Second) 249 for { 250 select { 251 case <-that.exitCh: 252 return 253 case <-ticker.C: 254 go that.checkTimeout() 255 go that.sync() 256 go that.saveBlock() 257 } 258 } 259 } 260 261 func (that *BlockSyncMgr) printHeight() { 262 t := time.NewTicker(p2pComm.DEFAULT_GEN_BLOCK_TIME * time.Second) 263 defer t.Stop() 264 265 for { 266 select { 267 case <-t.C: 268 hh := that.ledger.GetCurrentHeaderHeight() 269 log.Info("main_sync", "CurrentBlockHeight", that.ledger.GetCurrentBlockHeight( /*that.orgID*/), "GetCurrentHeaderHeight", hh) 270 case <-that.exitCh: 271 return 272 } 273 } 274 } 275 276 func (that *BlockSyncMgr) checkTimeout() { 277 now := time.Now() 278 headerTimeoutFlights := make(map[uint64]*SyncFlightInfo, 0) 279 blockTimeoutFlights := make(map[common.Hash][]*SyncFlightInfo, 0) 280 that.lock.RLock() 281 for height, flightInfo := range that.flightHeaders { 282 if int(now.Sub(flightInfo.startTime).Seconds()) >= SYNC_HEADER_REQUEST_TIMEOUT { 283 headerTimeoutFlights[height] = flightInfo 284 } 285 } 286 for blockHash, flightInfos := range that.flightBlocks { 287 for _, flightInfo := range flightInfos { 288 if int(now.Sub(flightInfo.startTime).Seconds()) >= SYNC_BLOCK_REQUEST_TIMEOUT { 289 blockTimeoutFlights[blockHash] = append(blockTimeoutFlights[blockHash], flightInfo) 290 } 291 } 292 } 293 that.lock.RUnlock() 294 295 curHeaderHeight := that.ledger.GetCurrentHeaderHeight() 296 curBlockHeight := that.ledger.GetCurrentBlockHeight() 297 298 for height, flightInfo := range headerTimeoutFlights { 299 that.addTimeoutCnt(flightInfo.GetNodeId()) 300 if height <= curHeaderHeight { 301 that.delFlightHeader(height) 302 continue 303 } 304 flightInfo.ResetStartTime() 305 flightInfo.MarkFailedNode() 306 log.Trace("[p2p]checkTimeout main sync headers", "from id", flightInfo.GetNodeId(), "height", height, "after", SYNC_HEADER_REQUEST_TIMEOUT, "Times", flightInfo.GetTotalFailedTimes()) 307 reqNode := that.getNodeWithMinFailedTimes(flightInfo, curBlockHeight) 308 if reqNode == nil { 309 break 310 } 311 flightInfo.SetNodeId(reqNode.GetID()) 312 313 headerHash := that.ledger.GetCurrentHeaderHash() 314 var nuladd common.Address 315 msg := msgpack.NewHeadersReq(headerHash, nuladd, p2pComm.SYNC_DATA_MAIN, curHeaderHeight) 316 // msg := msgpack.NewHeadersReq(headerHash,nuladd,p2pComm.SYNC_DATA_MAIN) 317 err := that.server.Send(reqNode, msg, false) 318 if err != nil { 319 log.Warn("[p2p]checkTimeout failed to send a new headersReq", "err", err) 320 } else { 321 that.appendReqTime(reqNode.GetID()) 322 } 323 } 324 325 for blockHash, flightInfos := range blockTimeoutFlights { 326 for _, flightInfo := range flightInfos { 327 that.addTimeoutCnt(flightInfo.GetNodeId()) 328 if flightInfo.Height <= curBlockHeight { 329 that.delFlightBlock(blockHash) 330 continue 331 } 332 flightInfo.ResetStartTime() 333 flightInfo.MarkFailedNode() 334 log.Trace("[p2p]checkTimeout sync", "height", flightInfo.Height, "blockHash", blockHash, "after", SYNC_BLOCK_REQUEST_TIMEOUT, "times", flightInfo.GetTotalFailedTimes()) 335 reqNode := that.getNodeWithMinFailedTimes(flightInfo, curBlockHeight) 336 if reqNode == nil { 337 break 338 } 339 flightInfo.SetNodeId(reqNode.GetID()) 340 341 var nuladd common.Address 342 msg := msgpack.NewBlkDataReq(blockHash, nuladd, p2pComm.SYNC_DATA_MAIN) 343 err := that.server.Send(reqNode, msg, false) 344 if err != nil { 345 log.Warn("[p2p]checkTimeout reqNode", "ID", reqNode.GetID(), "err", err) 346 continue 347 } else { 348 that.appendReqTime(reqNode.GetID()) 349 } 350 } 351 } 352 } 353 354 func (that *BlockSyncMgr) sync() { 355 that.syncHeader() 356 that.syncBlock() 357 } 358 359 func (that *BlockSyncMgr) syncHeader() { 360 if !that.server.ReachMinConnection() { 361 return 362 } 363 if that.tryGetSyncHeaderLock() { 364 return 365 } 366 defer that.releaseSyncHeaderLock() 367 368 if that.getFlightHeaderCount() >= SYNC_MAX_FLIGHT_HEADER_SIZE { 369 return 370 } 371 curBlockHeight := that.ledger.GetCurrentBlockHeight() 372 373 curHeaderHeight := that.ledger.GetCurrentHeaderHeight() 374 //Waiting for block catch up header 375 if curHeaderHeight-curBlockHeight >= uint64(SYNC_MAX_HEADER_FORWARD_SIZE) { 376 return 377 } 378 NextHeaderId := curHeaderHeight + 1 379 reqNode := that.getNextNode(NextHeaderId) 380 if reqNode == nil { 381 return 382 } 383 that.addFlightHeader(reqNode.GetID(), NextHeaderId) 384 385 headerHash := that.ledger.GetCurrentHeaderHash() 386 // fmt.Println(" ********* stopHeight:",headerHash) 387 var nuladd common.Address 388 msg := msgpack.NewHeadersReq(headerHash, nuladd, p2pComm.SYNC_DATA_MAIN, curHeaderHeight) 389 // msg := msgpack.NewHeadersReq(headerHash,nuladd,p2pComm.SYNC_DATA_MAIN) 390 err := that.server.Send(reqNode, msg, false) 391 if err != nil { 392 log.Warn("[p2p]syncHeader failed to send a new headersReq") 393 } else { 394 that.appendReqTime(reqNode.GetID()) 395 } 396 397 log.Info("主链--> Header sync request ", "height", NextHeaderId) 398 } 399 400 func (that *BlockSyncMgr) MainGetBlockHashByHeight(nextBlockHeight uint64) common.Hash { 401 nextBlockHeaderHash := that.ledger.GetBlockHeaderHashByHeight(nextBlockHeight) 402 empty := common.Hash{} 403 if nextBlockHeaderHash != empty { 404 return nextBlockHeaderHash 405 } 406 nextBlockHash, _ := that.ledger.GetBlockHashByHeight(nextBlockHeight) 407 return nextBlockHash 408 } 409 410 func (that *BlockSyncMgr) syncBlock() { 411 if that.tryGetSyncBlockLock() { 412 return 413 } 414 defer that.releaseSyncBlockLock() 415 416 availCount := SYNC_MAX_FLIGHT_BLOCK_SIZE - that.getFlightBlockCount() 417 if availCount <= 0 { 418 return 419 } 420 curBlockHeight := that.ledger.GetCurrentBlockHeight() 421 curHeaderHeight := that.ledger.GetCurrentHeaderHeight() 422 count := int(curHeaderHeight - curBlockHeight) 423 if count <= 0 { 424 return 425 } 426 if count > availCount { 427 count = availCount 428 } 429 cacheCap := SYNC_MAX_BLOCK_CACHE_SIZE - that.getBlockCacheSize() 430 if count > cacheCap { 431 count = cacheCap 432 } 433 434 counter := 1 435 i := uint64(0) 436 reqTimes := 1 437 for { 438 if counter > count { 439 break 440 } 441 i++ 442 nextBlockHeight := curBlockHeight + i 443 nextBlockHash := that.MainGetBlockHashByHeight(uint64(nextBlockHeight)) 444 empty := common.Hash{} 445 if nextBlockHash == empty { 446 return 447 } 448 if that.isBlockOnFlight(nextBlockHash) { 449 if nextBlockHeight <= curBlockHeight+SYNC_NEXT_BLOCKS_HEIGHT { 450 //request more nodes for next block height 451 reqTimes = SYNC_NEXT_BLOCK_TIMES 452 } else { 453 continue 454 } 455 } 456 if that.isInBlockCache(nextBlockHeight) { 457 continue 458 } 459 if nextBlockHeight <= curBlockHeight+SYNC_NEXT_BLOCKS_HEIGHT { 460 reqTimes = SYNC_NEXT_BLOCK_TIMES 461 } 462 for t := 0; t < reqTimes; t++ { 463 reqNode := that.getNextNode(nextBlockHeight) 464 if reqNode == nil { 465 return 466 } 467 that.addFlightBlock(reqNode.GetID(), nextBlockHeight, nextBlockHash) 468 var nuladd common.Address 469 msg := msgpack.NewBlkDataReq(nextBlockHash, nuladd, p2pComm.SYNC_DATA_MAIN) 470 err := that.server.Send(reqNode, msg, false) 471 if err != nil { 472 log.Warn("[p2p]syncBlock", "Height", nextBlockHeight, "err", err) 473 return 474 } else { 475 that.appendReqTime(reqNode.GetID()) 476 } 477 } 478 counter++ 479 reqTimes = 1 480 } 481 } 482 483 //OnHeaderReceive receive header from net 484 func (that *BlockSyncMgr) OnHeaderReceive(fromID uint64, headers []*types.Header) { 485 if len(headers) == 0 { 486 return 487 } 488 log.Info("Header receive", "Height", headers[0].Height, "Height", headers[len(headers)-1].Height) 489 height := headers[0].Height 490 curHeaderHeight := that.ledger.GetCurrentHeaderHeight() 491 492 //Means another gorountinue is adding header 493 if height <= curHeaderHeight { 494 return 495 } 496 if !that.isHeaderOnFlight(height) { 497 return 498 } 499 err := that.ledger.AddHeaders(headers) 500 that.delFlightHeader(height) 501 if err != nil { 502 that.addErrorRespCnt(fromID) 503 n := that.getNodeWeight(fromID) 504 if n != nil && n.GetErrorRespCnt() >= SYNC_MAX_ERROR_RESP_TIMES { 505 that.delNode(fromID) 506 } 507 log.Warn("[p2p]OnHeaderReceive AddHeaders", "err", err) 508 return 509 } 510 that.syncHeader() 511 } 512 513 //OnBlockReceive receive block from net 514 func (that *BlockSyncMgr) OnBlockReceive(fromID uint64, blockSize uint32, block *types.Block) { 515 height := uint32(block.Header.Height) 516 blockHash := block.Hash() 517 log.Trace("[p2p]OnBlockReceive", "height", height) 518 /* fmt.Println("*******************************************[p2p]OnBlockReceive", "height", height) 519 for k, v := range block.Transactions { 520 fmt.Println("num:", k, ",hash:", v.Hash().String(), ",from:", v.TxData.From.ToString(), ",nonce:", v.TxData.Froms.Tis[0].Nonce) 521 }*/ 522 that.lock.Lock() 523 flightInfos := that.flightBlocks[blockHash] 524 that.lock.Unlock() 525 526 for _, flightInfo := range flightInfos { 527 if flightInfo.GetNodeId() == fromID { 528 t := (time.Now().UnixNano() - flightInfo.GetStartTime().UnixNano()) / int64(time.Millisecond) 529 s := float32(blockSize) / float32(t) * 1000.0 / 1024.0 530 that.addNewSpeed(fromID, s) 531 break 532 } 533 } 534 535 that.delFlightBlock(blockHash) 536 curHeaderHeight := uint32(that.ledger.GetCurrentHeaderHeight()) 537 nextHeader := curHeaderHeight + 1 538 if height > nextHeader { 539 return 540 } 541 curBlockHeight := uint32(that.ledger.GetCurrentBlockHeight()) 542 if height <= curBlockHeight { 543 return 544 } 545 546 that.addBlockCache(fromID, block) 547 go that.saveBlock() 548 that.syncBlock() 549 } 550 551 //OnAddNode to node list when a new node added 552 func (that *BlockSyncMgr) OnAddNode(nodeId uint64) { 553 log.Debug("[p2p]OnAddNode", "nodeId", nodeId) 554 that.lock.Lock() 555 defer that.lock.Unlock() 556 w := NewNodeWeight(nodeId) 557 that.nodeWeights[nodeId] = w 558 } 559 560 //OnDelNode remove from node list. When the node disconnect 561 func (that *BlockSyncMgr) OnDelNode(nodeId uint64) { 562 that.delNode(nodeId) 563 log.Info("OnDelNode", "nodeId", nodeId) 564 } 565 566 //delNode remove from node list 567 func (that *BlockSyncMgr) delNode(nodeId uint64) { 568 that.lock.Lock() 569 defer that.lock.Unlock() 570 delete(that.nodeWeights, nodeId) 571 log.Info("delNode", "nodeId", nodeId) 572 if len(that.nodeWeights) == 0 { 573 log.Warn("no sync nodes") 574 } 575 log.Info("OnDelNode", "nodeId", nodeId) 576 } 577 578 func (that *BlockSyncMgr) tryGetSyncHeaderLock() bool { 579 that.lock.Lock() 580 defer that.lock.Unlock() 581 if that.syncHeaderLock { 582 return true 583 } 584 that.syncHeaderLock = true 585 return false 586 } 587 588 func (that *BlockSyncMgr) releaseSyncHeaderLock() { 589 that.lock.Lock() 590 defer that.lock.Unlock() 591 that.syncHeaderLock = false 592 } 593 594 func (that *BlockSyncMgr) tryGetSyncBlockLock() bool { 595 that.lock.Lock() 596 defer that.lock.Unlock() 597 if that.syncBlockLock { 598 return true 599 } 600 that.syncBlockLock = true 601 return false 602 } 603 604 func (that *BlockSyncMgr) releaseSyncBlockLock() { 605 that.lock.Lock() 606 defer that.lock.Unlock() 607 that.syncBlockLock = false 608 } 609 610 func (that *BlockSyncMgr) addBlockCache(nodeID uint64, block *types.Block) bool { 611 that.lock.Lock() 612 defer that.lock.Unlock() 613 blockInfo := &BlockInfo{ 614 nodeID: nodeID, 615 block: block, 616 } 617 that.blocksCache[block.Header.Height] = blockInfo 618 return true 619 } 620 621 func (that *BlockSyncMgr) getBlockCache(blockHeight uint64) (uint64, *types.Block) { 622 that.lock.RLock() 623 defer that.lock.RUnlock() 624 blockInfo, ok := that.blocksCache[blockHeight] 625 if !ok { 626 return 0, nil 627 } 628 return blockInfo.nodeID, blockInfo.block 629 } 630 631 func (that *BlockSyncMgr) delBlockCache(blockHeight uint64) { 632 that.lock.Lock() 633 defer that.lock.Unlock() 634 delete(that.blocksCache, blockHeight) 635 } 636 637 // used 638 func (that *BlockSyncMgr) tryGetSaveBlockLock() bool { 639 that.lock.Lock() 640 defer that.lock.Unlock() 641 if that.saveBlockLock { 642 return true 643 } 644 that.saveBlockLock = true 645 return false 646 } 647 648 func (that *BlockSyncMgr) releaseSaveBlockLock() { 649 that.lock.Lock() 650 defer that.lock.Unlock() 651 that.saveBlockLock = false 652 } 653 654 func (that *BlockSyncMgr) saveBlock() { 655 if that.tryGetSaveBlockLock() { 656 return 657 } 658 defer that.releaseSaveBlockLock() 659 curBlockHeight := that.ledger.GetCurrentBlockHeight() 660 nextBlockHeight := curBlockHeight + 1 661 that.lock.Lock() 662 for height := range that.blocksCache { 663 if uint64(height) <= curBlockHeight { 664 delete(that.blocksCache, height) 665 } 666 } 667 that.lock.Unlock() 668 for { 669 fromID, nextBlock := that.getBlockCache(nextBlockHeight) 670 if nextBlock == nil { 671 return 672 } 673 if that.lockBlkHeight == nextBlockHeight && that.syncStatus == true { 674 fmt.Printf("[p2p][block_sync]saveBlock block save lock at:%v\n", that.lockBlkHeight) 675 return 676 } 677 678 blockInfo, err := validation.ValidateBlock(nextBlock, that.ledger) 679 if err == nil { 680 if blockInfo.ObjTxs.Len() > 0 { 681 err = that.checkLeaguesBlock(blockInfo.ObjTxs) 682 if err != nil { 683 log.Error("[p2p][block_sync] checkLeaguesBlock error", "err", err) 684 return 685 } 686 } 687 err = that.ledger.SaveAll(blockInfo) 688 fmt.Printf("[p2p][block_sync] save received block data: hash=%s,height=%d,err=%v\n", blockInfo.Block.Hash(), blockInfo.Block.Header.Height, err) 689 } 690 that.delBlockCache(nextBlockHeight) 691 if err != nil { //flag001 692 that.addErrorRespCnt(fromID) 693 n := that.getNodeWeight(fromID) 694 if n != nil && n.GetErrorRespCnt() >= SYNC_MAX_ERROR_RESP_TIMES { 695 that.delNode(fromID) 696 } 697 log.Warn("[p2p]saveBlock", "Height", nextBlockHeight, "err", err) 698 reqNode := that.getNextNode(nextBlockHeight) 699 if reqNode == nil { 700 return 701 } 702 that.addFlightBlock(reqNode.GetID(), nextBlockHeight, nextBlock.Hash()) 703 var nuladd common.Address 704 msg := msgpack.NewBlkDataReq(nextBlock.Hash(), nuladd, p2pComm.SYNC_DATA_MAIN) 705 err := that.server.Send(reqNode, msg, false) 706 if err != nil { 707 log.Warn("[p2p]require new block", "err", err) 708 return 709 } else { 710 that.appendReqTime(reqNode.GetID()) 711 } 712 return 713 } 714 nextBlockHeight++ 715 that.pingOutsyncNodes(nextBlockHeight - 1) 716 } 717 } 718 719 func (that *BlockSyncMgr) checkLeaguesBlock(objTxs types.Transactions) error { 720 t := time.Now() 721 fmt.Printf("[p2p][block_sync] checkLeaguesBlock [id=%v]begin:%v\n", t.Nanosecond(), t.String()) 722 defer fmt.Printf("[p2p][block_sync] checkLeaguesBlock [id=%v]end:%v\n", t.Nanosecond(), time.Now().String()) 723 724 lsp := mainchain.NewLeagueStatePipe() 725 leaguesNum := that.radar.CheckLeaguesResult(objTxs, lsp) 726 for leaguesNum > 0 { 727 //// [test] for print node info 728 //for leagueId,value := range that.radar.ConvertTxsToObjTxForCheck(objTxs) { 729 // fmt.Printf("[p2p][block_sync]ConvertTxsToObjTxForCheck,leagueId=%v,value=%v\n", leagueId,value) 730 // for key,value := range mainchain.GetNodeLHCacheInstance().GetNodeLeagueHeight(leagueId) { 731 // fmt.Printf("[p2p][block_sync]nodeId:%v,nodeHeight:%v,nodePeerHandle:%v\n",key,value,that.server.GetNodeFromDiscoverID(key)) 732 // } 733 //} 734 select { 735 case sign := <-lsp.StateSignal: 736 switch sign.(type) { 737 case *mainchain.LeagueNeed: 738 leagueBlockNeed := sign.(*mainchain.LeagueNeed) 739 fmt.Println("[p2p][block_sync] LeagueNeedBlock:", leagueBlockNeed.LeagueId.ToString(), leagueBlockNeed.BlockHeight) 740 //nodeLH := mainchain.GetNodeLHCacheInstance().GetNodeLeagueHeight(leagueBlockNeed.LeagueId) 741 //for nodeIdStr, height := range nodeLH { 742 // if height < leagueBlockNeed.BlockHeight { 743 // continue 744 // } 745 // reqNode := that.server.GetNodeFromDiscoverID(nodeIdStr) 746 // if reqNode == nil { 747 // fmt.Printf("[p2p][block_sync] server.GetNodeFromDiscoverID is nil, nodeIdStr=%v\n",nodeIdStr) 748 // continue 749 // } 750 // fmt.Printf("[p2p][block_sync]nodeID%v,height:%v\n", nodeIdStr, height) 751 // extDataReq := &p2pComm.ExtDataResponse{ 752 // IsReq:true, 753 // LeagueId: leagueBlockNeed.LeagueId, 754 // Height: leagueBlockNeed.BlockHeight, 755 // Data:nil, 756 // } 757 // msg := msgpack.NewExtMsg(extDataReq) 758 // err := that.server.Send(reqNode, msg, false) 759 // if err != nil { 760 // log.Warn("[p2p]require ext block msg", "err", err) 761 // continue 762 // } else { 763 // that.appendReqTime(reqNode.GetID()) 764 // } 765 //} 766 extDataReq := &p2pComm.ExtDataRequest{ 767 LeagueId: leagueBlockNeed.LeagueId, 768 Height: leagueBlockNeed.BlockHeight, 769 } 770 err := that.server.Xmit(extDataReq) 771 if nil != err { 772 log.Warn("[p2p]error xmit message", "err", err.Error(), "Message", reflect.TypeOf(extDataReq)) 773 } 774 case *mainchain.LeagueExec: 775 fmt.Println("[p2p][block_sync] LeagueExec") 776 case *mainchain.LeagueErr: 777 // reget block info 778 leagueErr := sign.(*mainchain.LeagueErr) 779 fmt.Println("[p2p][block_sync] LeagueErr:", leagueErr) 780 } 781 case addr, ok := <-lsp.Successed: 782 if ok { 783 leaguesNum-- 784 if leaguesNum <= 0 { 785 fmt.Println("[p2p][block_sync] Check all OK") 786 that.radar.CommitLastHeight() 787 } 788 fmt.Printf("[p2p][block_sync] radar.CheckLeaguesResult,leaguesAddr[%v]\n", addr.ToString()) 789 } 790 //leaguesNum-- 791 //if leaguesNum <= 0 { 792 // fmt.Println("[p2p][block_sync] Check all OK") 793 // that.radar.CommitLastHeight() 794 //} 795 //fmt.Printf("[p2p][block_sync] radar.CheckLeaguesResult,leaguesNum[%v]\n", leaguesNum) 796 //case time.After(time.Second * 3): 797 // leaguesNum = -1 798 } 799 } 800 801 return nil 802 } 803 804 func (that *BlockSyncMgr) isInBlockCache(blockHeight uint64) bool { 805 that.lock.RLock() 806 defer that.lock.RUnlock() 807 _, ok := that.blocksCache[blockHeight] 808 return ok 809 } 810 811 func (that *BlockSyncMgr) getBlockCacheSize() int { 812 that.lock.RLock() 813 defer that.lock.RUnlock() 814 return len(that.blocksCache) 815 } 816 817 func (that *BlockSyncMgr) addFlightHeader(nodeId uint64, height uint64) { 818 that.lock.Lock() 819 defer that.lock.Unlock() 820 that.flightHeaders[height] = NewSyncFlightInfo(height, nodeId) 821 } 822 823 func (that *BlockSyncMgr) getFlightHeader(height uint64) *SyncFlightInfo { 824 that.lock.RLock() 825 defer that.lock.RUnlock() 826 info, ok := that.flightHeaders[height] 827 if !ok { 828 return nil 829 } 830 return info 831 } 832 833 func (that *BlockSyncMgr) delFlightHeader(height uint64) bool { 834 that.lock.Lock() 835 defer that.lock.Unlock() 836 _, ok := that.flightHeaders[height] 837 if !ok { 838 return false 839 } 840 delete(that.flightHeaders, height) 841 return true 842 } 843 844 func (that *BlockSyncMgr) getFlightHeaderCount() int { 845 that.lock.RLock() 846 defer that.lock.RUnlock() 847 return len(that.flightHeaders) 848 } 849 850 // used 851 func (that *BlockSyncMgr) isHeaderOnFlight(height uint64) bool { 852 flightInfo := that.getFlightHeader(height) 853 return flightInfo != nil 854 } 855 856 func (that *BlockSyncMgr) addFlightBlock(nodeId uint64, height uint64, blockHash common.Hash) { 857 that.lock.Lock() 858 defer that.lock.Unlock() 859 that.flightBlocks[blockHash] = append(that.flightBlocks[blockHash], NewSyncFlightInfo(height, nodeId)) 860 } 861 862 func (that *BlockSyncMgr) getFlightBlock(blockHash common.Hash) []*SyncFlightInfo { 863 that.lock.RLock() 864 defer that.lock.RUnlock() 865 info, ok := that.flightBlocks[blockHash] 866 if !ok { 867 return nil 868 } 869 return info 870 } 871 872 func (that *BlockSyncMgr) delFlightBlock(blockHash common.Hash) bool { 873 that.lock.Lock() 874 defer that.lock.Unlock() 875 _, ok := that.flightBlocks[blockHash] 876 if !ok { 877 return false 878 } 879 delete(that.flightBlocks, blockHash) 880 return true 881 } 882 883 func (that *BlockSyncMgr) getFlightBlockCount() int { 884 that.lock.RLock() 885 defer that.lock.RUnlock() 886 cnt := 0 887 for hash := range that.flightBlocks { 888 cnt += len(that.flightBlocks[hash]) 889 } 890 return cnt 891 } 892 893 func (that *BlockSyncMgr) isBlockOnFlight(blockHash common.Hash) bool { 894 flightInfos := that.getFlightBlock(blockHash) 895 if len(flightInfos) != 0 { 896 return true 897 } 898 return false 899 } 900 901 func (that *BlockSyncMgr) getNextNode(nextBlockHeight uint64) *peer.Peer { 902 weights := that.getAllNodeWeights() 903 sort.Sort(sort.Reverse(weights)) 904 nodelist := make([]uint64, 0) 905 for _, n := range weights { 906 nodelist = append(nodelist, n.id) 907 } 908 nextNodeIndex := 0 909 triedNode := make(map[uint64]bool, 0) 910 for { 911 var nextNodeId uint64 912 nextNodeIndex, nextNodeId = getNextNodeId(nextNodeIndex, nodelist) 913 if nextNodeId == 0 { 914 return nil 915 } 916 _, ok := triedNode[nextNodeId] 917 if ok { 918 return nil 919 } 920 triedNode[nextNodeId] = true 921 n := that.server.GetNode(nextNodeId) 922 if n == nil { 923 continue 924 } 925 if n.GetSyncState() != p2pComm.ESTABLISH { 926 continue 927 } 928 nodeBlockHeight := n.GetHeight() 929 if nextBlockHeight <= nodeBlockHeight { 930 return n 931 } 932 } 933 } 934 935 // used 936 // 1. Poll to find a node higher than the current height 937 // 2. If the node has not requested the height yet, use the node 938 // 3. Otherwise find the node with the fewest failures 939 func (that *BlockSyncMgr) getNodeWithMinFailedTimes(flightInfo *SyncFlightInfo, curBlockHeight uint64) *peer.Peer { 940 var minFailedTimes = math.MaxInt64 941 var minFailedTimesNode *peer.Peer 942 triedNode := make(map[uint64]bool, 0) 943 for { 944 nextNode := that.getNextNode(curBlockHeight + 1) 945 if nextNode == nil { 946 return nil 947 } 948 failedTimes := flightInfo.GetFailedTimes(nextNode.GetID()) 949 if failedTimes == 0 { 950 return nextNode 951 } 952 _, ok := triedNode[nextNode.GetID()] 953 if ok { 954 return minFailedTimesNode 955 } 956 triedNode[nextNode.GetID()] = true 957 if failedTimes < minFailedTimes { 958 minFailedTimes = failedTimes 959 minFailedTimesNode = nextNode 960 } 961 } 962 } 963 964 //Stop to sync 965 func (that *BlockSyncMgr) Close() { 966 close(that.exitCh) 967 } 968 969 //Stop to sync 970 func (that *BlockSyncMgr) SetSyncStatus(status bool, lockHeight uint64) { 971 that.syncStatus = status 972 that.lockBlkHeight = lockHeight 973 } 974 975 //getNodeWeight get nodeweight by id // used 976 func (that *BlockSyncMgr) getNodeWeight(nodeId uint64) *NodeWeight { 977 that.lock.RLock() 978 defer that.lock.RUnlock() 979 return that.nodeWeights[nodeId] 980 } 981 982 //getAllNodeWeights get all nodeweight and return a slice 983 func (that *BlockSyncMgr) getAllNodeWeights() NodeWeights { 984 that.lock.RLock() 985 defer that.lock.RUnlock() 986 weights := make(NodeWeights, 0, len(that.nodeWeights)) 987 for _, w := range that.nodeWeights { 988 weights = append(weights, w) 989 } 990 return weights 991 } 992 993 //addTimeoutCnt incre a node's timeout count // used 994 func (that *BlockSyncMgr) addTimeoutCnt(nodeId uint64) { 995 n := that.getNodeWeight(nodeId) 996 if n != nil { 997 n.AddTimeoutCnt() 998 } 999 } 1000 1001 //addErrorRespCnt incre a node's error resp count // used 1002 func (that *BlockSyncMgr) addErrorRespCnt(nodeId uint64) { 1003 n := that.getNodeWeight(nodeId) 1004 if n != nil { 1005 n.AddErrorRespCnt() 1006 } 1007 } 1008 1009 //appendReqTime append a node's request time // used 1010 func (that *BlockSyncMgr) appendReqTime(nodeId uint64) { 1011 n := that.getNodeWeight(nodeId) 1012 if n != nil { 1013 n.AppendNewReqtime() 1014 } 1015 } 1016 1017 //addNewSpeed apend the new speed to tail, remove the oldest one 1018 func (that *BlockSyncMgr) addNewSpeed(nodeId uint64, speed float32) { 1019 n := that.getNodeWeight(nodeId) 1020 if n != nil { 1021 n.AppendNewSpeed(speed) 1022 } 1023 } 1024 1025 //pingOutsyncNodes send ping msg to lower height nodes for syncing 1026 func (that *BlockSyncMgr) pingOutsyncNodes(curHeight uint64) { 1027 peers := make([]*peer.Peer, 0) 1028 that.lock.RLock() 1029 maxHeight := curHeight 1030 for id := range that.nodeWeights { 1031 peer := that.server.GetNode(id) 1032 if peer == nil { 1033 continue 1034 } 1035 peerHeight := peer.GetHeight() 1036 if peerHeight >= maxHeight { 1037 maxHeight = peerHeight 1038 } 1039 if peerHeight < curHeight { 1040 peers = append(peers, peer) 1041 } 1042 } 1043 that.lock.RUnlock() 1044 if curHeight > maxHeight-SYNC_MAX_HEIGHT_OFFSET && len(peers) > 0 { 1045 that.server.PingTo(peers, false) 1046 } 1047 } 1048 1049 //Using polling for load balance 1050 func getNextNodeId(nextNodeIndex int, nodeList []uint64) (int, uint64) { 1051 num := len(nodeList) 1052 if num == 0 { 1053 return 0, 0 1054 } 1055 if nextNodeIndex >= num { 1056 nextNodeIndex = 0 1057 } 1058 index := nextNodeIndex 1059 nextNodeIndex++ 1060 return nextNodeIndex, nodeList[index] 1061 }