github.com/annchain/OG@v0.0.9/og/txmaker/fifo_tip_generator.go (about)

     1  package txmaker
     2  
     3  import (
     4  	"github.com/annchain/OG/common"
     5  	"github.com/annchain/OG/og/types"
     6  
     7  	"github.com/sirupsen/logrus"
     8  	"math/rand"
     9  	"sync"
    10  )
    11  
    12  // FIFOTipGenerator wraps txpool random picker so that
    13  // when tps is low, the graph will not be like a chain.
    14  type FIFOTipGenerator struct {
    15  	maxCacheSize int
    16  	upstream     TipGenerator
    17  	fifoRing     []types.Txi
    18  	fifoRingPos  int
    19  	fifoRingFull bool
    20  	mu           sync.RWMutex
    21  }
    22  
    23  func NewFIFOTIpGenerator(upstream TipGenerator, maxCacheSize int) *FIFOTipGenerator {
    24  	return &FIFOTipGenerator{
    25  		upstream:     upstream,
    26  		maxCacheSize: maxCacheSize,
    27  		fifoRing:     make([]types.Txi, maxCacheSize),
    28  	}
    29  }
    30  
    31  func (f *FIFOTipGenerator) validation() {
    32  	var k int
    33  	for i := 0; i < f.maxCacheSize; i++ {
    34  		if f.fifoRing[i] == nil {
    35  			if f.fifoRingPos > i {
    36  				f.fifoRingPos = i
    37  			}
    38  			break
    39  		}
    40  		//if the tx is became fatal tx ,remove it from tips
    41  		if !f.fifoRing[i].Valid() {
    42  			logrus.WithField("tx ", f.fifoRing[i]).Debug("found invalid tx")
    43  			if !f.fifoRingFull {
    44  				if f.fifoRingPos > 0 {
    45  					if f.fifoRingPos-1 == i {
    46  						f.fifoRing[i] = nil
    47  					} else if f.fifoRingPos-1 > i {
    48  						f.fifoRing[i] = f.fifoRing[f.fifoRingPos-1]
    49  					} else {
    50  						f.fifoRing[i] = nil
    51  						break
    52  					}
    53  					f.fifoRingPos--
    54  				}
    55  			} else {
    56  				f.fifoRing[i] = f.fifoRing[f.maxCacheSize-k-1]
    57  				f.fifoRing[f.maxCacheSize-k-1] = nil
    58  				i--
    59  				k++
    60  				f.fifoRingFull = false
    61  			}
    62  		}
    63  	}
    64  }
    65  
    66  func (f *FIFOTipGenerator) GetByNonce(addr common.Address, nonce uint64) types.Txi {
    67  	return f.upstream.GetByNonce(addr, nonce)
    68  }
    69  
    70  func (f *FIFOTipGenerator) IsBadSeq(seq *types.Sequencer) error {
    71  	return f.upstream.IsBadSeq(seq)
    72  }
    73  
    74  func (f *FIFOTipGenerator) GetRandomTips(n int) (v []types.Txi) {
    75  	f.mu.Lock()
    76  	defer f.mu.Unlock()
    77  	upstreamTips := f.upstream.GetRandomTips(n)
    78  	//checkValidation
    79  	f.validation()
    80  	// update fifoRing
    81  	for _, upstreamTip := range upstreamTips {
    82  		duplicated := false
    83  		for i := 0; i < f.maxCacheSize; i++ {
    84  			if f.fifoRing[i] != nil && f.fifoRing[i].GetHash() == upstreamTip.GetHash() {
    85  				// duplicate, ignore directly
    86  				duplicated = true
    87  				break
    88  			}
    89  		}
    90  		if !duplicated {
    91  			// advance ring and put it in the fifo ring
    92  			f.fifoRing[f.fifoRingPos] = upstreamTip
    93  			f.fifoRingPos++
    94  			// round
    95  			if f.fifoRingPos == f.maxCacheSize {
    96  				f.fifoRingPos = 0
    97  				f.fifoRingFull = true
    98  			}
    99  		}
   100  	}
   101  	// randomly pick n from fifo cache
   102  	randIndices := make(map[int]bool)
   103  	ringSize := f.fifoRingPos
   104  	if f.fifoRingFull {
   105  		ringSize = f.maxCacheSize
   106  	}
   107  	pickSize := n
   108  	if !f.fifoRingFull && f.fifoRingPos < n {
   109  		pickSize = f.fifoRingPos
   110  	}
   111  
   112  	for len(randIndices) != pickSize {
   113  		randIndices[rand.Intn(ringSize)] = true
   114  	}
   115  
   116  	// dump those txs
   117  	for k := range randIndices {
   118  		v = append(v, f.fifoRing[k])
   119  	}
   120  	return
   121  
   122  }