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  }