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