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

debug_traceTransaction endpoint implementation #1515

Closed
wants to merge 21 commits into from
Closed

debug_traceTransaction endpoint implementation #1515

wants to merge 21 commits into from

Conversation

rayrapetyan
Copy link
Contributor

@rayrapetyan rayrapetyan commented Nov 24, 2018

What was wrong?

There was no way to trace transactions in py-evm

How was it fixed?

A basic tracing support was added.

Description

New functionality is based on a go-ethereum's debug_traceTransaction logic (https://github.com/ethereum/go-ethereum/wiki/Tracing:-Introduction). Only basic parts were ported so far (e.g. no JS tracers support). Closes issue #62.

List of open questions to discuss:

  • Should we drop output of computation.logger.trace as it mostly duplicates a new tracer's output?
  • Find a better way to turn tracer on\off (right now it's a member of VM's state class and we just check if it's "not None" from a computation instance). Another way could be passing Tracer as param all the way down in chain of calls: VM.state.apply_transaction() -> execute_transaction() -> TransactionExecutor.build_computation() -> computation.apply_computation().
  • Cross-compare output with go-ethereum tests. Problem is I can't find any tests related to non-JS (basic) tracer there. I've performed cross-comparison of multiple transactions and output is identical except few bugs in geth: e.g. sometimes it initializes memory with zero after push into stack, or do not populate error field in case error fired etc).
  • "gas" field in response represents a total block gas usage. I believe this is a bug in geth implementation and for traceTransaction should be equal to the gas used purely by a traced transaction, not the whole block.
  • Putting main "capture_state" into "finally" block allows us to catch both error and success cases in one place. Also it's the only way I've found to store a valid "cost" amount. In the future we shall move "cost" estimation calculations into Opcode's "gas_cost" method (see "operation's gasCost gasFunc" implementation in geth: https://github.com/ethereum/go-ethereum/blob/master/core/vm/jump_table.go).

eth/vm/state.py Outdated Show resolved Hide resolved
eth/vm/computation.py Outdated Show resolved Hide resolved
eth/tools/tracing.py Outdated Show resolved Hide resolved
Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

Incomplete review, will try to get you a full review tomorrow.

eth/tools/tracing.py Outdated Show resolved Hide resolved
eth/tools/tracing.py Outdated Show resolved Hide resolved
eth/tools/tracing.py Outdated Show resolved Hide resolved
@pipermerriam pipermerriam mentioned this pull request Nov 29, 2018
@pipermerriam
Copy link
Member

@rayrapetyan I started reviewing and realized that there were somewhat significant architectural changes that I wanted but needed to figure out via code.

Take a look at #1515

Wondering if you feel confident picking that up and continuing from there?

@rayrapetyan
Copy link
Contributor Author

Thanks @pipermerriam, I'll continue here using your changes.

@pipermerriam
Copy link
Member

@rayrapetyan 👍 let me know if you need anything from me.

Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

It'd be nice to get some additional tests added for this to demonstrate tracing situations that aren't boring simple value transfers (which don't excercise the actual tracing core logic).

@@ -125,7 +106,8 @@ class BaseComputation(Configurable, ABC):
def __init__(self,
state: BaseState,
message: Message,
transaction_context: BaseTransactionContext) -> None:
transaction_context: BaseTransactionContext,
tracer: BaseTracer = None) -> None:
Copy link
Member

Choose a reason for hiding this comment

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

I've been struggling with whether the tracer should be a required parameter and I'm leaning towards yes. My thought is that I already had a situation where my tests were failing because I thought I was using a real tracer but a code path hadn't been updated properly so it was defaulting to the NoopTracer. By making this a required argument we can't make that mistake.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pipermerriam, I've made it required. As per tests - do you think keeping expected JSON-trace and then simply comparing it with a result will be a good test for that?

p.s. py35-lint went crazy lol - it blames to one line which passes checks in master...
It behaves really strange, e.g. we have a lot of formatted strings like f"...", which "...are only supported in Python 3.6 and greater", how does master passes py35-lint checks then?

Copy link
Member

@pipermerriam pipermerriam Dec 8, 2018

Choose a reason for hiding this comment

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

The eth module still has to support python 3.5 so we don't use f-strings there.

My apologies if I was the one who introduced any of those 😸

Copy link
Contributor Author

@rayrapetyan rayrapetyan Dec 11, 2018

Choose a reason for hiding this comment

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

@pipermerriam, so why py35-lint is launching on a trinity module then? It fails on:
__version__: str at the top of __init__.py.
It somehow passes same on master branch...

