diff --git a/src/ape/exceptions.py b/src/ape/exceptions.py index 0a1530592c..6ff5bcdefa 100644 --- a/src/ape/exceptions.py +++ b/src/ape/exceptions.py @@ -186,7 +186,7 @@ def __init__( contract_address: Optional["AddressType"] = None, source_traceback: _SOURCE_TRACEBACK_ARG = None, project: Optional["ProjectManager"] = None, - set_ape_traceback: bool = False, # Overriden in ContractLogicError + set_ape_traceback: bool = False, # Overridden in ContractLogicError ): message = message or (str(base_err) if base_err else self.DEFAULT_MESSAGE) self.message = message diff --git a/src/ape_ethereum/ecosystem.py b/src/ape_ethereum/ecosystem.py index 62f6836b93..738d0fc942 100644 --- a/src/ape_ethereum/ecosystem.py +++ b/src/ape_ethereum/ecosystem.py @@ -1254,7 +1254,6 @@ def _enrich_returndata(self, call: dict, method_abi: MethodABI, **kwargs) -> dic default_return_value = "" returndata = call.get("returndata", "") is_hexstr = isinstance(returndata, str) and is_0x_prefixed(returndata) - return_value_bytes = None # Check if return is only a revert string. call = self._enrich_revert_message(call) diff --git a/src/ape_ethereum/trace.py b/src/ape_ethereum/trace.py index 7b251601bd..501ef2ec98 100644 --- a/src/ape_ethereum/trace.py +++ b/src/ape_ethereum/trace.py @@ -226,13 +226,21 @@ def return_value(self) -> Any: return self._return_value_from_enriched_calltree elif abi := self.root_method_abi: - return_data = self._return_data_from_trace_frames - if return_data is not None: - try: - return self._ecosystem.decode_returndata(abi, return_data) - except Exception as err: - logger.debug(f"Failed decoding return data from trace frames. Error: {err}") - # Use enrichment method. It is slow but it'll at least work. + if self.call_trace_approach is TraceApproach.GETH_STRUCT_LOG_PARSE: + return_data = self._return_data_from_trace_frames + if return_data is not None: + try: + return self._ecosystem.decode_returndata(abi, return_data) + except Exception as err: + logger.debug(f"Failed decoding return data from trace frames. Error: {err}") + # Use enrichment method. It is slow but it'll at least work. + + else: + # Barely enrich a calltree for performance reasons + # (likely not a need to enrich the whole thing). + calltree = self.get_raw_calltree() + enriched_calltree = self._ecosystem._enrich_returndata(calltree, abi) + return self._get_return_value_from_calltree(enriched_calltree) return self._return_value_from_enriched_calltree @@ -244,6 +252,9 @@ def _return_value_from_enriched_calltree(self) -> Any: if "return_value" in self.__dict__: return self.__dict__["return_value"] + return self._get_return_value_from_calltree(calltree) + + def _get_return_value_from_calltree(self, calltree: dict) -> Any: # If enriching too much, Ethereum places regular values in a key # named "unenriched_return_values". if "unenriched_return_values" in calltree: diff --git a/tests/functional/geth/test_trace.py b/tests/functional/geth/test_trace.py index a71a3a50bd..532e75a0e1 100644 --- a/tests/functional/geth/test_trace.py +++ b/tests/functional/geth/test_trace.py @@ -310,8 +310,13 @@ def test_call_trace_supports_debug_trace_call(geth_contract, geth_account): @geth_process_test -def test_return_value(geth_contract, geth_account): - receipt = geth_contract.getFilledArray.transact(sender=geth_account) +def test_return_value(benchmark, geth_contract, geth_account): + receipt = benchmark.pedantic( + geth_contract.getFilledArray.transact, + kwargs={"sender": geth_account}, + rounds=5, + warmup_rounds=1, + ) trace = receipt.trace expected = [1, 2, 3] # Hardcoded in contract assert receipt.return_value == expected @@ -324,3 +329,9 @@ def test_return_value(geth_contract, geth_account): # NOTE: This is very important from a performance perspective! # (VERY IMPORTANT). We shouldn't need to enrich anything. assert trace._enriched_calltree is None + + # Seeing 0.14. + # Before https://github.com/ApeWorX/ape/pull/2225, was seeing 0.17. + # In CI, can see up to 0.4 though. + avg = benchmark.stats["mean"] + assert avg < 0.6