github.com/cryptogateway/go-paymex@v0.0.0-20210204174735-96277fb1e602/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/cryptogateway/go-paymex/common" 24 "github.com/cryptogateway/go-paymex/core/types" 25 "github.com/cryptogateway/go-paymex/rlp" 26 ) 27 28 type lesTxRelay struct { 29 txSent map[common.Hash]*types.Transaction 30 txPending map[common.Hash]struct{} 31 peerList []*serverPeer 32 peerStartPos int 33 lock sync.Mutex 34 stop chan struct{} 35 36 retriever *retrieveManager 37 } 38 39 func newLesTxRelay(ps *serverPeerSet, retriever *retrieveManager) *lesTxRelay { 40 r := &lesTxRelay{ 41 txSent: make(map[common.Hash]*types.Transaction), 42 txPending: make(map[common.Hash]struct{}), 43 retriever: retriever, 44 stop: make(chan struct{}), 45 } 46 ps.subscribe(r) 47 return r 48 } 49 50 func (ltrx *lesTxRelay) Stop() { 51 close(ltrx.stop) 52 } 53 54 func (ltrx *lesTxRelay) registerPeer(p *serverPeer) { 55 ltrx.lock.Lock() 56 defer ltrx.lock.Unlock() 57 58 // Short circuit if the peer is announce only. 59 if p.onlyAnnounce { 60 return 61 } 62 ltrx.peerList = append(ltrx.peerList, p) 63 } 64 65 func (ltrx *lesTxRelay) unregisterPeer(p *serverPeer) { 66 ltrx.lock.Lock() 67 defer ltrx.lock.Unlock() 68 69 for i, peer := range ltrx.peerList { 70 if peer == p { 71 // Remove from the peer list 72 ltrx.peerList = append(ltrx.peerList[:i], ltrx.peerList[i+1:]...) 73 return 74 } 75 } 76 } 77 78 // send sends a list of transactions to at most a given number of peers. 79 func (ltrx *lesTxRelay) send(txs types.Transactions, count int) { 80 sendTo := make(map[*serverPeer]types.Transactions) 81 82 ltrx.peerStartPos++ // rotate the starting position of the peer list 83 if ltrx.peerStartPos >= len(ltrx.peerList) { 84 ltrx.peerStartPos = 0 85 } 86 87 for _, tx := range txs { 88 hash := tx.Hash() 89 _, ok := ltrx.txSent[hash] 90 if !ok { 91 ltrx.txSent[hash] = tx 92 ltrx.txPending[hash] = struct{}{} 93 } 94 if len(ltrx.peerList) > 0 { 95 cnt := count 96 pos := ltrx.peerStartPos 97 for { 98 peer := ltrx.peerList[pos] 99 sendTo[peer] = append(sendTo[peer], tx) 100 cnt-- 101 if cnt == 0 { 102 break // sent it to the desired number of peers 103 } 104 pos++ 105 if pos == len(ltrx.peerList) { 106 pos = 0 107 } 108 if pos == ltrx.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 enc, _ := rlp.EncodeToBytes(ll) 119 120 reqID := genReqID() 121 rq := &distReq{ 122 getCost: func(dp distPeer) uint64 { 123 peer := dp.(*serverPeer) 124 return peer.getTxRelayCost(len(ll), len(enc)) 125 }, 126 canSend: func(dp distPeer) bool { 127 return !dp.(*serverPeer).onlyAnnounce && dp.(*serverPeer) == pp 128 }, 129 request: func(dp distPeer) func() { 130 peer := dp.(*serverPeer) 131 cost := peer.getTxRelayCost(len(ll), len(enc)) 132 peer.fcServer.QueuedRequest(reqID, cost) 133 return func() { peer.sendTxs(reqID, len(ll), enc) } 134 }, 135 } 136 go ltrx.retriever.retrieve(context.Background(), reqID, rq, func(p distPeer, msg *Msg) error { return nil }, ltrx.stop) 137 } 138 } 139 140 func (ltrx *lesTxRelay) Send(txs types.Transactions) { 141 ltrx.lock.Lock() 142 defer ltrx.lock.Unlock() 143 144 ltrx.send(txs, 3) 145 } 146 147 func (ltrx *lesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) { 148 ltrx.lock.Lock() 149 defer ltrx.lock.Unlock() 150 151 for _, hash := range mined { 152 delete(ltrx.txPending, hash) 153 } 154 155 for _, hash := range rollback { 156 ltrx.txPending[hash] = struct{}{} 157 } 158 159 if len(ltrx.txPending) > 0 { 160 txs := make(types.Transactions, len(ltrx.txPending)) 161 i := 0 162 for hash := range ltrx.txPending { 163 txs[i] = ltrx.txSent[hash] 164 i++ 165 } 166 ltrx.send(txs, 1) 167 } 168 } 169 170 func (ltrx *lesTxRelay) Discard(hashes []common.Hash) { 171 ltrx.lock.Lock() 172 defer ltrx.lock.Unlock() 173 174 for _, hash := range hashes { 175 delete(ltrx.txSent, hash) 176 delete(ltrx.txPending, hash) 177 } 178 }