Skip to content

Commit b6046f0

Browse files
authored
fix: show trace on transaction fail (#129)
1 parent 29e328d commit b6046f0

File tree

12 files changed

+191
-99
lines changed

12 files changed

+191
-99
lines changed

.github/workflows/codeql.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020

2121
steps:
2222
- name: Checkout repository
23-
uses: actions/checkout@v4
23+
uses: actions/checkout@v5
2424

2525
- name: Initialize CodeQL
2626
uses: github/codeql-action/init@v2

.github/workflows/commitlint.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010

1111
steps:
12-
- uses: actions/checkout@v4
12+
- uses: actions/checkout@v5
1313
with:
1414
fetch-depth: 0
1515

.github/workflows/docs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
contents: write
1717

1818
steps:
19-
- uses: actions/checkout@v4
19+
- uses: actions/checkout@v5
2020

2121
- name: Setup Python
2222
uses: actions/setup-python@v5

.github/workflows/prtitle.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313

1414
steps:
15-
- uses: actions/checkout@v4
15+
- uses: actions/checkout@v5
1616

1717
- name: Setup Python
1818
uses: actions/setup-python@v5

.github/workflows/publish.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111

1212
steps:
13-
- uses: actions/checkout@v4
13+
- uses: actions/checkout@v5
1414

1515
- name: Set up Python
1616
uses: actions/setup-python@v5

.github/workflows/test.yaml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515

1616
steps:
17-
- uses: actions/checkout@v4
17+
- uses: actions/checkout@v5
1818

1919
- name: Setup Python
2020
uses: actions/setup-python@v5
@@ -26,14 +26,11 @@ jobs:
2626
python -m pip install --upgrade pip
2727
pip install .[lint]
2828
29-
- name: Run Black
30-
run: black --check .
29+
- name: Run Ruff Lint
30+
run: ruff check .
3131

32-
- name: Run isort
33-
run: isort --check-only .
34-
35-
- name: Run flake8
36-
run: flake8 .
32+
- name: Run Ruff Format
33+
run: ruff format --check .
3734

3835
- name: Run mdformat
3936
run: mdformat . --check
@@ -42,7 +39,7 @@ jobs:
4239
runs-on: ubuntu-latest
4340

4441
steps:
45-
- uses: actions/checkout@v4
42+
- uses: actions/checkout@v5
4643

4744
- name: Setup Python
4845
uses: actions/setup-python@v5
@@ -66,7 +63,7 @@ jobs:
6663
python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]
6764

6865
steps:
69-
- uses: actions/checkout@v4
66+
- uses: actions/checkout@v5
7067

7168
- name: Install Foundry
7269
uses: foundry-rs/foundry-toolchain@v1
@@ -102,7 +99,7 @@ jobs:
10299
# fail-fast: true
103100
#
104101
# steps:
105-
# - uses: actions/checkout@v4
102+
# - uses: actions/checkout@v5
106103
#
107104
# - name: Setup Python
108105
# uses: actions/setup-python@v5

.pre-commit-config.yaml

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,21 @@ repos:
44
hooks:
55
- id: check-yaml
66

7-
- repo: https://github.com/PyCQA/isort
8-
rev: 5.13.2
7+
- repo: https://github.com/astral-sh/ruff-pre-commit
8+
rev: v0.12.0 # Latest ruff version
99
hooks:
10-
- id: isort
11-
12-
- repo: https://github.com/psf/black
13-
rev: 24.10.0
14-
hooks:
15-
- id: black
16-
name: black
17-
18-
- repo: https://github.com/pycqa/flake8
19-
rev: 7.1.1
20-
hooks:
21-
- id: flake8
22-
additional_dependencies: [flake8-breakpoint, flake8-print, flake8-pydantic, flake8-type-checking]
10+
- id: ruff
11+
args: [--fix, --exit-non-zero-on-fix]
12+
- id: ruff-format
2313

2414
- repo: https://github.com/pre-commit/mirrors-mypy
25-
rev: v1.13.0
15+
rev: v1.16.1
2616
hooks:
2717
- id: mypy
28-
additional_dependencies: [types-PyYAML, types-requests, types-setuptools, pydantic]
18+
additional_dependencies: [types-setuptools, pydantic]
2919

3020
- repo: https://github.com/executablebooks/mdformat
31-
rev: 0.7.19
21+
rev: 0.7.22
3222
hooks:
3323
- id: mdformat
3424
additional_dependencies: [mdformat-gfm, mdformat-frontmatter, mdformat-pyproject]

