github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/netsync/chainmgr/block_keeper.go (about)

     1  package chainmgr
     2  
     3  import (
     4  	"time"
     5  
     6  	log "github.com/sirupsen/logrus"
     7  
     8  	"github.com/bytom/bytom/consensus"
     9  	dbm "github.com/bytom/bytom/database/leveldb"
    10  	"github.com/bytom/bytom/netsync/peers"
    11  	"github.com/bytom/bytom/p2p/security"
    12  	"github.com/bytom/bytom/protocol/bc"
    13  	"github.com/bytom/bytom/protocol/bc/types"
    14  )
    15  
    16  const (
    17  	syncCycle = 5 * time.Second
    18  
    19  	noNeedSync = iota
    20  	fastSyncType
    21  	regularSyncType
    22  )
    23  
    24  var (
    25  	maxNumOfBlocksPerMsg      = uint64(64)
    26  	maxNumOfHeadersPerMsg     = uint64(1000)
    27  	maxNumOfBlocksRegularSync = uint64(128)
    28  )
    29  
    30  // Fetcher is the interface for fetch struct
    31  type Fetcher interface {
    32  	processBlock(peerID string, block *types.Block)
    33  	processBlocks(peerID string, blocks []*types.Block)
    34  	processHeaders(peerID string, headers []*types.BlockHeader)
    35  	requireBlock(peerID string, height uint64) (*types.Block, error)
    36  }
    37  
    38  type blockMsg struct {
    39  	block  *types.Block
    40  	peerID string
    41  }
    42  
    43  type blocksMsg struct {
    44  	blocks []*types.Block
    45  	peerID string
    46  }
    47  
    48  type headersMsg struct {
    49  	headers []*types.BlockHeader
    50  	peerID  string
    51  }
    52  
    53  type blockKeeper struct {
    54  	chain      Chain
    55  	fastSync   *fastSync
    56  	msgFetcher Fetcher
    57  	peers      *peers.PeerSet
    58  	syncPeer   *peers.Peer
    59  
    60  	quit chan struct{}
    61  }
    62  
    63  func newBlockKeeper(chain Chain, peers *peers.PeerSet, fastSyncDB dbm.DB) *blockKeeper {
    64  	storage := newStorage(fastSyncDB)
    65  	msgFetcher := newMsgFetcher(storage, peers)
    66  	return &blockKeeper{
    67  		chain:      chain,
    68  		fastSync:   newFastSync(chain, msgFetcher, storage, peers),
    69  		msgFetcher: msgFetcher,
    70  		peers:      peers,
    71  		quit:       make(chan struct{}),
    72  	}
    73  }
    74  
    75  func (bk *blockKeeper) locateBlocks(locator []*bc.Hash, stopHash *bc.Hash, isTimeout func() bool) ([]*types.Block, error) {
    76  	headers, err := bk.locateHeaders(locator, stopHash, 0, maxNumOfBlocksPerMsg)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	blocks := []*types.Block{}
    82  	for _, header := range headers {
    83  		headerHash := header.Hash()
    84  		block, err := bk.chain.GetBlockByHash(&headerHash)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  
    89  		blocks = append(blocks, block)
    90  		if isTimeout() {
    91  			break
    92  		}
    93  	}
    94  	return blocks, nil
    95  }
    96  
    97  func (bk *blockKeeper) locateHeaders(locator []*bc.Hash, stopHash *bc.Hash, skip uint64, maxNum uint64) ([]*types.BlockHeader, error) {
    98  	startHeader, err := bk.chain.GetHeaderByHeight(0)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	for _, hash := range locator {
   104  		header, err := bk.chain.GetHeaderByHash(hash)
   105  		if err == nil && bk.chain.InMainChain(header.Hash()) {
   106  			startHeader = header
   107  			break
   108  		}
   109  	}
   110  
   111  	headers := make([]*types.BlockHeader, 0)
   112  	stopHeader, err := bk.chain.GetHeaderByHash(stopHash)
   113  	if err != nil {
   114  		return headers, err
   115  	}
   116  
   117  	if !bk.chain.InMainChain(*stopHash) || stopHeader.Height < startHeader.Height {
   118  		return headers, nil
   119  	}
   120  
   121  	headers = append(headers, startHeader)
   122  	if stopHeader.Height == startHeader.Height {
   123  		return headers, nil
   124  	}
   125  
   126  	for num, index := uint64(0), startHeader.Height; num < maxNum-1; num++ {
   127  		index += skip + 1
   128  		if index >= stopHeader.Height {
   129  			headers = append(headers, stopHeader)
   130  			break
   131  		}
   132  
   133  		header, err := bk.chain.GetHeaderByHeight(index)
   134  		if err != nil {
   135  			return nil, err
   136  		}
   137  
   138  		headers = append(headers, header)
   139  	}
   140  
   141  	return headers, nil
   142  }
   143  
   144  func (bk *blockKeeper) processBlock(peerID string, block *types.Block) {
   145  	bk.msgFetcher.processBlock(peerID, block)
   146  }
   147  
   148  func (bk *blockKeeper) processBlocks(peerID string, blocks []*types.Block) {
   149  	bk.msgFetcher.processBlocks(peerID, blocks)
   150  }
   151  
   152  func (bk *blockKeeper) processHeaders(peerID string, headers []*types.BlockHeader) {
   153  	bk.msgFetcher.processHeaders(peerID, headers)
   154  }
   155  
   156  func (bk *blockKeeper) regularBlockSync() error {
   157  	peerHeight := bk.syncPeer.Height()
   158  	bestHeight := bk.chain.BestBlockHeight()
   159  	targetHeight := bestHeight + maxNumOfBlocksRegularSync
   160  	if targetHeight > peerHeight {
   161  		targetHeight = peerHeight
   162  	}
   163  
   164  	for i := bestHeight + 1; i <= targetHeight; {
   165  		block, err := bk.msgFetcher.requireBlock(bk.syncPeer.ID(), i)
   166  		if err != nil {
   167  			bk.peers.ProcessIllegal(bk.syncPeer.ID(), security.LevelConnException, err.Error())
   168  			return err
   169  		}
   170  
   171  		isOrphan, err := bk.chain.ProcessBlock(block)
   172  		if err != nil {
   173  			bk.peers.ProcessIllegal(bk.syncPeer.ID(), security.LevelMsgIllegal, err.Error())
   174  			return err
   175  		}
   176  
   177  		if isOrphan {
   178  			i--
   179  			continue
   180  		}
   181  
   182  		//This code is used to preventing the sync peer return a dust block which will not change the node's chain status
   183  		if bestHeight = bk.chain.BestBlockHeight(); i == bestHeight+1 {
   184  			log.WithFields(log.Fields{"module": logModule, "height": i}).Warn("stop regular sync due to loop sync same height")
   185  			return nil
   186  		}
   187  
   188  		i = bestHeight + 1
   189  	}
   190  	log.WithFields(log.Fields{"module": logModule, "height": bk.chain.BestBlockHeight()}).Info("regular sync success")
   191  	return nil
   192  }
   193  
   194  func (bk *blockKeeper) start() {
   195  	go bk.syncWorker()
   196  }
   197  
   198  func (bk *blockKeeper) checkSyncType() int {
   199  	bestHeight := bk.chain.BestBlockHeight()
   200  	peer := bk.peers.BestPeer(consensus.SFFullNode | consensus.SFFastSync)
   201  	if peer != nil {
   202  		if peerJustifiedHeight := peer.JustifiedHeight(); peerJustifiedHeight >= bestHeight+minGapStartFastSync {
   203  			bk.fastSync.setSyncPeer(peer)
   204  			return fastSyncType
   205  		}
   206  	}
   207  
   208  	peer = bk.peers.BestPeer(consensus.SFFullNode)
   209  	if peer == nil {
   210  		log.WithFields(log.Fields{"module": logModule}).Debug("can't find sync peer")
   211  		return noNeedSync
   212  	}
   213  
   214  	if peer.Height() > bestHeight {
   215  		bk.syncPeer = peer
   216  		return regularSyncType
   217  	}
   218  
   219  	return noNeedSync
   220  }
   221  
   222  func (bk *blockKeeper) startSync() bool {
   223  	switch bk.checkSyncType() {
   224  	case fastSyncType:
   225  		if err := bk.fastSync.process(); err != nil {
   226  			log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("failed on fast sync")
   227  			return false
   228  		}
   229  	case regularSyncType:
   230  		if err := bk.regularBlockSync(); err != nil {
   231  			log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on regularBlockSync")
   232  			return false
   233  		}
   234  	default:
   235  		return false
   236  	}
   237  
   238  	return true
   239  }
   240  
   241  func (bk *blockKeeper) stop() {
   242  	close(bk.quit)
   243  }
   244  
   245  func (bk *blockKeeper) syncWorker() {
   246  	syncTicker := time.NewTicker(syncCycle)
   247  	defer syncTicker.Stop()
   248  
   249  	for {
   250  		select {
   251  		case <-syncTicker.C:
   252  			if update := bk.startSync(); !update {
   253  				continue
   254  			}
   255  
   256  			lastJustifiedHeader, err := bk.chain.LastJustifiedHeader()
   257  			if err != nil {
   258  				log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail get last just justified header")
   259  			}
   260  
   261  			if err := bk.peers.BroadcastNewStatus(bk.chain.BestBlockHeader(), lastJustifiedHeader); err != nil {
   262  				log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker broadcast new status")
   263  			}
   264  		case <-bk.quit:
   265  			return
   266  		}
   267  	}
   268  }