github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/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 "sync" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/core/types" 24 "github.com/ethereum/go-ethereum/log" 25 ) 26 27 type ltrInfo struct { 28 tx *types.Transaction 29 sentTo map[*peer]struct{} 30 } 31 32 type LesTxRelay struct { 33 txSent map[common.Hash]*ltrInfo 34 txPending map[common.Hash]struct{} 35 ps *peerSet 36 peerList []*peer 37 lock sync.RWMutex 38 39 reqDist *requestDistributor 40 } 41 42 func NewLesTxRelay(ps *peerSet, reqDist *requestDistributor) *LesTxRelay { 43 r := &LesTxRelay{ 44 txSent: make(map[common.Hash]*ltrInfo), 45 txPending: make(map[common.Hash]struct{}), 46 ps: ps, 47 reqDist: reqDist, 48 } 49 ps.notify(r) 50 return r 51 } 52 53 func (self *LesTxRelay) registerPeer(p *peer) { 54 self.lock.Lock() 55 defer self.lock.Unlock() 56 57 self.peerList = self.ps.AllPeers() 58 } 59 60 func (self *LesTxRelay) unregisterPeer(p *peer) { 61 self.lock.Lock() 62 defer self.lock.Unlock() 63 64 self.peerList = self.ps.AllPeers() 65 } 66 67 func (self *LesTxRelay) HasPeerWithEtherbase(etherbase *common.Address) error { 68 _, err := self.ps.getPeerWithEtherbase(etherbase) 69 return err 70 } 71 72 // send sends a list of transactions to at most a given number of peers at 73 // once, never resending any particular transaction to the same peer twice 74 func (self *LesTxRelay) send(txs types.Transactions) { 75 sendTo := make(map[*peer]types.Transactions) 76 77 for _, tx := range txs { 78 hash := tx.Hash() 79 ltr, ok := self.txSent[hash] 80 if !ok { 81 p, err := self.ps.getPeerWithEtherbase(tx.GatewayFeeRecipient()) 82 // TODO(asa): When this happens, the nonce is still incremented, preventing future txs from being added. 83 // We rely on transactions to be rejected in light/txpool validateTx to prevent transactions 84 // with GatewayFeeRecipient != one of our peers from making it to the relayer. 85 if err != nil { 86 log.Error("Unable to find peer with matching etherbase", "err", err, "tx.hash", tx.Hash(), "tx.gatewayFeeRecipient", tx.GatewayFeeRecipient()) 87 continue 88 } 89 sendTo[p] = append(sendTo[p], tx) 90 ltr = <rInfo{ 91 tx: tx, 92 sentTo: make(map[*peer]struct{}), 93 } 94 self.txSent[hash] = ltr 95 self.txPending[hash] = struct{}{} 96 } 97 } 98 99 for p, list := range sendTo { 100 pp := p 101 ll := list 102 103 reqID := genReqID() 104 rq := &distReq{ 105 getCost: func(dp distPeer) uint64 { 106 peer := dp.(*peer) 107 return peer.GetRequestCost(SendTxMsg, len(ll)) 108 }, 109 canSend: func(dp distPeer) bool { 110 return dp.(*peer) == pp 111 }, 112 request: func(dp distPeer) func() { 113 peer := dp.(*peer) 114 cost := peer.GetRequestCost(SendTxMsg, len(ll)) 115 peer.fcServer.QueueRequest(reqID, cost) 116 return func() { peer.SendTxs(reqID, cost, ll) } 117 }, 118 } 119 self.reqDist.queue(rq) 120 } 121 } 122 123 func (self *LesTxRelay) Send(txs types.Transactions) { 124 self.lock.Lock() 125 defer self.lock.Unlock() 126 127 self.send(txs) 128 } 129 130 func (self *LesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) { 131 self.lock.Lock() 132 defer self.lock.Unlock() 133 134 for _, hash := range mined { 135 delete(self.txPending, hash) 136 } 137 138 for _, hash := range rollback { 139 self.txPending[hash] = struct{}{} 140 } 141 142 if len(self.txPending) > 0 { 143 txs := make(types.Transactions, len(self.txPending)) 144 i := 0 145 for hash := range self.txPending { 146 txs[i] = self.txSent[hash].tx 147 i++ 148 } 149 self.send(txs) 150 } 151 } 152 153 func (self *LesTxRelay) Discard(hashes []common.Hash) { 154 self.lock.Lock() 155 defer self.lock.Unlock() 156 157 for _, hash := range hashes { 158 delete(self.txSent, hash) 159 delete(self.txPending, hash) 160 } 161 }