Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/txpool/legacypool: add overflowpool for txs #2660

Merged
merged 59 commits into from
Oct 17, 2024
Merged

core/txpool/legacypool: add overflowpool for txs #2660

merged 59 commits into from
Oct 17, 2024

Conversation

emailtovamos
Copy link
Contributor

@emailtovamos emailtovamos commented Aug 20, 2024

Description

This PR incorporates an Overflow Pool which stores transactions in memory for such cases and time to time transfers them to the Main Pool when the Main Pool isn't full. It is not propagated or announced while it is in the Overflow Pool. But when it is finally transferred to the Main Pool, at that point it is considered as a transaction that just arrived at the Main Pool and is subject to the usual checks and propagation logic.
Overflow Pool's size can be chosen by a node depending on its hardware capacity.

Rationale

During high traffic, transactions are lost as the current legacy pool (Main Pool) has limits on its capacity and propagating them during high traffic also costs network congestions. So this is an attempt to solve 'tx lost' and get better UX.

Details

a. Main Pool

There is no new structure for Main Pool, actually it is just the current Transaction Pool (Legacy Pool). When this Pool isn't full, the received new transactions will be broadcasted to all the relevant peers, just the same as the current behaviour.

b. Overflow Pool: the local buffer (LRU or Heap)

When the Main Pool is overflowed during high traffic, then it would put lots of stress on the network if we keep broadcasting new transactions. So we put any new transaction into the Overflow Pool and don’t broadcast or announce.
The size of the Overflow Pool could be very large, in order to hold a large traffic volume, like 500K. Suppose the average transaction size is 500B, it will take around 256MB memory, which is acceptable.

How to flush transactions from Overflow Pool to Main Pool:

  • To satisfy the first-come-first-serve policy, when new transactions arrive & the Main Pool is full, we will push it to the Overflow Pool if it is not full.
  • This transaction that is part of Overflow Pool doesn’t get announced or propagated. Its knowledge and existence is completely local to the particular node.
  • We regularly try to pop new transactions from the Overflow Pool to add to the Main Pool when Main Pool has space. This can either be time-based (e.g. once every 10 seconds) or block based (once every new block or every 2 blocks)
  • When a transaction moves from Overflow Pool to Main Pool, it is treated the same way when a transaction directly arrives in the Main Pool.
  • When a new block is imported, we can try to flush the Overflow Pool to Main Pool.

Copy link

@WTDuck2255 WTDuck2255 left a comment

Choose a reason for hiding this comment

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

Thx so much

@emailtovamos emailtovamos marked this pull request as ready for review September 2, 2024 06:18
core/events.go Outdated Show resolved Hide resolved
@emailtovamos
Copy link
Contributor Author

no replacement logic in pool3, so if txs put into pool3, the replacement may fail, does it matter?

@buddh0 if by replacement transaction you mean transaction with same nonce but different/higher gas price then if the first transaction is already in pool3 (which we are calling Overflow Pool now) then the Main Pool is unaware of it and might treat the replacement transaction as the only one and might include in a block. In that case when the original transaction finally gets from Overflow Pool to Main Pool, it will be discarded due to ErrNonceTooLow. So it shouldn't matter.

@buddh0
Copy link
Collaborator

buddh0 commented Oct 15, 2024

no replacement logic in pool3, so if txs put into pool3, the replacement may fail, does it matter?

@buddh0 if by replacement transaction you mean transaction with same nonce but different/higher gas price then if the first transaction is already in pool3 (which we are calling Overflow Pool now) then the Main Pool is unaware of it and might treat the replacement transaction as the only one and might include in a block. In that case when the original transaction finally gets from Overflow Pool to Main Pool, it will be discarded due to ErrNonceTooLow. So it shouldn't matter.

ok

@buddh0
Copy link
Collaborator

buddh0 commented Oct 16, 2024

  1. change the PR title to follow default format, such as
    New higher capacity Txpool
    -->
    core/txpool/legacypool: add overflowpool for txs
  2. update the PR Description
    this PR is not a trival PR, please introduces the key points, such as movitation and the design
    It will be useful when people check related code in the future

@emailtovamos emailtovamos changed the title New higher capacity Txpool core/txpool/legacypool: add overflowpool for txs Oct 16, 2024
}
item := old[n-1]
old[n-1] = nil // avoid memory leak
*h = old[0 : n-1]
Copy link
Collaborator

@zzzckck zzzckck Oct 17, 2024

Choose a reason for hiding this comment

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

It will pop the latest tx, right? but IMO, we wanna to pop the oldest tx.
So it is actually a Stack, not a Heap.
Should we change it to:

	item := old[0]
	old[0] = nil // avoid memory leak
	*h = old[1 : n]

But, it will update the all item's index...

Copy link
Contributor

@NathanBSC NathanBSC Oct 17, 2024

Choose a reason for hiding this comment

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

It will pop the latest tx, right? but IMO, we wanna to pop the oldest tx. So it is actually a Stack, not a Heap. Should we change it to:

	item := old[0]
	old[0] = nil // avoid memory leak
	*h = old[1 : n]

But, it will update the all item's index...

heap.Pop will pop the oldest one:
heap.Pop will put the oldest item at the end firstly, compare by the func txHeap.Less
then call txHeap.Pop

Copy link
Collaborator

Choose a reason for hiding this comment

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

ok, got it. but I wonder if it would cost lots of CPU resource for each Pop operation, as it needs to do sorting first

@zzzckck zzzckck merged commit 675449a into develop Oct 17, 2024
6 of 7 checks passed
@zzzckck
Copy link
Collaborator

zzzckck commented Oct 21, 2024

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.

8 participants