Skip to content

Commit

Permalink
Fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
Djadih committed Dec 17, 2024
1 parent a46f628 commit 1455a68
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 70 deletions.
64 changes: 37 additions & 27 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,20 @@ var defaultCacheConfig = &CacheConfig{
//
// StateProcessor implements Processor.
type StateProcessor struct {
config *params.ChainConfig // Chain configuration options
hc *HeaderChain // Canonical block chain
engine consensus.Engine // Consensus engine used for block rewards
logsFeed event.Feed
rmLogsFeed event.Feed
cacheConfig *CacheConfig // CacheConfig for StateProcessor
stateCache state.Database // State database to reuse between imports (contains state cache)
etxCache state.Database // ETX database to reuse between imports (contains ETX cache)
receiptsCache *lru.Cache[common.Hash, types.Receipts] // Cache for the most recent receipts per block
txLookupCache *lru.Cache[common.Hash, rawdb.LegacyTxLookupEntry]
validator Validator // Block and state validator interface
prefetcher Prefetcher
vmConfig vm.Config
minFee, maxFee, avgFee *big.Int
config *params.ChainConfig // Chain configuration options
hc *HeaderChain // Canonical block chain
engine consensus.Engine // Consensus engine used for block rewards
logsFeed event.Feed
rmLogsFeed event.Feed
cacheConfig *CacheConfig // CacheConfig for StateProcessor
stateCache state.Database // State database to reuse between imports (contains state cache)
etxCache state.Database // ETX database to reuse between imports (contains ETX cache)
receiptsCache *lru.Cache[common.Hash, types.Receipts] // Cache for the most recent receipts per block
txLookupCache *lru.Cache[common.Hash, rawdb.LegacyTxLookupEntry]
validator Validator // Block and state validator interface
prefetcher Prefetcher
vmConfig vm.Config
minFee, maxFee, avgFee, numElements *big.Int

scope event.SubscriptionScope
wg sync.WaitGroup // chain processing wait group for shutting down
Expand Down Expand Up @@ -774,7 +774,7 @@ func (p *StateProcessor) Process(block *types.WorkObject, batch ethdb.Batch) (ty
}
time5 := common.PrettyDuration(time.Since(start))

calcRollingFeeInfo(p.minFee, p.maxFee, p.avgFee, blockMinFee, blockMaxFee, blockAvgFee, numTxsProcessed)
calcRollingFeeInfo(p.minFee, p.maxFee, p.avgFee, p.numElements, blockMinFee, blockMaxFee, blockAvgFee, numTxsProcessed)

p.logger.WithFields(log.Fields{
"signing time": common.PrettyDuration(timeSign),
Expand Down Expand Up @@ -1876,16 +1876,16 @@ func (p *StateProcessor) StateAtTransaction(block *types.WorkObject, txIndex int
}

func calcQiTxStats(blockMinFee, blockMaxFee, blockAvgFee, qiTxFee, numTxsProcessed *big.Int) (newBlockMinFee, newBlockMaxFee, newBlockAvgFee *big.Int) {
numTxsProcessed = numTxsProcessed.Add(numTxsProcessed, common.Big1)
val := numTxsProcessed.Cmp(common.Big0)

if val == 1 {
if numTxsProcessed.Cmp(common.Big0) == 0 {
numTxsProcessed.Add(numTxsProcessed, common.Big1)
blockMinFee = new(big.Int).Set(qiTxFee)
blockMaxFee = new(big.Int).Set(qiTxFee)
blockAvgFee = new(big.Int).Set(qiTxFee)
return blockMinFee, blockMaxFee, blockAvgFee
}

numTxsProcessed = numTxsProcessed.Add(numTxsProcessed, common.Big1)
blockMinFee = bigMath.BigMin(qiTxFee, blockMinFee)
blockMaxFee = bigMath.BigMax(qiTxFee, blockMaxFee)
intermediateAvg := new(big.Int).Add(blockAvgFee, qiTxFee)
Expand All @@ -1894,34 +1894,44 @@ func calcQiTxStats(blockMinFee, blockMaxFee, blockAvgFee, qiTxFee, numTxsProcess
return blockMinFee, blockMaxFee, blockAvgFee
}

func calcRollingFeeInfo(rollingMinFee, rollingMaxFee, rollingAvgFee, blockMinFee, blockMaxFee, blockAvgFee, numTxsProcessed *big.Int) (min, max, avg *big.Int) {
func calcRollingFeeInfo(rollingMinFee, rollingMaxFee, rollingAvgFee, rollingNumElements, blockMinFee, blockMaxFee, blockAvgFee, numTxsProcessed *big.Int) (min, max, avg *big.Int) {
decay := func(fee *big.Int) {
fee = fee.Mul(fee, big.NewInt(99))
fee.Set(fee.Div(fee, big.NewInt(100)))
fee.Mul(fee, big.NewInt(99))
fee.Div(fee, big.NewInt(100))
}

// Implement peak/envelope filter
if numTxsProcessed.Cmp(common.Big0) == 0 {
// Block values will be nil, so don't compare or update.
return rollingMinFee, rollingMaxFee, rollingAvgFee
}
if rollingMinFee == nil || blockMinFee.Cmp(rollingMinFee) < 0 {
// If the new minimum is less than the old minimum, overwrite it.
rollingMinFee = blockMinFee
rollingMinFee = new(big.Int).Set(blockMinFee)
} else {
// If not, decay the old minimum by 1%.
decay(rollingMinFee)
}

if rollingMaxFee == nil || blockMaxFee.Cmp(rollingMaxFee) > 0 {
rollingMaxFee = blockMaxFee
rollingMaxFee = new(big.Int).Set(blockMaxFee)
} else {
decay(rollingMaxFee)
}

// Implement running average
if rollingAvgFee == nil {
rollingAvgFee = common.Big1
rollingAvgFee = big.NewInt(1)
rollingNumElements = big.NewInt(0)
}

if numTxsProcessed.Cmp(common.Big0) > 0 {
intermediateVal := new(big.Int).Mul(rollingNumElements, rollingAvgFee)
intermediateVal = intermediateVal.Add(intermediateVal, blockAvgFee)

rollingAvgFee = intermediateVal.Div(intermediateVal, numTxsProcessed)
rollingNumElements.Add(rollingNumElements, common.Big1)
}
intermediateVal := new(big.Int).Mul(new(big.Int).Sub(numTxsProcessed, common.Big1), rollingAvgFee)
intermediateVal = intermediateVal.Add(intermediateVal, blockAvgFee)
rollingAvgFee = intermediateVal.Div(intermediateVal, numTxsProcessed)

return rollingMinFee, rollingMaxFee, rollingAvgFee
}
Expand Down
110 changes: 67 additions & 43 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,68 +5,92 @@ import (
"math/rand"
"testing"

"github.com/dominant-strategies/go-quai/common"
"github.com/stretchr/testify/require"
)

func generateRandomNumbers(min, max, count int) (simpleNums []int, bigNums []*big.Int) {
simpleNums = make([]int, count)
bigNums = make([]*big.Int, count)
func generateRandomBlockFees(min, max, numBlocks, maxNumTxs int) (simpleBlockFees [][]int, bigBlockFees [][]*big.Int) {
// Generate the number of txs in this block first.
simpleBlockFees = make([][]int, numBlocks)
bigBlockFees = make([][]*big.Int, numBlocks)
for blockNum := 0; blockNum < numBlocks; blockNum++ {
txLen := rand.Intn(maxNumTxs)

for i := 0; i < count; i++ {
randNum := rand.Intn(max-min+1) + min
simpleNums[i] = randNum
bigNums[i] = big.NewInt(int64(randNum))
simpleBlockFees[blockNum] = make([]int, txLen)
bigBlockFees[blockNum] = make([]*big.Int, txLen)

for i := 0; i < txLen; i++ {
randNum := rand.Intn(max-min+1) + min
simpleBlockFees[blockNum][i] = randNum
bigBlockFees[blockNum][i] = big.NewInt(int64(randNum))
}
}

return simpleNums, bigNums
return simpleBlockFees, bigBlockFees
}

func TestSingleBlockTxStats(t *testing.T) {
const testLength = 1000
simpleFees, bigFees := generateRandomNumbers(1000, 1000000000, testLength)
func TestMultiBlockTxStats(t *testing.T) {
simpleBlockFees, bigBlockFees := generateRandomBlockFees(1000, 10000000000, 1, 100)

numTxsProcessed := 0
var expectedMin int
var expectedMax int
var sum int
for _, fee := range simpleFees {
if numTxsProcessed == 0 {
expectedMin = fee
expectedMax = fee
sum = 0
} else {
if fee < expectedMin {
expectedMin = fee
var expectedRollingMin, expectedRollingMax, expectedRollingAvg int
for blockNum, blockFees := range simpleBlockFees {
var blockMin, blockMax, sum int
for txCount, fee := range blockFees {
if txCount == 0 {
blockMin = fee
blockMax = fee
sum = 0
} else {
expectedMin = expectedMin * 99 / 100
if fee < blockMin {
blockMin = fee
}

if fee > blockMax {
blockMax = fee
}
}
sum += fee
}

if fee > expectedMax {
expectedMax = fee
if blockNum == 0 {
expectedRollingMin = blockMin
expectedRollingMax = blockMax
if len(blockFees) != 0 {
expectedRollingAvg = sum / len(blockFees)
}
} else {
if blockMin < expectedRollingMin {
expectedRollingMin = blockMin
} else {
expectedMax = expectedMax * 99 / 100
expectedRollingMin = expectedRollingMin * 99 / 100
}

if blockMax > expectedRollingMax {
expectedRollingMax = blockMax
} else {
expectedRollingMax = expectedRollingMax * 99 / 100
}
if len(blockFees) != 0 {
// Calculate a running average
expectedRollingAvg = (len(blockFees)*expectedRollingAvg + sum) / len(blockFees)
}
}

sum += fee
numTxsProcessed += 1
}
expectedAvg := sum / numTxsProcessed

bigTxsProcessed := new(big.Int).Set(common.Big0)
var blockMin, blockMax, blockAvg *big.Int
var actualMin *big.Int
var actualMax *big.Int
var actualAvg *big.Int
for _, fee := range bigFees {
blockMin, blockMax, blockAvg := calcQiTxStats(blockMin, blockMax, blockAvg, fee, bigTxsProcessed)
actualMin, actualMax, actualAvg = calcRollingFeeInfo(actualMin, actualMax, actualAvg, blockMin, blockMax, blockAvg, bigTxsProcessed)
var actualRollingMin, actualRollingMax, rollingAvg, rollingNumElements *big.Int
for _, blockFees := range bigBlockFees {
bigTxsProcessed := big.NewInt(0)
for _, fee := range blockFees {
blockMin, blockMax, blockAvg = calcQiTxStats(blockMin, blockMax, blockAvg, fee, bigTxsProcessed)
}

actualRollingMin, actualRollingMax, rollingAvg = calcRollingFeeInfo(actualRollingMin, actualRollingMax, rollingAvg, rollingNumElements, blockMin, blockMax, blockAvg, bigTxsProcessed)
}

require.Equal(t, uint64(expectedMin), actualMin.Uint64(), "Expected min not equal")
require.Equal(t, uint64(expectedMax), actualMax.Uint64(), "Expected max not equal")
// Account for maxmium error of 1 unit of gas due to float math for average
require.InEpsilon(t, uint64(expectedAvg), actualAvg.Uint64(), float64(1), "Expected average not equal")
if expectedRollingMin != 0 || expectedRollingMax != 0 || expectedRollingAvg != 0 {
// If any one of these values is non-zero, then there were fees, so compare.
require.Equal(t, uint64(expectedRollingMin), actualRollingMin.Uint64(), "Expected min not equal")
require.Equal(t, uint64(expectedRollingMax), actualRollingMax.Uint64(), "Expected max not equal")
require.Equal(t, uint64(expectedRollingAvg), rollingAvg.Uint64(), "Expected average not equal")
}
}

0 comments on commit 1455a68

Please sign in to comment.