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