github.com/gochain-io/gochain@v2.2.26+incompatible/les/txrelay.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package les 18 19 import ( 20 "context" 21 "sync" 22 23 "github.com/gochain-io/gochain/common" 24 "github.com/gochain-io/gochain/core/types" 25 "github.com/gochain-io/gochain/log" 26 ) 27 28 type ltrInfo struct { 29 tx *types.Transaction 30 sentTo map[*peer]struct{} 31 } 32 33 type LesTxRelay struct { 34 txSent map[common.Hash]*ltrInfo 35 txPending map[common.Hash]struct{} 36 ps *peerSet 37 peerList []*peer 38 peerStartPos int 39 lock sync.RWMutex 40 41 reqDist *requestDistributor 42 } 43 44 func NewLesTxRelay(ps *peerSet, reqDist *requestDistributor) *LesTxRelay { 45 r := &LesTxRelay{ 46 txSent: make(map[common.Hash]*ltrInfo), 47 txPending: make(map[common.Hash]struct{}), 48 ps: ps, 49 reqDist: reqDist, 50 } 51 ps.notify(r) 52 return r 53 } 54 55 func (self *LesTxRelay) registerPeer(p *peer) { 56 self.lock.Lock() 57 defer self.lock.Unlock() 58 59 self.peerList = self.ps.AllPeers() 60 } 61 62 func (self *LesTxRelay) unregisterPeer(p *peer) { 63 self.lock.Lock() 64 defer self.lock.Unlock() 65 66 self.peerList = self.ps.AllPeers() 67 } 68 69 // send sends a list of transactions to at most a given number of peers at 70 // once, never resending any particular transaction to the same peer twice 71 func (self *LesTxRelay) send(txs types.Transactions, count int) { 72 sendTo := make(map[*peer]types.Transactions) 73 74 self.peerStartPos++ // rotate the starting position of the peer list 75 if self.peerStartPos >= len(self.peerList) { 76 self.peerStartPos = 0 77 } 78 79 for _, tx := range txs { 80 hash := tx.Hash() 81 ltr, ok := self.txSent[hash] 82 if !ok { 83 ltr = <rInfo{ 84 tx: tx, 85 sentTo: make(map[*peer]struct{}), 86 } 87 self.txSent[hash] = ltr 88 self.txPending[hash] = struct{}{} 89 } 90 91 if len(self.peerList) > 0 { 92 cnt := count 93 pos := self.peerStartPos 94 for { 95 peer := self.peerList[pos] 96 if _, ok := ltr.sentTo[peer]; !ok { 97 sendTo[peer] = append(sendTo[peer], tx) 98 ltr.sentTo[peer] = struct{}{} 99 cnt-- 100 } 101 if cnt == 0 { 102 break // sent it to the desired number of peers 103 } 104 pos++ 105 if pos == len(self.peerList) { 106 pos = 0 107 } 108 if pos == self.peerStartPos { 109 break // tried all available peers 110 } 111 } 112 } 113 } 114 115 for p, list := range sendTo { 116 pp := p 117 ll := list 118 119 reqID := genReqID() 120 rq := &distReq{ 121 getCost: func(dp distPeer) uint64 { 122 peer := dp.(*peer) 123 return peer.GetRequestCost(SendTxMsg, len(ll)) 124 }, 125 canSend: func(dp distPeer) bool { 126 return dp.(*peer) == pp 127 }, 128 request: func(dp distPeer) func(context.Context) { 129 peer := dp.(*peer) 130 cost := peer.GetRequestCost(SendTxMsg, len(ll)) 131 peer.fcServer.QueueRequest(reqID, cost) 132 return func(ctx context.Context) { 133 if err := peer.SendTxs(ctx, reqID, cost, ll); err != nil { 134 log.Error("Cannot send txs in relay", "req_id", reqID, "err", err) 135 } 136 } 137 }, 138 } 139 self.reqDist.queue(rq) 140 } 141 } 142 143 func (self *LesTxRelay) Send(txs types.Transactions) { 144 self.lock.Lock() 145 defer self.lock.Unlock() 146 147 self.send(txs, 3) 148 } 149 150 func (self *LesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) { 151 self.lock.Lock() 152 defer self.lock.Unlock() 153 154 for _, hash := range mined { 155 delete(self.txPending, hash) 156 } 157 158 for _, hash := range rollback { 159 self.txPending[hash] = struct{}{} 160 } 161 162 if len(self.txPending) > 0 { 163 txs := make(types.Transactions, len(self.txPending)) 164 i := 0 165 for hash := range self.txPending { 166 txs[i] = self.txSent[hash].tx 167 i++ 168 } 169 self.send(txs, 1) 170 } 171 } 172 173 func (self *LesTxRelay) Discard(hashes []common.Hash) { 174 self.lock.Lock() 175 defer self.lock.Unlock() 176 177 for _, hash := range hashes { 178 delete(self.txSent, hash) 179 delete(self.txPending, hash) 180 } 181 }