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 }