github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/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  )
    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() *LesTxRelay {
    43  	return &LesTxRelay{
    44  		txSent:    make(map[common.Hash]*ltrInfo),
    45  		txPending: make(map[common.Hash]struct{}),
    46  	}
    47  }
    48  
    49  func (self *LesTxRelay) addPeer(p *peer) {
    50  	self.lock.Lock()
    51  	defer self.lock.Unlock()
    52  
    53  	self.ps.Register(p)
    54  	self.peerList = self.ps.AllPeers()
    55  }
    56  
    57  func (self *LesTxRelay) removePeer(id string) {
    58  	self.lock.Lock()
    59  	defer self.lock.Unlock()
    60  
    61  	self.ps.Unregister(id)
    62  	self.peerList = self.ps.AllPeers()
    63  }
    64  
    65  // send sends a list of transactions to at most a given number of peers at
    66  // once, never resending any particular transaction to the same peer twice
    67  func (self *LesTxRelay) send(txs types.Transactions, count int) {
    68  	sendTo := make(map[*peer]types.Transactions)
    69  
    70  	self.peerStartPos++ // rotate the starting position of the peer list
    71  	if self.peerStartPos >= len(self.peerList) {
    72  		self.peerStartPos = 0
    73  	}
    74  
    75  	for _, tx := range txs {
    76  		hash := tx.Hash()
    77  		ltr, ok := self.txSent[hash]
    78  		if !ok {
    79  			ltr = &ltrInfo{
    80  				tx:     tx,
    81  				sentTo: make(map[*peer]struct{}),
    82  			}
    83  			self.txSent[hash] = ltr
    84  			self.txPending[hash] = struct{}{}
    85  		}
    86  
    87  		if len(self.peerList) > 0 {
    88  			cnt := count
    89  			pos := self.peerStartPos
    90  			for {
    91  				peer := self.peerList[pos]
    92  				if _, ok := ltr.sentTo[peer]; !ok {
    93  					sendTo[peer] = append(sendTo[peer], tx)
    94  					ltr.sentTo[peer] = struct{}{}
    95  					cnt--
    96  				}
    97  				if cnt == 0 {
    98  					break // sent it to the desired number of peers
    99  				}
   100  				pos++
   101  				if pos == len(self.peerList) {
   102  					pos = 0
   103  				}
   104  				if pos == self.peerStartPos {
   105  					break // tried all available peers
   106  				}
   107  			}
   108  		}
   109  	}
   110  
   111  	for p, list := range sendTo {
   112  		pp := p
   113  		ll := list
   114  
   115  		reqID := getNextReqID()
   116  		rq := &distReq{
   117  			getCost: func(dp distPeer) uint64 {
   118  				peer := dp.(*peer)
   119  				return peer.GetRequestCost(SendTxMsg, len(ll))
   120  			},
   121  			canSend: func(dp distPeer) bool {
   122  				return dp.(*peer) == pp
   123  			},
   124  			request: func(dp distPeer) func() {
   125  				peer := dp.(*peer)
   126  				cost := peer.GetRequestCost(SendTxMsg, len(ll))
   127  				peer.fcServer.QueueRequest(reqID, cost)
   128  				return func() { peer.SendTxs(reqID, cost, ll) }
   129  			},
   130  		}
   131  		self.reqDist.queue(rq)
   132  	}
   133  }
   134  
   135  func (self *LesTxRelay) Send(txs types.Transactions) {
   136  	self.lock.Lock()
   137  	defer self.lock.Unlock()
   138  
   139  	self.send(txs, 3)
   140  }
   141  
   142  func (self *LesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) {
   143  	self.lock.Lock()
   144  	defer self.lock.Unlock()
   145  
   146  	for _, hash := range mined {
   147  		delete(self.txPending, hash)
   148  	}
   149  
   150  	for _, hash := range rollback {
   151  		self.txPending[hash] = struct{}{}
   152  	}
   153  
   154  	if len(self.txPending) > 0 {
   155  		txs := make(types.Transactions, len(self.txPending))
   156  		i := 0
   157  		for hash := range self.txPending {
   158  			txs[i] = self.txSent[hash].tx
   159  			i++
   160  		}
   161  		self.send(txs, 1)
   162  	}
   163  }
   164  
   165  func (self *LesTxRelay) Discard(hashes []common.Hash) {
   166  	self.lock.Lock()
   167  	defer self.lock.Unlock()
   168  
   169  	for _, hash := range hashes {
   170  		delete(self.txSent, hash)
   171  		delete(self.txPending, hash)
   172  	}
   173  }