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 = &ltrInfo{
    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  }