Skip to content

Commit

Permalink
txpool slotGauge uint64 underflow (#1907)
Browse files Browse the repository at this point in the history
  • Loading branch information
ohijiho committed Oct 2, 2023
1 parent 9e55557 commit 6544e22
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
19 changes: 19 additions & 0 deletions txpool/slot_gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ func (g *slotGauge) increase(slots uint64) {
metrics.SetGauge([]string{txPoolMetrics, "slots_used"}, float32(newHeight))
}

// increaseWithinLimit increases the height of the gauge by the specified slots amount only if the increased height is
// less than max. Returns true if the height is increased.
func (g *slotGauge) increaseWithinLimit(slots uint64) (updated bool) {
for {
old := g.read()
newHeight := old + slots

if newHeight > g.max {
return false
}

if atomic.CompareAndSwapUint64(&g.height, old, newHeight) {
metrics.SetGauge([]string{txPoolMetrics, "slots_used"}, float32(newHeight))

return true
}
}
}

// decrease decreases the height of the gauge by the specified slots amount.
func (g *slotGauge) decrease(slots uint64) {
newHeight := atomic.AddUint64(&g.height, ^(slots - 1))
Expand Down
30 changes: 21 additions & 9 deletions txpool/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,8 +787,6 @@ func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error {

// initialize account for this address once or retrieve existing one
account := p.getOrCreateAccount(tx.From)
// populate currently free slots
slotsFree := p.gauge.freeSlots()

account.promoted.lock(true)
account.enqueued.lock(true)
Expand Down Expand Up @@ -827,8 +825,6 @@ func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error {

return ErrReplacementUnderpriced
}

slotsFree += slotsRequired(oldTxWithSameNonce) // add old tx slots
} else {
if account.enqueued.length() == account.maxEnqueued && tx.Nonce != accountNonce {
return ErrMaxEnqueuedLimitReached
Expand All @@ -842,27 +838,43 @@ func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error {
}
}

// check for overflow
if slotsRequired(tx) > slotsFree {
return ErrTxPoolOverflow
slotsAllocated := slotsRequired(tx)

var slotsFreed uint64
if oldTxWithSameNonce != nil {
slotsFreed = slotsRequired(oldTxWithSameNonce)
}

var slotsIncreased uint64
if slotsAllocated > slotsFreed {
slotsIncreased = slotsAllocated - slotsFreed
if !p.gauge.increaseWithinLimit(slotsIncreased) {
return ErrTxPoolOverflow
}
}

// add to index
if ok := p.index.add(tx); !ok {
metrics.IncrCounter([]string{txPoolMetrics, "already_known_tx"}, 1)

if slotsIncreased > 0 {
p.gauge.decrease(slotsIncreased)
}

return ErrAlreadyKnown
}

if slotsFreed > slotsAllocated {
p.gauge.decrease(slotsFreed - slotsAllocated)
}

if oldTxWithSameNonce != nil {
p.index.remove(oldTxWithSameNonce)
p.gauge.decrease(slotsRequired(oldTxWithSameNonce))
} else {
metrics.SetGauge([]string{txPoolMetrics, "added_tx"}, 1)
}

account.enqueue(tx, oldTxWithSameNonce != nil) // add or replace tx into account
p.gauge.increase(slotsRequired(tx))

go p.invokePromotion(tx, tx.Nonce <= accountNonce) // don't signal promotion for higher nonce txs

Expand Down

0 comments on commit 6544e22

Please sign in to comment.