Copy link
Member

Choose a reason for hiding this comment

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

Ah! py35-lint should not be run on the trinity module. That is an error/mistake.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pipermerriam. Weird, I don't see any diff for tox.ini in master\tracer branches, but somehow master passes all tests, and tracer fails one py35-lint test here.

@pipermerriam
Copy link
Member

I took some additional liberties here: https://github.com/rayrapetyan/py-evm/pull/2

eth/vm/tracing.py Outdated Show resolved Hide resolved
eth/vm/tracing.py Outdated Show resolved Hide resolved
@rayrapetyan
Copy link
Contributor Author

@pipermerriam, awaiting your responses in https://github.com/rayrapetyan/py-evm/pull/2. Thanks.

@rayrapetyan
Copy link
Contributor Author

@pipermerriam, please review and merge.

@carver
Copy link
Contributor

carver commented Dec 18, 2018

This commit history is pretty messy. Are you up for doing rebase/squash and force push?

Also, best to remove [WIP] from the PR title if you're ready for the final review before merging. That is one signal we use for readiness.

@rayrapetyan rayrapetyan changed the title [WIP] debug_traceTransaction endpoint implementation debug_traceTransaction endpoint implementation Dec 18, 2018
@rayrapetyan
Copy link
Contributor Author

@carver, removed WIP, please review and if everything is OK I'll squash. Thanks.

Copy link
Contributor

@carver carver left a comment

Choose a reason for hiding this comment

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

Mostly minor comments.

One thing holding it back is having a test with a trace over json-rpc with at least one failing and one succeeding transaction. Some examples with other endpoints: https://github.com/ethereum/py-evm/blob/master/tests/trinity/core/json-rpc/test_ipc.py

Alternatively, you could split out the json-rpc part into a second PR to work on those tests, and I think this would be basically ready to go. (Assuming Piper has no objections, of course). I think that would be preferred, since it's already a long PR, but not a hard requirement.

eth/vm/computation.py Outdated Show resolved Hide resolved
eth/vm/computation.py Outdated Show resolved Hide resolved
eth/vm/computation.py Outdated Show resolved Hide resolved
eth/vm/computation.py Outdated Show resolved Hide resolved
eth/vm/memory.py Outdated Show resolved Hide resolved
eth/vm/stack.py Outdated Show resolved Hide resolved
@pipermerriam
Copy link
Member

@carver I'm a little too close to this issue (as I did some significant rewriting along the way) so I'm good delegating to you for final merge.

i = 0
while i + 32 <= len(e.memory):
entry['memory'].append(remove_0x_prefix(encode_hex(e.memory[i: i + 32])))
i += 32
Copy link
Member

Choose a reason for hiding this comment

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

This is a section I'd like to cleanup but it doesn't have to be in this PR. I'm actually 👍 on removing all of the JSON-RPC stuff from this PR and doing it in a subsequent one (and just merging the core tracer API in this PR.

@rayrapetyan
Copy link
Contributor Author

@carver, if possible - please merge on your side. I swear never merge master into dev branches anymore :)

@pipermerriam
Copy link
Member

@rayrapetyan in case you aren't aware: https://help.github.com/articles/about-git-rebase/

git rebase master is what you're looking for but it takes a little bit of a learning curve to deal with merge conflicts properly.

Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

@carver I'm 👍 but I want to take this branch and pull out the trinity parts so we can iterate on those separately rather than merging them as-is.

@rayrapetyan
Copy link
Contributor Author

@pipermerriam, I would be glad to merge, but most of the changes there are yours so I can miss\overlook something. As for trinity parts - I guess you mean formatting function, I would leave it as is with a TODO mark. while i + 32 <= len(e.memory): part is exactly how it was done in geth. And btw unassign me from bounty - this was primarily your job done here. Thanks.

@pipermerriam
Copy link
Member

@rayrapetyan I'm fine with you collecting the bounty.

  1. you laid the foundation for what I did
  2. you still did a significant part of the work
  3. I like contributors being paid though I appreciate you willingness to contribute for free.

@pipermerriam
Copy link
Member

@rayrapetyan it's less about that specific line of code and more 1) wanting to give the whole implementation of the RPC endpoint another once-over and 2) wanting to convert that entire normalization function into something more inline with our code style (functional and immutable).

Copy link
Contributor

@carver carver left a comment

Choose a reason for hiding this comment

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

Needs a rebase

@pacrob pacrob deleted the branch ethereum:master December 21, 2023 02:56
@pacrob pacrob closed this Dec 21, 2023
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.

4 participants