From 501f6f70276d38e60fa2a1696d570a28b33dcb7e Mon Sep 17 00:00:00 2001 From: Lazy Nina Date: Tue, 15 Jul 2025 14:13:28 -0400 Subject: [PATCH 1/3] use fee time bucket set to find bucket instead of using math to compute --- lib/pos_fee_estimator.go | 6 +++--- lib/pos_fee_estimator_test.go | 7 ++++--- lib/pos_transaction_register.go | 20 +++++++++++++++++--- 3 files changed, 24 insertions(+), 9 deletions(-) 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) From c3cdee423d91f3c3c5047e5be6bd8917d652e3d5 Mon Sep 17 00:00:00 2001 From: Lazy Nina Date: Tue, 15 Jul 2025 14:40:59 -0400 Subject: [PATCH 2/3] add test for fee bucket caching --- lib/pos_transaction_register_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/pos_transaction_register_test.go b/lib/pos_transaction_register_test.go index e1f46b033..538bbd327 100644 --- a/lib/pos_transaction_register_test.go +++ b/lib/pos_transaction_register_test.go @@ -381,6 +381,8 @@ func _testGetDefaultGlobalParams() *GlobalParamsEntry { globalParams.SoftMaxBlockSizeBytesPoS = 1000 + globalParams.MinimumNetworkFeeNanosPerKB = 100 + globalParams.FeeBucketGrowthRateBasisPoints = 1000 return &globalParams } @@ -568,6 +570,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() From eb7d441bd766f92df2ea9e33895eb7f3e5c9ab93 Mon Sep 17 00:00:00 2001 From: Lazy Nina Date: Tue, 15 Jul 2025 14:43:12 -0400 Subject: [PATCH 3/3] revert change to test global params --- lib/pos_transaction_register_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pos_transaction_register_test.go b/lib/pos_transaction_register_test.go index 538bbd327..fd3904789 100644 --- a/lib/pos_transaction_register_test.go +++ b/lib/pos_transaction_register_test.go @@ -381,8 +381,6 @@ func _testGetDefaultGlobalParams() *GlobalParamsEntry { globalParams.SoftMaxBlockSizeBytesPoS = 1000 - globalParams.MinimumNetworkFeeNanosPerKB = 100 - globalParams.FeeBucketGrowthRateBasisPoints = 1000 return &globalParams }