github.com/luckypickle/go-ethereum-vet@v1.14.2/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/luckypickle/go-ethereum-vet/common"
    23  	"github.com/luckypickle/go-ethereum-vet/core/types"
    24  )
    25  
    26  type ltrInfo struct {
    27  	tx     *types.Transaction
    28  	sentTo map[*peer]struct{}
    29  }
    30  
    31  type LesTxRelay struct {
    32  	txSent       map[common.Hash]*ltrInfo
    33  	txPending    map[common.Hash]struct{}
    34  	ps           *peerSet
    35  	peerList     []*peer
    36  	peerStartPos int
    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  // send sends a list of transactions to at most a given number of peers at
    68  // once, never resending any particular transaction to the same peer twice
    69  func (self *LesTxRelay) send(txs types.Transactions, count int) {
    70  	sendTo := make(map[*peer]types.Transactions)
    71  
    72  	self.peerStartPos++ // rotate the starting position of the peer list
    73  	if self.peerStartPos >= len(self.peerList) {
    74  		self.peerStartPos = 0
    75  	}
    76  
    77  	for _, tx := range txs {
    78  		hash := tx.Hash()
    79  		ltr, ok := self.txSent[hash]
    80  		if !ok {
    81  			ltr = &ltrInfo{
    82  				tx:     tx,
    83  				sentTo: make(map[*peer]struct{}),
    84  			}
    85  			self.txSent[hash] = ltr
    86  			self.txPending[hash] = struct{}{}
    87  		}
    88  
    89  		if len(self.peerList) > 0 {
    90  			cnt := count
    91  			pos := self.peerStartPos
    92  			for {
    93  				peer := self.peerList[pos]
    94  				if _, ok := ltr.sentTo[peer]; !ok {
    95  					sendTo[peer] = append(sendTo[peer], tx)
    96  					ltr.sentTo[peer] = struct{}{}
    97  					cnt--
    98  				}
    99  				if cnt == 0 {
   100  					break // sent it to the desired number of peers
   101  				}
   102  				pos++
   103  				if pos == len(self.peerList) {
   104  					pos = 0
   105  				}
   106  				if pos == self.peerStartPos {
   107  					break // tried all available peers
   108  				}
   109  			}
   110  		}
   111  	}
   112  
   113  	for p, list := range sendTo {
   114  		pp := p
   115  		ll := list
   116  
   117  		reqID := genReqID()
   118  		rq := &distReq{
   119  			getCost: func(dp distPeer) uint64 {
   120  				peer := dp.(*peer)
   121  				return peer.GetRequestCost(SendTxMsg, len(ll))
   122  			},
   123  			canSend: func(dp distPeer) bool {
   124  				return dp.(*peer) == pp
   125  			},
   126  			request: func(dp distPeer) func() {
   127  				peer := dp.(*peer)
   128  				cost := peer.GetRequestCost(SendTxMsg, len(ll))
   129  				peer.fcServer.QueueRequest(reqID, cost)
   130  				return func() { peer.SendTxs(reqID, cost, ll) }
   131  			},
   132  		}
   133  		self.reqDist.queue(rq)
   134  	}
   135  }
   136  
   137  func (self *LesTxRelay) Send(txs types.Transactions) {
   138  	self.lock.Lock()
   139  	defer self.lock.Unlock()
   140  
   141  	self.send(txs, 3)
   142  }
   143  
   144  func (self *LesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) {
   145  	self.lock.Lock()
   146  	defer self.lock.Unlock()
   147  
   148  	for _, hash := range mined {
   149  		delete(self.txPending, hash)
   150  	}
   151  
   152  	for _, hash := range rollback {
   153  		self.txPending[hash] = struct{}{}
   154  	}
   155  
   156  	if len(self.txPending) > 0 {
   157  		txs := make(types.Transactions, len(self.txPending))
   158  		i := 0
   159  		for hash := range self.txPending {
   160  			txs[i] = self.txSent[hash].tx
   161  			i++
   162  		}
   163  		self.send(txs, 1)
   164  	}
   165  }
   166  
   167  func (self *LesTxRelay) Discard(hashes []common.Hash) {
   168  	self.lock.Lock()
   169  	defer self.lock.Unlock()
   170  
   171  	for _, hash := range hashes {
   172  		delete(self.txSent, hash)
   173  		delete(self.txPending, hash)
   174  	}
   175  }