Skip to content

Conversation

@swift1337
Copy link
Member

@swift1337 swift1337 commented Dec 8, 2025

Description

  • Unify mempool.Select and mempool.SelectBy calls
  • Share re-check function across the whole reorg loop
  • Implement "max timeout" for total recheck tx for the reog loop in evm mempool
  • Add basic test case

Timeout logic

LegacyPool.WaitForReorgHeight now also has a timeout parameter (hard-coded to 300ms in mempool.Select)

func (pool *LegacyPool) WaitForReorgHeight(ctx context.Context, height int64, timeout time.Duration)

Inside this function, we call reorgContext that either sets ctx.timeout = timeout or lowers existing timeout by 100ms ~ ctx.timeout -= 100ms.

After ctx is timed out, is calls an atomic bool reorgCancelRequested that is checked for every account during promoteExecutables or demoteUnexecutables

Note: due to how EVM mempool works, it's challenging to properly propagate ctx across all goroutines as the mempool follows the actor model with lots of channels. This leads to a semi-forced context timeout, where we might still have some operations running after the timeout (ie, hard timeout if not guaranteed)

Closes: STACK-1927


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • tackled an existing issue or discussed with a team member
  • left instructions on how to review the changes
  • targeted the main branch

@linear
Copy link

linear bot commented Dec 8, 2025

@swift1337 swift1337 changed the base branch from main to feat/krakatoa December 8, 2025 18:38
@swift1337 swift1337 self-assigned this Dec 8, 2025
@swift1337 swift1337 changed the title feat(mempool): add timeout for recheck duration feat(mempool): add timeout for reorg Dec 8, 2025
@swift1337 swift1337 marked this pull request as ready for review December 8, 2025 19:02
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
totalcost *uint256.Int // Total cost of all transactions in the list

lastCheckedHeight int64 // the height at which the list was last checked
Copy link
Member Author

@swift1337 swift1337 Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No mutex required, as this is an internal structure and its access is already under a lock

// reset the cancel requested flag
pool.reorgCancelRequested.Store(false)

defer func(start time.Time) { reorgDurationTimer.UpdateSince(start) }(time.Now())

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
} else {
// set the last checked height for the list
// this is used to return only checked accounts in Pending method
list.setLastCheckedHeight(height)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattac21 @Eric-Warehime , so this is the place where we'd set the last checked height.

The drawback of this approach: now, to be included in pool.Pending() → mempool.SelectBy() results, tx should go through demoteUnexecutables, which is not the case for same-block-inclusion (imagine an addition to an empty mempool) eg:

[time_0: block(1), t1: add_tx(), t2: propose_block(2)]

Do you see any easy ways to handle this case?

@swift1337
Copy link
Member Author

Closing, might open a re-implementation later if needed.

@swift1337 swift1337 closed this Dec 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants