github.phpd.cn/morph-l2/go-ethereum@v1.9.7/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/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core/types" 25 "github.com/ethereum/go-ethereum/rlp" 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 stop chan struct{} 41 42 retriever *retrieveManager 43 } 44 45 func newLesTxRelay(ps *peerSet, retriever *retrieveManager) *lesTxRelay { 46 r := &lesTxRelay{ 47 txSent: make(map[common.Hash]*ltrInfo), 48 txPending: make(map[common.Hash]struct{}), 49 ps: ps, 50 retriever: retriever, 51 stop: make(chan struct{}), 52 } 53 ps.notify(r) 54 return r 55 } 56 57 func (self *lesTxRelay) Stop() { 58 close(self.stop) 59 } 60 61 func (self *lesTxRelay) registerPeer(p *peer) { 62 self.lock.Lock() 63 defer self.lock.Unlock() 64 65 self.peerList = self.ps.AllPeers() 66 } 67 68 func (self *lesTxRelay) unregisterPeer(p *peer) { 69 self.lock.Lock() 70 defer self.lock.Unlock() 71 72 self.peerList = self.ps.AllPeers() 73 } 74 75 // send sends a list of transactions to at most a given number of peers at 76 // once, never resending any particular transaction to the same peer twice 77 func (self *lesTxRelay) send(txs types.Transactions, count int) { 78 sendTo := make(map[*peer]types.Transactions) 79 80 self.peerStartPos++ // rotate the starting position of the peer list 81 if self.peerStartPos >= len(self.peerList) { 82 self.peerStartPos = 0 83 } 84 85 for _, tx := range txs { 86 hash := tx.Hash() 87 ltr, ok := self.txSent[hash] 88 if !ok { 89 ltr = <rInfo{ 90 tx: tx, 91 sentTo: make(map[*peer]struct{}), 92 } 93 self.txSent[hash] = ltr 94 self.txPending[hash] = struct{}{} 95 } 96 97 if len(self.peerList) > 0 { 98 cnt := count 99 pos := self.peerStartPos 100 for { 101 peer := self.peerList[pos] 102 if _, ok := ltr.sentTo[peer]; !ok { 103 sendTo[peer] = append(sendTo[peer], tx) 104 ltr.sentTo[peer] = struct{}{} 105 cnt-- 106 } 107 if cnt == 0 { 108 break // sent it to the desired number of peers 109 } 110 pos++ 111 if pos == len(self.peerList) { 112 pos = 0 113 } 114 if pos == self.peerStartPos { 115 break // tried all available peers 116 } 117 } 118 } 119 } 120 121 for p, list := range sendTo { 122 pp := p 123 ll := list 124 enc, _ := rlp.EncodeToBytes(ll) 125 126 reqID := genReqID() 127 rq := &distReq{ 128 getCost: func(dp distPeer) uint64 { 129 peer := dp.(*peer) 130 return peer.GetTxRelayCost(len(ll), len(enc)) 131 }, 132 canSend: func(dp distPeer) bool { 133 return !dp.(*peer).onlyAnnounce && dp.(*peer) == pp 134 }, 135 request: func(dp distPeer) func() { 136 peer := dp.(*peer) 137 cost := peer.GetTxRelayCost(len(ll), len(enc)) 138 peer.fcServer.QueuedRequest(reqID, cost) 139 return func() { peer.SendTxs(reqID, cost, enc) } 140 }, 141 } 142 go self.retriever.retrieve(context.Background(), reqID, rq, func(p distPeer, msg *Msg) error { return nil }, self.stop) 143 } 144 } 145 146 func (self *lesTxRelay) Send(txs types.Transactions) { 147 self.lock.Lock() 148 defer self.lock.Unlock() 149 150 self.send(txs, 3) 151 } 152 153 func (self *lesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) { 154 self.lock.Lock() 155 defer self.lock.Unlock() 156 157 for _, hash := range mined { 158 delete(self.txPending, hash) 159 } 160 161 for _, hash := range rollback { 162 self.txPending[hash] = struct{}{} 163 } 164 165 if len(self.txPending) > 0 { 166 txs := make(types.Transactions, len(self.txPending)) 167 i := 0 168 for hash := range self.txPending { 169 txs[i] = self.txSent[hash].tx 170 i++ 171 } 172 self.send(txs, 1) 173 } 174 } 175 176 func (self *lesTxRelay) Discard(hashes []common.Hash) { 177 self.lock.Lock() 178 defer self.lock.Unlock() 179 180 for _, hash := range hashes { 181 delete(self.txSent, hash) 182 delete(self.txPending, hash) 183 } 184 }