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

Task/improve evm tracer performance #3521

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

vitaliy-io
Copy link
Collaborator

Fix N^2 behavior of block tracers

@vitaliy-io vitaliy-io marked this pull request as ready for review January 15, 2025 18:20
depth int
interrupt atomic.Bool // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
txToStack map[common.Hash][]CallFrame
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't it possible to avoid changing this struct and also prestateTracer?
I'm asking because these files are almost a 1 to 1 copy of the code in go-ethereum, and so they are very easy to update whenever there are changes upstream. These changes will make it more difficult to keep the code updated.

Also, I see that there is some duplicated logic in the call and prestate tracers, surrounding the map[common.Hash], currentTxHash, traceBlock and fakeTxs, so maybe there is a different solution? How does go-ethereum solve this problem?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Geth does not have N^2 problem because their VM layer is different, the bottom line is that geth's VM allows transactions to be executed individually (meaning that each tx has it's own tracer) but reusing the same state (thus allowing txs to see the changes made by previous txs in the same block). Basically they loop through the block transactions and for each one they run VM with tracing.
Out VM however accepts a list of transactions to run and only then it gets the state to base on. I'm sure that we could change our VM to work like geth, but for me it's hard to understand how difficult that would be (maybe it's easy).
That's why I decided to alter the tracers itself. But I agree that it would make it difficult to copy fixes from geth

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, I see. Anyway, do you think it's possible to fix or at least decrease the amount of duplicated code?

Maybe moving that logic to our own Tracer struct:

type Tracer struct {
    txTracers  map[common.Hash]*tracers.Tracer
    currentTx  common.Hash
	traceBlock bool
	fakeTxs    []*types.Transaction
}

fakeTxs := make([]*types.Transaction, 0, len(blockTxs))
for _, tx := range blockTxs {
if evmutil.IsFakeTransaction(tx) {
fakeTxs = append(fakeTxs, tx)
Copy link
Collaborator

Choose a reason for hiding this comment

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

So fakeTxs contains the list of fake txs in the block. But it doesn't record their tx index. I don't remember, is it possible that a block contains regular and fake txs interleaved? Shouldn't the trace ouput respect the transaction indices?

block:
  tx #0: regular tx
  tx #1: fake tx
  tx #2: regular tx
  tx #3: fake tx

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.

2 participants