ape_foundry/provider.py

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,18 @@
2626
from ape.utils import cached_property
2727
from ape_ethereum.provider import Web3Provider
2828
from ape_test import ApeTestConfig
29-
from eth_pydantic_types import HexBytes, HexBytes32
3029
from eth_typing import HexStr
3130
from eth_utils import add_0x_prefix, is_0x_prefixed, is_hex, to_hex
3231
from pydantic import field_validator, model_validator
3332
from pydantic_settings import SettingsConfigDict
3433
from web3 import HTTPProvider, Web3
35-
from web3.exceptions import ContractCustomError
34+
from web3.exceptions import ContractCustomError, ExtraDataLengthError
3635
from web3.exceptions import ContractLogicError as Web3ContractLogicError
37-
from web3.exceptions import ExtraDataLengthError
3836
from web3.gas_strategies.rpc import rpc_gas_price_strategy
3937

38+
from eth_pydantic_types import HexBytes, HexBytes32
39+
from eth_pydantic_types.utils import PadDirection
40+
4041
try:
4142
from web3.middleware import ExtraDataToPOAMiddleware # type: ignore
4243
except ImportError:
@@ -66,6 +67,9 @@
6667
EPHEMERAL_PORTS_END = 60999
6768
DEFAULT_PORT = 8545
6869
FOUNDRY_CHAIN_ID = 31337
70+
FOUNDRY_REVERT_PREFIX = (
71+
"Error: VM Exception while processing transaction: reverted with reason string"
72+
)
6973

7074

7175
class FoundryForkConfig(PluginConfig):
@@ -345,16 +349,15 @@ def connect(self):
345349
else:
346350
# The user configured a host and the anvil process was already running.
347351
logger.info(
348-
f"Connecting to existing '{self.process_name}' "
349-
f"at host '{self._clean_uri}'."
352+
f"Connecting to existing '{self.process_name}' at host '{self._clean_uri}'."
350353
)
351354
else:
352355
for _ in range(self.settings.process_attempts):
353356
try:
354357
self._start()
355358
break
356359
except FoundryNotInstalledError:
357-
# Is a sub-class of `FoundrySubprocessError` but we to still raise
360+
# Is a subclass of `FoundrySubprocessError` but we to still raise
358361
# so we don't keep retrying.
359362
raise
360363
except SubprocessError as exc:
@@ -562,14 +565,9 @@ def get_virtual_machine_error(self, exception: Exception, **kwargs) -> VirtualMa
562565
if not message:
563566
return VirtualMachineError(base_err=exception, **kwargs)
564567

565-
# Handle specific cases based on message content
566-
foundry_prefix = (
567-
"Error: VM Exception while processing transaction: reverted with reason string "
568-
)
569-
570568
# Handle Foundry error prefix
571-
if message.startswith(foundry_prefix):
572-
message = message.replace(foundry_prefix, "").strip("'")
569+
if message.startswith(FOUNDRY_REVERT_PREFIX):
570+
message = message.replace(f"{FOUNDRY_REVERT_PREFIX} ", "").strip("'")
573571
return self._handle_execution_reverted(exception, message, **kwargs)
574572

575573
# Handle various cases of transaction reverts
@@ -604,6 +602,9 @@ def get_virtual_machine_error(self, exception: Exception, **kwargs) -> VirtualMa
604602
def _handle_execution_reverted( # type: ignore[override]
605603
self, exception: Exception, revert_message: Optional[str] = None, **kwargs
606604
):
605+
trace = kwargs.get("trace")
606+
txn = kwargs.get("txn")
607+
607608
# Assign default message if revert_message is invalid
608609
if revert_message == "0x":
609610
revert_message = TransactionError.DEFAULT_MESSAGE
@@ -618,12 +619,25 @@ def _handle_execution_reverted( # type: ignore[override]
618619
enriched = self.compiler_manager.enrich_error(sub_err)
619620

620621
# Show call trace if available
621-
txn = enriched.txn
622-
if txn and hasattr(txn, "show_trace"):
623-
if isinstance(txn, TransactionAPI) and txn.receipt:
624-
txn.receipt.show_trace()
622+
if trace and callable(trace):
623+
trace = trace()
624+
625+
if not trace and (txn := txn):
626+
if isinstance(txn, TransactionAPI):
627+
if txn.receipt:
628+
trace = txn.receipt.trace
629+
else:
630+
# Calls it from the provider.
631+
try:
632+
trace = txn.trace
633+
except Exception:
634+
pass
635+
625636
elif isinstance(txn, ReceiptAPI):
626-
txn.show_trace()
637+
trace = txn.trace
638+
639+
if trace:
640+
trace.show()
627641

628642
return enriched
629643

@@ -668,8 +682,8 @@ def set_storage(self, address: "AddressType", slot: int, value: HexBytes):
668682
"anvil_setStorageAt",
669683
[
670684
address,
671-
to_hex(HexBytes32.__eth_pydantic_validate__(slot)),
672-
to_hex(HexBytes32.__eth_pydantic_validate__(value)),
685+
to_hex(HexBytes32.__eth_pydantic_validate__(slot, pad=PadDirection.LEFT)),
686+
to_hex(HexBytes32.__eth_pydantic_validate__(value, pad=PadDirection.LEFT)),
673687
],
674688
)
675689

0 commit comments

Comments
 (0)