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