Skip to content

Commit

Permalink
chore: bump ethpm-types [APE-676] (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Feb 28, 2023
1 parent 44b6a13 commit 4f7497e
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ repos:
rev: v0.991
hooks:
- id: mypy
additional_dependencies: [types-PyYAML, types-requests, types-setuptools]
additional_dependencies: [types-PyYAML, types-requests, types-setuptools, pydantic]

- repo: https://github.com/executablebooks/mdformat
rev: 0.7.14
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ from web3 import HTTPProvider, Web3
from evm_trace import TraceFrame

web3 = Web3(HTTPProvider("https://path.to.my.node"))
txn_hash = "0x..."
struct_logs = web3.manager.request_blocking("debug_traceTransaction", [txn_hash]).structLogs
for item in struct_logs:
yield TraceFrame(**item)
frame = TraceFrame.parse_obj(item)
```

If you want to get the call-tree node, you can do:
Expand Down
66 changes: 39 additions & 27 deletions evm_trace/geth.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,46 @@ def get_calltree_from_geth_trace(
:class:`~evm_trace.base.CallTreeNode`: Call tree of transaction trace.
"""

return _create_node_from_call(
return _create_node(
trace=trace,
show_internal=show_internal,
**root_node_kwargs,
)


def _extract_memory(offset: HexBytes, size: HexBytes, memory: List[HexBytes]) -> HexBytes:
def create_call_node_data(frame: TraceFrame) -> Dict:
"""
Parse a CALL-opcode frame into an address and calldata.
Args:
frame (:class:`~evm_trace.geth.TraceFrame`): The call frame to parse.
Returns:
Tuple[str, HexBytes]: A tuple of the address str and the calldata.
"""

data = {"address": frame.stack[-2][-20:], "depth": frame.depth}
if frame.op == CallType.CALL.value:
data["call_type"] = CallType.CALL
data["value"] = int(frame.stack[-3].hex(), 16)
data["calldata"] = extract_memory(
offset=frame.stack[-4], size=frame.stack[-5], memory=frame.memory
)
elif frame.op == CallType.DELEGATECALL.value:
data["call_type"] = CallType.DELEGATECALL
data["calldata"] = extract_memory(
offset=frame.stack[-3], size=frame.stack[-4], memory=frame.memory
)
else:
data["call_type"] = CallType.STATICCALL
data["calldata"] = extract_memory(
offset=frame.stack[-3], size=frame.stack[-4], memory=frame.memory
)

return data


def extract_memory(offset: HexBytes, size: HexBytes, memory: List[HexBytes]) -> HexBytes:
"""
Extracts memory from the EVM stack.
Expand Down Expand Up @@ -129,7 +161,7 @@ def _extract_memory(offset: HexBytes, size: HexBytes, memory: List[HexBytes]) ->
return HexBytes(return_bytes)


def _create_node_from_call(
def _create_node(
trace: Iterator[TraceFrame], show_internal: bool = False, **node_kwargs
) -> CallTreeNode:
"""
Expand All @@ -145,29 +177,9 @@ def _create_node_from_call(
if frame.op in [x.value for x in CALL_OPCODES]:
# NOTE: Because of the different meanings in structLog style gas values,
# gas is not set for nodes created this way.
child_node_kwargs = {"address": frame.stack[-2][-20:], "depth": frame.depth}

if frame.op == CallType.CALL.value:
child_node_kwargs["call_type"] = CallType.CALL
child_node_kwargs["value"] = int(frame.stack[-3].hex(), 16)
child_node_kwargs["calldata"] = _extract_memory(
offset=frame.stack[-4], size=frame.stack[-5], memory=frame.memory
)
elif frame.op == CallType.DELEGATECALL.value:
child_node_kwargs["call_type"] = CallType.DELEGATECALL
child_node_kwargs["calldata"] = _extract_memory(
offset=frame.stack[-3], size=frame.stack[-4], memory=frame.memory
)
else:
child_node_kwargs["call_type"] = CallType.STATICCALL
child_node_kwargs["calldata"] = _extract_memory(
offset=frame.stack[-3], size=frame.stack[-4], memory=frame.memory
)

child_node = _create_node_from_call(
trace=trace, show_internal=show_internal, **child_node_kwargs
)
node.calls.append(child_node)
data = create_call_node_data(frame)
child = _create_node(trace=trace, show_internal=show_internal, **data)
node.calls.append(child)

# TODO: Handle internal nodes using JUMP and JUMPI

Expand All @@ -181,7 +193,7 @@ def _create_node_from_call(
break

elif frame.op in ("RETURN", "REVERT") and not node.returndata:
node.returndata = _extract_memory(
node.returndata = extract_memory(
offset=frame.stack[-1], size=frame.stack[-2], memory=frame.memory
)
# TODO: Handle "execution halted" vs. gas limit reached
Expand Down
2 changes: 1 addition & 1 deletion evm_trace/vmtrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from eth.vm.memory import Memory
from eth.vm.stack import Stack
from eth_utils import to_checksum_address
from hexbytes import HexBytes
from ethpm_types import HexBytes
from msgspec import Struct
from msgspec.json import Decoder

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ requires = ["setuptools>=51.1.1", "wheel", "setuptools_scm[toml]>=5.0"]

[tool.mypy]
exclude = "build/"
plugins = ["pydantic.mypy"]

[tool.setuptools_scm]
write_to = "evm_trace/version.py"
Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@
install_requires=[
"pydantic>=1.10.1,<2",
"py-evm>=0.6.0a1",
"hexbytes>=0.2.3,<1",
"eth-utils>=2",
"ethpm-types>=0.3.7,<0.4",
"ethpm-types>=0.4.0,<0.5",
"msgspec>=0.8",
],
python_requires=">=3.8,<4",
Expand Down
2 changes: 1 addition & 1 deletion tests/test_geth.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from hexbytes import HexBytes
from ethpm_types import HexBytes
from pydantic import ValidationError

from evm_trace.enums import CallType
Expand Down

0 comments on commit 4f7497e

Please sign in to comment.