diff --git a/lib/pos_fee_estimator.go b/lib/pos_fee_estimator.go index e95aa2e55..f0503e6dc 100644 --- a/lib/pos_fee_estimator.go +++ b/lib/pos_fee_estimator.go @@ -687,7 +687,7 @@ func (posFeeEstimator *PoSFeeEstimator) estimateFeeRateNanosPerKBGivenTransactio return globalMinFeeRate } - bucketMinFee, bucketMaxFee := getPriorityFeeBucketFromTxns( + bucketMinFee, bucketMaxFee := txnRegister.getPriorityFeeBucketFromTxns( txns, priorityPercentileBasisPoints, txnRegister.minimumNetworkFeeNanosPerKB, @@ -724,7 +724,7 @@ func (posFeeEstimator *PoSFeeEstimator) estimateFeeRateNanosPerKBGivenTransactio // The feeTimeOrderedTxns have the highest fees first and the lowest fees last, so we need to compute // the percentile position of the priorityPercentileBasisPoints param and then compute the fee bucket // range based on the fee rate per KB of the transaction at that position. -func getPriorityFeeBucketFromTxns( +func (tr *TransactionRegister) getPriorityFeeBucketFromTxns( feeTimeOrderedTxns []*MempoolTx, priorityPercentileBasisPoints uint64, minimumNetworkFeeNanosPerKB *big.Float, @@ -739,7 +739,7 @@ func getPriorityFeeBucketFromTxns( percentilePosition = uint64(len(feeTimeOrderedTxns)) - 1 } - bucketMin, bucketMax := computeFeeTimeBucketRangeFromFeeNanosPerKB( + bucketMin, bucketMax := tr.computeFeeTimeBucketRangeFromFeeNanosPerKB( feeTimeOrderedTxns[percentilePosition].FeePerKB, minimumNetworkFeeNanosPerKB, feeBucketGrowthRateBasisPoints, diff --git a/lib/pos_fee_estimator_test.go b/lib/pos_fee_estimator_test.go index 32f805af6..5de0dcc30 100644 --- a/lib/pos_fee_estimator_test.go +++ b/lib/pos_fee_estimator_test.go @@ -31,12 +31,13 @@ func TestFeeEstimator(t *testing.T) { require.NoError(t, mempool.Start()) require.True(t, mempool.IsRunning()) defer mempool.Stop() - minFeeBucketMin, minFeeBucketMax := computeFeeTimeBucketRangeFromFeeNanosPerKB( + tr := mempool.txnRegister + minFeeBucketMin, minFeeBucketMax := tr.computeFeeTimeBucketRangeFromFeeNanosPerKB( globalParams.MinimumNetworkFeeNanosPerKB, big.NewFloat(float64(globalParams.MinimumNetworkFeeNanosPerKB)), mempool.txnRegister.feeBucketGrowthRateBasisPoints) // set the feeMin to the third fee bucket. - secondMinFeeBucketMin, secondMinFeeBucketMax := computeFeeTimeBucketRangeFromFeeNanosPerKB( + secondMinFeeBucketMin, secondMinFeeBucketMax := tr.computeFeeTimeBucketRangeFromFeeNanosPerKB( minFeeBucketMax+1, big.NewFloat(float64(globalParams.MinimumNetworkFeeNanosPerKB)), mempool.txnRegister.feeBucketGrowthRateBasisPoints) @@ -119,7 +120,7 @@ func TestFeeEstimator(t *testing.T) { err = posFeeEstimator.AddBlock(dummyBlock) require.NoError(t, err) // Compute the next fee bucket min - _, feeBucketMax := computeFeeTimeBucketRangeFromFeeNanosPerKB( + _, feeBucketMax := tr.computeFeeTimeBucketRangeFromFeeNanosPerKB( feeMin, big.NewFloat(float64(globalParams.MinimumNetworkFeeNanosPerKB)), mempool.txnRegister.feeBucketGrowthRateBasisPoints) diff --git a/lib/pos_transaction_register.go b/lib/pos_transaction_register.go index b0b3b59ea..2c878b961 100644 --- a/lib/pos_transaction_register.go +++ b/lib/pos_transaction_register.go @@ -146,7 +146,7 @@ func (tr *TransactionRegister) addTransactionNoLock(txn *MempoolTx) error { } // Determine the min fee of the bucket based on the transaction's fee rate. - bucketMinFeeNanosPerKb, bucketMaxFeeNanosPerKB := computeFeeTimeBucketRangeFromFeeNanosPerKB(txn.FeePerKB, + bucketMinFeeNanosPerKb, bucketMaxFeeNanosPerKB := tr.computeFeeTimeBucketRangeFromFeeNanosPerKB(txn.FeePerKB, tr.minimumNetworkFeeNanosPerKB, tr.feeBucketGrowthRateBasisPoints) // Lookup the bucket in the map. bucket, bucketExists := tr.feeTimeBucketsByMinFeeMap[bucketMinFeeNanosPerKb] @@ -197,7 +197,7 @@ func (tr *TransactionRegister) removeTransactionNoLock(txn *MempoolTx) error { } // Determine the min fee of the bucket based on the transaction's fee rate. - bucketMinFeeNanosPerKb, _ := computeFeeTimeBucketRangeFromFeeNanosPerKB(txn.FeePerKB, + bucketMinFeeNanosPerKb, _ := tr.computeFeeTimeBucketRangeFromFeeNanosPerKB(txn.FeePerKB, tr.minimumNetworkFeeNanosPerKB, tr.feeBucketGrowthRateBasisPoints) // Remove the transaction from the bucket. if bucket, exists := tr.feeTimeBucketsByMinFeeMap[bucketMinFeeNanosPerKb]; exists { @@ -645,9 +645,23 @@ func ComputeMultiplierFromGrowthRateBasisPoints(growthRateBasisPoints *big.Float // computeFeeTimeBucketRangeFromFeeNanosPerKB takes a fee rate, minimumNetworkFeeNanosPerKB, and feeBucketMultiplier, // and returns the [minFeeNanosPerKB, maxFeeNanosPerKB] of the fee range. -func computeFeeTimeBucketRangeFromFeeNanosPerKB(feeNanosPerKB uint64, minimumNetworkFeeNanosPerKB *big.Float, +func (tr *TransactionRegister) computeFeeTimeBucketRangeFromFeeNanosPerKB(feeNanosPerKB uint64, minimumNetworkFeeNanosPerKB *big.Float, feeBucketGrowthRateBasisPoints *big.Float) (uint64, uint64) { + idx, feeBucketInterface := tr.feeTimeBucketSet.Find(func(idx int, value interface{}) bool { + bucket, ok := value.(*FeeTimeBucket) + if !ok { + glog.Error(CLog(Red, "computeFeeTimeBucketRangeFromFeeNanosPerKB: Invalid type in feeTimeBucketSet. This is BAD NEWS, we should never get here.")) + return false + } + // If the bucket's min fee is greater than the feeNanosPerKB, then we can stop searching. + return bucket.minFeeNanosPerKB < feeNanosPerKB && bucket.maxFeeNanosPerKB > feeNanosPerKB + }) + if idx != -1 && feeBucketInterface != nil { + feeBucket := feeBucketInterface.(*FeeTimeBucket) + return feeBucket.minFeeNanosPerKB, feeBucket.maxFeeNanosPerKB + } + feeBucketMultiplier := ComputeMultiplierFromGrowthRateBasisPoints(feeBucketGrowthRateBasisPoints) bucketExponent := computeFeeTimeBucketExponentFromFeeNanosPerKB(feeNanosPerKB, minimumNetworkFeeNanosPerKB, feeBucketMultiplier) return computeFeeTimeBucketRangeFromExponent(bucketExponent, minimumNetworkFeeNanosPerKB, feeBucketMultiplier) diff --git a/lib/pos_transaction_register_test.go b/lib/pos_transaction_register_test.go index e1f46b033..fd3904789 100644 --- a/lib/pos_transaction_register_test.go +++ b/lib/pos_transaction_register_test.go @@ -568,6 +568,26 @@ func TestComputeFeeBucketWithFee(t *testing.T) { } } +func TestComputeFeeBucketFromRegisterWithFee(t *testing.T) { + globalParams := _testGetDefaultGlobalParams() + globalParams.MinimumNetworkFeeNanosPerKB = 100 + globalParams.FeeBucketGrowthRateBasisPoints = 1000 + baseRate, _ := globalParams.ComputeFeeTimeBucketMinimumFeeAndMultiplier() + + feeBucketGrowthRate := NewFloat().SetUint64(globalParams.FeeBucketGrowthRateBasisPoints) + tr := NewTransactionRegister() + + for ii := uint64(100); ii < 100000; ii++ { + minFee, maxFee := tr.computeFeeTimeBucketRangeFromFeeNanosPerKB(ii, baseRate, feeBucketGrowthRate) + require.LessOrEqual(t, minFee, ii) + require.GreaterOrEqual(t, maxFee, ii) + tr.AddTransaction(&MempoolTx{ + Hash: NewBlockHash(RandomBytes(32)), + FeePerKB: ii, + }) + } +} + func TestHasGlobalParamChange(t *testing.T) { // Create the transaction register. globalParams := _testGetDefaultGlobalParams()