github.com/koko1123/flow-go-1@v0.29.6/module/builder/collection/rate_limiter.go (about)

     1  package collection
     2  
     3  import (
     4  	"math"
     5  
     6  	"github.com/koko1123/flow-go-1/model/flow"
     7  )
     8  
     9  // rateLimiter implements payer-based rate limiting. See Config for details.
    10  type rateLimiter struct {
    11  
    12  	// maximum rate of transactions/payer/collection (from Config)
    13  	rate float64
    14  	// set of unlimited payer address (from Config)
    15  	unlimited map[flow.Address]struct{}
    16  	// height of the collection we are building
    17  	height uint64
    18  
    19  	// for each payer, height of latest collection in which a transaction for
    20  	// which they were payer was included
    21  	latestCollectionHeight map[flow.Address]uint64
    22  	// number of transactions included in the currently built block per payer
    23  	txIncludedCount map[flow.Address]uint
    24  }
    25  
    26  func newRateLimiter(conf Config, height uint64) *rateLimiter {
    27  	limiter := &rateLimiter{
    28  		rate:                   conf.MaxPayerTransactionRate,
    29  		unlimited:              conf.UnlimitedPayers,
    30  		height:                 height,
    31  		latestCollectionHeight: make(map[flow.Address]uint64),
    32  		txIncludedCount:        make(map[flow.Address]uint),
    33  	}
    34  	return limiter
    35  }
    36  
    37  // note the existence and height of a transaction in an ancestor collection.
    38  func (limiter *rateLimiter) addAncestor(height uint64, tx *flow.TransactionBody) {
    39  
    40  	// skip tracking payers if we aren't rate-limiting or are configured
    41  	// to allow multiple transactions per payer per collection
    42  	if limiter.rate >= 1 || limiter.rate <= 0 {
    43  		return
    44  	}
    45  
    46  	latest := limiter.latestCollectionHeight[tx.Payer]
    47  	if height >= latest {
    48  		limiter.latestCollectionHeight[tx.Payer] = height
    49  	}
    50  }
    51  
    52  // note that we have added a transaction to the collection under construction.
    53  func (limiter *rateLimiter) transactionIncluded(tx *flow.TransactionBody) {
    54  	limiter.txIncludedCount[tx.Payer]++
    55  }
    56  
    57  // applies the rate limiting rules, returning whether the transaction should be
    58  // omitted from the collection under construction.
    59  func (limiter *rateLimiter) shouldRateLimit(tx *flow.TransactionBody) bool {
    60  
    61  	payer := tx.Payer
    62  
    63  	// skip rate limiting if it is turned off or the payer is unlimited
    64  	_, isUnlimited := limiter.unlimited[payer]
    65  	if limiter.rate == 0 || isUnlimited {
    66  		return false
    67  	}
    68  
    69  	// if rate >=1, we only consider the current collection and rate limit once
    70  	// the number of transactions for the payer exceeds rate
    71  	if limiter.rate >= 1 {
    72  		if limiter.txIncludedCount[payer] >= uint(math.Floor(limiter.rate)) {
    73  			return true
    74  		}
    75  	}
    76  
    77  	// if rate < 1, we need to look back to see when a transaction by this payer
    78  	// was most recently included - we rate limit if the # of collections since
    79  	// the payer's last transaction is less than ceil(1/rate)
    80  	if limiter.rate < 1 {
    81  
    82  		// rate limit if we've already include a transaction for this payer, we allow
    83  		// AT MOST one transaction per payer in a given collection
    84  		if limiter.txIncludedCount[payer] > 0 {
    85  			return true
    86  		}
    87  
    88  		// otherwise, check whether sufficiently many empty collection
    89  		// have been built since the last transaction from the payer
    90  
    91  		latestHeight, hasLatest := limiter.latestCollectionHeight[payer]
    92  		// if there is no recent transaction, don't rate limit
    93  		if !hasLatest {
    94  			return false
    95  		}
    96  
    97  		if limiter.height-latestHeight < uint64(math.Ceil(1/limiter.rate)) {
    98  			return true
    99  		}
   100  	}
   101  
   102  	return false
   103  }