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 }