From 347e0ca8143e6727ac21c88e4434c4137545ab2f Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Wed, 8 Sep 2021 15:10:07 -0700 Subject: [PATCH 1/5] make stack the expected length --- brownie/network/transaction.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/brownie/network/transaction.py b/brownie/network/transaction.py index 1f144ffe1..a816921ea 100644 --- a/brownie/network/transaction.py +++ b/brownie/network/transaction.py @@ -10,6 +10,7 @@ from hashlib import sha1 from pathlib import Path from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings import black import requests @@ -839,6 +840,11 @@ def _expand_trace(self) -> None: is_subcall = trace[i - 1]["op"] in call_opcodes if is_depth_increase or is_subcall: step = trace[i - 1] + + # different nodes return this hex in different formats + # we need 32 bytes (64 characters) without the 0x prefix + step["stack"] = [HexBytes(s).hex()[2:].zfill(64) for s in step["stack"]] + if step["op"] in ("CREATE", "CREATE2"): # creating a new contract out = next(x for x in trace[i:] if x["depth"] == step["depth"]) @@ -864,6 +870,7 @@ def _expand_trace(self) -> None: self._subcalls.append( {"from": step["address"], "to": EthAddress(address), "op": step["op"]} ) + if step["op"] in ("CALL", "CALLCODE"): self._subcalls[-1]["value"] = int(step["stack"][-3], 16) if is_depth_increase and calldata and last_map[trace[i]["depth"]].get("function"): @@ -978,8 +985,12 @@ def _expand_trace(self) -> None: ) def _add_internal_xfer(self, from_: str, to: str, value: str) -> None: + if not value.startswith("0x"): + # TODO: this seems wrong + value = f"0x{value}" + self._internal_transfers.append( # type: ignore - {"from": EthAddress(from_), "to": EthAddress(to), "value": Wei(f"0x{value}")} + {"from": EthAddress(from_), "to": EthAddress(to), "value": Wei(value)} ) def _full_name(self) -> str: From bd395dac8189102a86eb825686c3ee08f8b0bee8 Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Thu, 9 Sep 2021 11:47:19 -0700 Subject: [PATCH 2/5] undo unnecessary change --- brownie/network/transaction.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/brownie/network/transaction.py b/brownie/network/transaction.py index a816921ea..6b811458f 100644 --- a/brownie/network/transaction.py +++ b/brownie/network/transaction.py @@ -10,7 +10,6 @@ from hashlib import sha1 from pathlib import Path from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union -import warnings import black import requests @@ -985,12 +984,8 @@ def _expand_trace(self) -> None: ) def _add_internal_xfer(self, from_: str, to: str, value: str) -> None: - if not value.startswith("0x"): - # TODO: this seems wrong - value = f"0x{value}" - self._internal_transfers.append( # type: ignore - {"from": EthAddress(from_), "to": EthAddress(to), "value": Wei(value)} + {"from": EthAddress(from_), "to": EthAddress(to), "value": Wei(f"0x{value}")} ) def _full_name(self) -> str: From 3dc73f4b7be1b99a87435fb34e620db8f0188fc3 Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Thu, 9 Sep 2021 11:47:59 -0700 Subject: [PATCH 3/5] lint --- brownie/network/transaction.py | 1 - 1 file changed, 1 deletion(-) diff --git a/brownie/network/transaction.py b/brownie/network/transaction.py index 6b811458f..6cbc4a588 100644 --- a/brownie/network/transaction.py +++ b/brownie/network/transaction.py @@ -869,7 +869,6 @@ def _expand_trace(self) -> None: self._subcalls.append( {"from": step["address"], "to": EthAddress(address), "op": step["op"]} ) - if step["op"] in ("CALL", "CALLCODE"): self._subcalls[-1]["value"] = int(step["stack"][-3], 16) if is_depth_increase and calldata and last_map[trace[i]["depth"]].get("function"): From 27fa5c799e23d78e27bdd0917e943768c025ceb5 Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Thu, 9 Sep 2021 20:22:00 -0700 Subject: [PATCH 4/5] move the stack fix and fix similar issues --- brownie/network/state.py | 4 +-- brownie/network/transaction.py | 45 +++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/brownie/network/state.py b/brownie/network/state.py index f617f70c0..3e3182dd3 100644 --- a/brownie/network/state.py +++ b/brownie/network/state.py @@ -14,7 +14,7 @@ from brownie._config import CONFIG, _get_data_folder from brownie._singleton import _Singleton from brownie.convert import Wei -from brownie.exceptions import BrownieEnvironmentError +from brownie.exceptions import BrownieEnvironmentError, CompilerError from brownie.network import rpc from brownie.project.build import DEPLOYMENT_KEYS from brownie.utils.sql import Cursor @@ -555,7 +555,7 @@ def _find_contract(address: Any) -> Any: from brownie.network.contract import Contract return Contract(address) - except ValueError: + except (ValueError, CompilerError): pass diff --git a/brownie/network/transaction.py b/brownie/network/transaction.py index 6cbc4a588..54ec4cb7d 100644 --- a/brownie/network/transaction.py +++ b/brownie/network/transaction.py @@ -10,6 +10,7 @@ from hashlib import sha1 from pathlib import Path from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +from warnings import warn import black import requests @@ -657,12 +658,33 @@ def _get_trace(self) -> None: self._modified_state = False return - if isinstance(trace[0]["gas"], str): - # handle traces where numeric values are returned as hex (Nethermind) + # different nodes return their values in slightly different formats. its really fun to handle + + # check to see if need to fix the values on the stack + fix_stack = False + for step in trace: + if not step["stack"]: + continue + check = step["stack"][0] + if not (len(check) == 64 and check.isnumeric()): + fix_stack = True + break + + fix_gas = isinstance(trace[0]["gas"], str) + + if fix_stack or fix_gas: for step in trace: - step["gas"] = int(step["gas"], 16) - step["gasCost"] = int.from_bytes(HexBytes(step["gasCost"]), "big", signed=True) - step["pc"] = int(step["pc"], 16) + # for stack values, we need 32 bytes (64 characters) without the 0x prefix + # geth/nethermind returns unprefixed and with padding + # erigon returns 0x-prefixed and without padding (but their memory values are like geth) + if fix_stack: + step["stack"] = [HexBytes(s).hex()[2:].zfill(64) for s in step["stack"]] + + if fix_gas: + # handle traces where numeric values are returned as hex (Nethermind) + step["gas"] = int(step["gas"], 16) + step["gasCost"] = int.from_bytes(HexBytes(step["gasCost"]), "big", signed=True) + step["pc"] = int(step["pc"], 16) if self.status: self._confirmed_trace(trace) @@ -678,6 +700,9 @@ def _confirmed_trace(self, trace: Sequence) -> None: if contract: data = _get_memory(trace[-1], -1) fn = contract.get_method_object(self.input) + if not fn: + warn(f"Unable to find function on {contract} for input {self.input}") + return self._return_value = fn.decode_output(data) def _reverted_trace(self, trace: Sequence) -> None: @@ -839,11 +864,6 @@ def _expand_trace(self) -> None: is_subcall = trace[i - 1]["op"] in call_opcodes if is_depth_increase or is_subcall: step = trace[i - 1] - - # different nodes return this hex in different formats - # we need 32 bytes (64 characters) without the 0x prefix - step["stack"] = [HexBytes(s).hex()[2:].zfill(64) for s in step["stack"]] - if step["op"] in ("CREATE", "CREATE2"): # creating a new contract out = next(x for x in trace[i:] if x["depth"] == step["depth"]) @@ -983,8 +1003,11 @@ def _expand_trace(self) -> None: ) def _add_internal_xfer(self, from_: str, to: str, value: str) -> None: + if not value.startswith("0x"): + value = f"0x{value}" + self._internal_transfers.append( # type: ignore - {"from": EthAddress(from_), "to": EthAddress(to), "value": Wei(f"0x{value}")} + {"from": EthAddress(from_), "to": EthAddress(to), "value": Wei(value)} ) def _full_name(self) -> str: From 856c0dae9583394565d121e4419fd3b388c38645 Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Thu, 9 Sep 2021 20:33:21 -0700 Subject: [PATCH 5/5] lint --- brownie/network/transaction.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/brownie/network/transaction.py b/brownie/network/transaction.py index 54ec4cb7d..c72144753 100644 --- a/brownie/network/transaction.py +++ b/brownie/network/transaction.py @@ -658,15 +658,17 @@ def _get_trace(self) -> None: self._modified_state = False return - # different nodes return their values in slightly different formats. its really fun to handle - - # check to see if need to fix the values on the stack + # different nodes return slightly different formats. its really fun to handle + # geth/nethermind returns unprefixed and with 0-padding for stack and memory + # erigon returns 0x-prefixed and without padding (but their memory values are like geth) fix_stack = False for step in trace: if not step["stack"]: continue check = step["stack"][0] - if not (len(check) == 64 and check.isnumeric()): + if not isinstance(check, str): + break + if check.startswith("0x"): fix_stack = True break @@ -674,12 +676,9 @@ def _get_trace(self) -> None: if fix_stack or fix_gas: for step in trace: - # for stack values, we need 32 bytes (64 characters) without the 0x prefix - # geth/nethermind returns unprefixed and with padding - # erigon returns 0x-prefixed and without padding (but their memory values are like geth) if fix_stack: + # for stack values, we need 32 bytes (64 chars) without the 0x prefix step["stack"] = [HexBytes(s).hex()[2:].zfill(64) for s in step["stack"]] - if fix_gas: # handle traces where numeric values are returned as hex (Nethermind) step["gas"] = int(step["gas"], 16)