github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/neatptc/sync.go (about)

     1  package neatptc
     2  
     3  import (
     4  	"math/rand"
     5  	"sync/atomic"
     6  	"time"
     7  
     8  	"github.com/neatlab/neatio/chain/core/types"
     9  	"github.com/neatlab/neatio/chain/log"
    10  	"github.com/neatlab/neatio/neatptc/downloader"
    11  	"github.com/neatlab/neatio/network/p2p/discover"
    12  	"github.com/neatlab/neatio/utilities/common"
    13  )
    14  
    15  const (
    16  	forceSyncCycle      = 10 * time.Second
    17  	minDesiredPeerCount = 5
    18  
    19  	txsyncPackSize = 100 * 1024
    20  )
    21  
    22  type txsync struct {
    23  	p   *peer
    24  	txs []*types.Transaction
    25  }
    26  
    27  func (pm *ProtocolManager) syncTransactions(p *peer) {
    28  	var txs types.Transactions
    29  	pending, _ := pm.txpool.Pending()
    30  	for _, batch := range pending {
    31  		txs = append(txs, batch...)
    32  	}
    33  	if len(txs) == 0 {
    34  		return
    35  	}
    36  	select {
    37  	case pm.txsyncCh <- &txsync{p, txs}:
    38  	case <-pm.quitSync:
    39  	}
    40  }
    41  
    42  func (pm *ProtocolManager) txsyncLoop() {
    43  	var (
    44  		pending = make(map[discover.NodeID]*txsync)
    45  		sending = false
    46  		pack    = new(txsync)
    47  		done    = make(chan error, 1)
    48  	)
    49  
    50  	send := func(s *txsync) {
    51  
    52  		size := common.StorageSize(0)
    53  		pack.p = s.p
    54  		pack.txs = pack.txs[:0]
    55  		for i := 0; i < len(s.txs) && size < txsyncPackSize; i++ {
    56  			pack.txs = append(pack.txs, s.txs[i])
    57  			size += s.txs[i].Size()
    58  		}
    59  
    60  		s.txs = s.txs[:copy(s.txs, s.txs[len(pack.txs):])]
    61  		if len(s.txs) == 0 {
    62  			delete(pending, s.p.ID())
    63  		}
    64  
    65  		s.p.Log().Trace("Sending batch of transactions", "count", len(pack.txs), "bytes", size)
    66  		sending = true
    67  		go func() { done <- pack.p.SendTransactions(pack.txs) }()
    68  	}
    69  
    70  	pick := func() *txsync {
    71  		if len(pending) == 0 {
    72  			return nil
    73  		}
    74  		n := rand.Intn(len(pending)) + 1
    75  		for _, s := range pending {
    76  			if n--; n == 0 {
    77  				return s
    78  			}
    79  		}
    80  		return nil
    81  	}
    82  
    83  	for {
    84  		select {
    85  		case s := <-pm.txsyncCh:
    86  			pending[s.p.ID()] = s
    87  			if !sending {
    88  				send(s)
    89  			}
    90  		case err := <-done:
    91  			sending = false
    92  
    93  			if err != nil {
    94  				pack.p.Log().Debug("Transaction send failed", "err", err)
    95  				delete(pending, pack.p.ID())
    96  			}
    97  
    98  			if s := pick(); s != nil {
    99  				send(s)
   100  			}
   101  		case <-pm.quitSync:
   102  			return
   103  		}
   104  	}
   105  }
   106  
   107  func (pm *ProtocolManager) syncer() {
   108  
   109  	pm.fetcher.Start()
   110  	defer pm.fetcher.Stop()
   111  	defer pm.downloader.Terminate()
   112  
   113  	forceSync := time.NewTicker(forceSyncCycle)
   114  	defer forceSync.Stop()
   115  
   116  	for {
   117  		select {
   118  		case <-pm.newPeerCh:
   119  
   120  			if pm.peers.Len() < minDesiredPeerCount {
   121  				break
   122  			}
   123  			go pm.synchronise(pm.peers.BestPeer())
   124  
   125  		case <-forceSync.C:
   126  
   127  			go pm.synchronise(pm.peers.BestPeer())
   128  
   129  		case <-pm.noMorePeers:
   130  			return
   131  		}
   132  	}
   133  }
   134  
   135  func (pm *ProtocolManager) synchronise(peer *peer) {
   136  
   137  	if peer == nil {
   138  		return
   139  	}
   140  
   141  	currentBlock := pm.blockchain.CurrentBlock()
   142  	td := pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
   143  
   144  	pHead, pTd := peer.Head()
   145  	if pTd.Cmp(td) <= 0 {
   146  		return
   147  	}
   148  
   149  	mode := downloader.FullSync
   150  	if atomic.LoadUint32(&pm.fastSync) == 1 {
   151  
   152  		mode = downloader.FastSync
   153  	} else if currentBlock.NumberU64() == 0 && pm.blockchain.CurrentFastBlock().NumberU64() > 0 {
   154  
   155  		atomic.StoreUint32(&pm.fastSync, 1)
   156  		mode = downloader.FastSync
   157  	}
   158  
   159  	if mode == downloader.FastSync {
   160  
   161  		if pm.blockchain.GetTdByHash(pm.blockchain.CurrentFastBlock().Hash()).Cmp(pTd) >= 0 {
   162  			return
   163  		}
   164  	}
   165  
   166  	if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
   167  		return
   168  	}
   169  	if atomic.LoadUint32(&pm.fastSync) == 1 {
   170  		log.Info("Fast sync complete, auto disabling")
   171  		atomic.StoreUint32(&pm.fastSync, 0)
   172  	}
   173  	atomic.StoreUint32(&pm.acceptTxs, 1)
   174  	if head := pm.blockchain.CurrentBlock(); head.NumberU64() > 0 {
   175  
   176  		go pm.BroadcastBlock(head, false)
   177  	}
   178  }