diff --git a/evm_trace/base.py b/evm_trace/base.py index c6304c9..622640f 100644 --- a/evm_trace/base.py +++ b/evm_trace/base.py @@ -3,7 +3,7 @@ from eth_pydantic_types import HexBytes from pydantic import BaseModel as _BaseModel -from pydantic import ConfigDict, field_validator +from pydantic import ConfigDict, Field, field_validator from evm_trace.display import get_tree_display from evm_trace.enums import CallType @@ -30,11 +30,15 @@ class EventNode(BaseModel): depth: int """The depth in a call-tree where the event took place.""" - selector: HexBytes - """The selector hash of the event.""" + topics: list[HexBytes] = Field(min_length=1) + """Event topics, including the selector.""" - topics: list[HexBytes] = [] - """Event topics.""" + @property + def selector(self) -> HexBytes: + """ + The selector is always the first topic. + """ + return self.topics[0] class CallTreeNode(BaseModel): diff --git a/evm_trace/geth.py b/evm_trace/geth.py index 5bfdfc2..aa6940a 100644 --- a/evm_trace/geth.py +++ b/evm_trace/geth.py @@ -357,7 +357,7 @@ def _create_event_node(frame: TraceFrame) -> EventNode: # Figure out topics. start_topic_idx = selector_idx - num_topics + 1 - topics = [HexBytes(t) for t in reversed(frame.stack[start_topic_idx:selector_idx])] + topics = [selector, *[HexBytes(t) for t in reversed(frame.stack[start_topic_idx:selector_idx])]] # Figure out data. num_data_items = int(frame.stack[-2].hex(), 16) // 32 @@ -367,12 +367,7 @@ def _create_event_node(frame: TraceFrame) -> EventNode: end_data_idx = data_idx + num_data_items data = frame.memory.root[data_idx:end_data_idx] - return EventNode( - data=data, - depth=frame.depth, - selector=selector, - topics=topics, - ) + return EventNode(data=data, depth=frame.depth, topics=topics) def _validate_data_from_call_tracer(data: dict) -> dict: diff --git a/tests/test_geth.py b/tests/test_geth.py index b98a2a6..79d899e 100644 --- a/tests/test_geth.py +++ b/tests/test_geth.py @@ -150,11 +150,16 @@ def test_get_calltree_from_geth_trace_handles_events(geth_structlogs): # Assert `.topics` is correct. assert actual_events[0].topics == [ + HexBytes(expected_selector_0), HexBytes(f"0x000000000000000000000000{contract_a}"), HexBytes("0x0000000000000000000000000000000000000000000000000000000000000001"), ] - assert actual_events[1].topics == [HexBytes(f"0x000000000000000000000000{contract_a}")] + assert actual_events[1].topics == [ + HexBytes(expected_selector_1), + HexBytes(f"0x000000000000000000000000{contract_a}"), + ] assert actual_events[2].topics == [ + HexBytes(expected_selector_2), HexBytes("0x0000000000000000000000000000000000000000000000000000000000000005"), HexBytes("0x0000000000000000000000000000000000000000000000000000000000000006"), HexBytes("0x0000000000000000000000000000000000000000000000000000000000000007"),