Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show_trace() method on ReceiptAPI #746

Merged
merged 97 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
2289724
feat: trace
antazoey May 23, 2022
ae951f5
docs: correct format
antazoey May 23, 2022
884816d
fix: returndata and coloring improvements
antazoey May 23, 2022
2af0ad9
refactor: make returndata output brighter
antazoey May 23, 2022
071f1cd
fix: fetch contract type from etherscan
antazoey May 23, 2022
b888c8f
fix: fetch contract type from etherscan
antazoey May 23, 2022
3f46ed2
chore: Merge branch 'fix/jules-regression-fetch-contract-type' into f…
antazoey May 23, 2022
2be678c
feat: handle struct and list wrapping
antazoey May 24, 2022
4e74961
feat: return value color fix
antazoey May 24, 2022
d1f7557
chore: Merge branch 'main' into feat/jules-show-trace
antazoey May 25, 2022
ee3281d
docs: adjust primitive val docs
antazoey May 25, 2022
86da232
chore: abs
antazoey May 26, 2022
2e5cd79
chore: resolve merge conflicts
antazoey Jun 2, 2022
00ede3e
fix: check for contract logic error
antazoey Jun 2, 2022
bca0681
chore: Merge branch 'fix/jules-ignore-contract-logic-error-in-proxy' …
antazoey Jun 2, 2022
4d2f03e
chore: revert eth upgrade changes
antazoey Jun 2, 2022
a5496bd
refactor: include default vm error handling
antazoey Jun 2, 2022
eca7cf1
fix: contract logic error
antazoey Jun 2, 2022
0128bd8
fix: default vm err handling in call
antazoey Jun 2, 2022
081693c
chore: Merge branch 'refactor/jules/add-default-vm-err-handling' into…
antazoey Jun 2, 2022
1362af9
chore: Merge branch 'fix/jules-ignore-contract-logic-error-in-proxy' …
antazoey Jun 2, 2022
5f464c0
feat: display revert message
antazoey Jun 2, 2022
413fb12
feat: show contract names when found
antazoey Jun 2, 2022
39f2fe7
docs: adjust comment
antazoey Jun 2, 2022
5caf24b
fix: change from 4 to 2 spaces
antazoey Jun 2, 2022
d5f9ed8
feat: include gas in call sig
antazoey Jun 2, 2022
c05cc9c
feat: inc sender
antazoey Jun 2, 2022
09a4d46
fix: space
antazoey Jun 2, 2022
36e0f4b
feat: verbose option
antazoey Jun 2, 2022
3113ca0
chore: Merge branch 'main' into feat/jules-show-trace
antazoey Jun 3, 2022
cb8a12a
chore: upgrade mypy
antazoey Jun 3, 2022
dff5c0a
refactor: use new ethpm-types selector access
antazoey Jun 3, 2022
9f3a906
fix: dont cache iterator
antazoey Jun 3, 2022
fff7cd1
fix: inject contract name if can for default
antazoey Jun 3, 2022
8a83de6
fix: view methods
antazoey Jun 3, 2022
fa45960
fix: handle corrup return data
antazoey Jun 3, 2022
3669f4b
feat: use Sender for sender
antazoey Jun 3, 2022
b7b397a
refactor: rename
antazoey Jun 6, 2022
605802c
test: add really bad test
antazoey Jun 8, 2022
a68ad5a
docs: add docs
antazoey Jun 9, 2022
d8a0db2
fix: issue where struct values were not decoding
antazoey Jun 9, 2022
9d46a87
docs: revise
antazoey Jun 9, 2022
9364b77
fix: rm duplicate code
antazoey Jun 9, 2022
33b06c9
chore: merge main
antazoey Jun 9, 2022
4979a37
chore: mypy
antazoey Jun 9, 2022
8b40be8
chore: lessen some eth constraints
antazoey Jun 9, 2022
a6b6fb1
fix: conditional trunc and readme not impl
antazoey Jun 9, 2022
5458017
docs: update default desc
antazoey Jun 9, 2022
de5a25c
feat: use tx.origin for Sender
antazoey Jun 9, 2022
b380852
feat: more colors
antazoey Jun 9, 2022
f1fe613
feat: make cached_iterator
antazoey Jun 9, 2022
6f52a82
fix: cached iterator bug
antazoey Jun 9, 2022
8c28707
feat: member var
antazoey Jun 9, 2022
99fd67e
chore: upgrade lint deps from template
antazoey Jun 9, 2022
3573dbc
feat: use symbol if available
antazoey Jun 9, 2022
e26e043
fix: simplify getting contract inst
antazoey Jun 9, 2022
fcf9faf
chore: merge main
antazoey Jun 9, 2022
da82cde
fix: colors
antazoey Jun 9, 2022
e78c3a1
feat: dim even the default gas blocks
antazoey Jun 9, 2022
00fdddd
feat: collapse precompile calls
antazoey Jun 10, 2022
98fbcaf
refactor: simplify tee logic
antazoey Jun 13, 2022
9512034
refactor: matching change to last commit
antazoey Jun 13, 2022
9a77544
feat: use new evm-trace upgrade
antazoey Jun 13, 2022
9326039
chore: Merge branch 'feat/jules-show-trace' of github.com:unparallele…
antazoey Jun 13, 2022
22cf0c0
fix: issue with input data
antazoey Jun 13, 2022
18d0844
fix: dim default gas when partial default
antazoey Jun 13, 2022
65d004a
feat: include value
antazoey Jun 13, 2022
6c96abe
feat: add failed prop
antazoey Jun 14, 2022
35e74d5
fix: properly handle revert
antazoey Jun 14, 2022
6881743
fix: bytes input data
banteg Jun 14, 2022
203b33b
refactor: rm unused code
antazoey Jun 14, 2022
34f8ae2
feat: add get_call_tree to geth provider
banteg Jun 14, 2022
f10ff71
chore: rm no longer needed code
antazoey Jun 14, 2022
f1af3fb
Merge pull request #76 from banteg/bunny-trace-2
antazoey Jun 14, 2022
1deb3d3
fix: eth value
antazoey Jun 14, 2022
0ce729a
fix: more suport for parity and traces
antazoey Jun 14, 2022
aa24884
fix: more suport for parity and traces
antazoey Jun 14, 2022
ad8e0d1
fix: dont inc val when 0.0
antazoey Jun 15, 2022
64a78a2
chore: color adjustments
antazoey Jun 15, 2022
a37f3a1
fix: issue with verbose JSON calltype
antazoey Jun 15, 2022
30f96a2
fix: weirdness with empty str
antazoey Jun 15, 2022
0b33f4f
feat: handle list of lists
antazoey Jun 15, 2022
d83cb06
refactor: trace utils
antazoey Jun 15, 2022
ab91df3
fix: properly handle list of lists
antazoey Jun 15, 2022
8b0239a
test: begin test
antazoey Jun 15, 2022
819739e
chore: upgrade mypy
antazoey Jun 15, 2022
633c62e
chore: upgrade evm-trace
antazoey Jun 15, 2022
6513b19
chore: Merge branch 'main' into feat/jules-show-trace
antazoey Jun 15, 2022
3542089
chore: rm emoji
antazoey Jun 15, 2022
3fb4f63
chore: rm accidental changes
antazoey Jun 15, 2022
9abac68
test: fix tests
antazoey Jun 15, 2022
69e5658
fix: allow overriding cached contracts for local
antazoey Jun 15, 2022
1f9c912
chore: Merge branch 'main' into feat/jules-show-trace
antazoey Jun 16, 2022
5658834
chore: merge main
antazoey Jun 16, 2022
8bfe27e
refactor: make show_trace an api method
antazoey Jun 16, 2022
9013560
chore: resolve conflicts and update eg trace
antazoey Jun 16, 2022
30e2da7
feat: raises not implemented
antazoey Jun 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ repos:
- id: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.950
rev: v0.961
hooks:
- id: mypy
additional_dependencies: [types-PyYAML, types-requests]
Expand Down
16 changes: 16 additions & 0 deletions docs/methoddocs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,22 @@
:show-inheritance:
```

## Transactions

```{eval-rst}
.. autoclass:: ape.api.transactions.ReceiptAPI
:members:
:show-inheritance:
:exclude-members: __repr__, __weakref__, __metaclass__, __init__
```

```{eval-rst}
.. autoclass:: ape.api.transactions.TransactionAPI
:members:
:show-inheritance:
:exclude-members: __repr__, __weakref__, __metaclass__, __init__
```

## Query

```{eval-rst}
Expand Down
84 changes: 84 additions & 0 deletions docs/userguides/transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,90 @@ In your `ape-config.yaml` file, add the following:
transaction_acceptance_timeout: 600 # 5 minutes
```

## Traces

If you are using a provider that is able to fetch transaction traces, such as the [ape-hardhat](https://github.com/ApeWorX/ape-hardhat) provider, you can call the [`ReceiptAPI.show_trace()`](../methoddocs/api.html?highlight=receiptapi#ape.api.transactions.ReceiptAPI.show_trace) method.
antazoey marked this conversation as resolved.
Show resolved Hide resolved

```python
from ape import accounts, project

owner = accounts.load("acct")
contract = project.Contract.deploy(sender=owner)
receipt = contract.methodWithoutArguments()
receipt.show_trace()
```

**NOTE**: If your provider does not support traces, you will see a `NotImplementedError` saying that the method is not supported.

The trace might look something like:

```bash
Call trace for '0x43abb1fdadfdae68f84ce8cd2582af6ab02412f686ee2544aa998db662a5ef50'
txn.origin=0x1e59ce931B4CFea3fe4B875411e280e173cB7A9C
ContractA.methodWithoutArguments() -> 0x00..7a9c [469604 gas]
├── SYMBOL.supercluster(x=234444) -> [
│ [23523523235235, 11111111111, 234444],
│ [
│ 345345347789999991,
│ 99999998888882,
│ 345457847457457458457457457
│ ],
│ [234444, 92222229999998888882, 3454],
│ [
│ 111145345347789999991,
│ 333399998888882,
│ 234545457847457457458457457457
│ ]
│ ] [461506 gas]
├── SYMBOL.methodB1(lolol="ice-cream", dynamo=345457847457457458457457457) [402067 gas]
│ ├── ContractC.getSomeList() -> [
│ │ 3425311345134513461345134534531452345,
│ │ 111344445534535353,
│ │ 993453434534534534534977788884443333
│ │ ] [370103 gas]
│ └── ContractC.methodC1(
│ windows95="simpler",
│ jamaica=345457847457457458457457457,
│ cardinal=ContractA
│ ) [363869 gas]
├── SYMBOL.callMe(blue=tx.origin) -> tx.origin [233432 gas]
├── SYMBOL.methodB2(trombone=tx.origin) [231951 gas]
│ ├── ContractC.paperwork(ContractA) -> (
│ │ os="simpler",
│ │ country=345457847457457458457457457,
│ │ wings=ContractA
│ │ ) [227360 gas]
│ ├── ContractC.methodC1(windows95="simpler", jamaica=0, cardinal=ContractC) [222263 gas]
│ ├── ContractC.methodC2() [147236 gas]
│ └── ContractC.methodC2() [122016 gas]
├── ContractC.addressToValue(tx.origin) -> 0 [100305 gas]
├── SYMBOL.bandPractice(tx.origin) -> 0 [94270 gas]
├── SYMBOL.methodB1(lolol="lemondrop", dynamo=0) [92321 gas]
│ ├── ContractC.getSomeList() -> [
│ │ 3425311345134513461345134534531452345,
│ │ 111344445534535353,
│ │ 993453434534534534534977788884443333
│ │ ] [86501 gas]
│ └── ContractC.methodC1(windows95="simpler", jamaica=0, cardinal=ContractA) [82729 gas]
└── SYMBOL.methodB1(lolol="snitches_get_stiches", dynamo=111) [55252 gas]
├── ContractC.getSomeList() -> [
│ 3425311345134513461345134534531452345,
│ 111344445534535353,
│ 993453434534534534534977788884443333
│ ] [52079 gas]
└── ContractC.methodC1(windows95="simpler", jamaica=111, cardinal=ContractA) [48306 gas]
```

Additionally, you can view the traces of other transactions on your network.

```python
from ape import networks

txn_hash = "0x053cba5c12172654d894f66d5670bab6215517a94189a9ffc09bc40a589ec04d"
receipt = networks.provider.get_transaction(txn_hash)
receipt.show_trace()
```

## Estimate Fees

To estimate the fees on a transaction without sending it, use the `as_transaction()` method to get a reference to a transaction API object.
Expand Down
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ exclude =
per-file-ignores =
# Need signal handler before imports
src/ape/__init__.py: E402
# Test data causes long lines
tests/functional/data/python/__init__.py: E501
tests/functional/utils/expected_traces.py: E501
16 changes: 8 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
],
"lint": [
"black>=22.3.0,<23.0", # auto-formatter and linter
"mypy>=0.950,<1.0", # Static type analyzer
"mypy>=0.961,<1.0", # Static type analyzer
"types-PyYAML", # NOTE: Needed due to mypy typeshed
"types-requests", # NOTE: Needed due to mypy typeshed
"flake8>=4.0.1,<5.0", # Style linter
Expand Down Expand Up @@ -93,9 +93,8 @@
install_requires=[
"backports.cached_property ; python_version<'3.8'",
"click>=8.1.0",
"eth-account==0.5.7",
"ethpm-types>=0.3.1,<0.4.0",
"evm-trace>=0.1.0.a2",
"ethpm-types>=0.3.2,<0.4.0",
"evm-trace>=0.1.0.a6",
"hexbytes>=0.2.2,<1.0.0",
"packaging>=20.9,<21.0",
"pandas>=1.3.0,<2.0",
Expand All @@ -113,11 +112,12 @@
"rich>=10.14,<11",
"tqdm>=4.62.3,<5.0",
"typing-extensions ; python_version<'3.8'",
"web3[tester]>=5.29.0,<6.0",
"eth_abi==2.1.1",
"eth-utils==1.10.0",
"eth-rlp==0.2.1",
"python-dateutil>=2.8.2,<3.0",
"web3[tester]>=5.29.0,<6.0",
"eth-abi>=2.1.1,<3.0",
"eth-utils>=1.10.0,<2.0",
"eth-rlp>=0.2.1,<0.3",
"eth-account==0.5.7",
],
entry_points={
"console_scripts": ["ape=ape._cli:cli"],
Expand Down
22 changes: 20 additions & 2 deletions src/ape/api/networks.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from functools import partial
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Type
from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Tuple, Type, Union

from ethpm_types.abi import ConstructorABI, EventABI, MethodABI
from hexbytes import HexBytes
from pydantic import BaseModel

from ape.exceptions import NetworkError, NetworkNotFoundError
from ape.types import AddressType, ContractLog, RawAddress
from ape.utils import BaseInterfaceModel, abstractmethod, cached_property
from ape.utils import BaseInterfaceModel, abstractmethod, cached_property, raises_not_implemented

from .config import PluginConfig

Expand Down Expand Up @@ -287,6 +287,24 @@ def decode_logs(self, abi: EventABI, raw_logs: List[Dict]) -> Iterator[ContractL
Iterator[:class:`~ape.types.ContractLog`]
"""

@raises_not_implemented
def decode_primitive_value(
self, value: Any, output_type: Union[str, Tuple, List]
) -> Union[str, HexBytes, Tuple]:
"""
Decode a primitive value-type given its ABI type as a ``str``
and the value itself. This method is a hook for converting
addresses, HexBytes, or other primitive data-types into
friendlier Python equivalents.

Args:
value (Any): The value to decode.
output_type (Union[str, Tuple, List]): The value type.

Returns:
Union[str, HexBytes, Tuple]
"""

@abstractmethod
def create_transaction(self, **kwargs) -> "TransactionAPI":
"""
Expand Down
41 changes: 35 additions & 6 deletions src/ape/api/transactions.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import sys
import time
from typing import TYPE_CHECKING, Iterator, List, Optional, Union
from typing import IO, TYPE_CHECKING, Iterator, List, Optional, Union

from ethpm_types import HexBytes
from ethpm_types.abi import EventABI
from evm_trace import TraceFrame
from pydantic.fields import Field
from tqdm import tqdm # type: ignore

from ape.api.explorers import ExplorerAPI
from ape.exceptions import TransactionError
from ape.logging import logger
from ape.types import ContractLog, TransactionSignature
from ape.utils import BaseInterfaceModel, abstractmethod
from ape.utils import BaseInterfaceModel, abstractmethod, cached_iterator, raises_not_implemented

if TYPE_CHECKING:
from ape.contracts import ContractEvent
Expand Down Expand Up @@ -148,7 +150,6 @@ class ReceiptAPI(BaseInterfaceModel):
gas_limit: int
gas_price: int
gas_used: int
input_data: str = ""
logs: List[dict] = []
nonce: Optional[int] = None
receiver: str
Expand All @@ -161,12 +162,16 @@ class ReceiptAPI(BaseInterfaceModel):
def __repr__(self) -> str:
return f"<{self.__class__.__name__} {self.txn_hash}>"

def raise_for_status(self):
@property
def failed(self) -> bool:
"""
Handle provider-specific errors regarding a non-successful
:class:`~api.providers.TransactionStatusEnum`.
Whether the receipt represents a failing transaction.
Ecosystem plugins override this property when their receipts
are able to be failing.
"""

return False

@property
@abstractmethod
def ran_out_of_gas(self) -> bool:
Expand All @@ -178,6 +183,13 @@ def ran_out_of_gas(self) -> bool:
same amount of gas as the given ``gas_limit``.
"""

@cached_iterator
def trace(self) -> Iterator[TraceFrame]:
"""
The trace of the transaction, if available from your provider.
"""
return self.provider.get_transaction_trace(txn_hash=self.txn_hash)
fubuloubu marked this conversation as resolved.
Show resolved Hide resolved

@property
def _explorer(self) -> Optional[ExplorerAPI]:
return self.provider.network.explorer
Expand All @@ -195,6 +207,12 @@ def _confirmations_occurred(self) -> int:

return latest_block.number - self.block_number

def raise_for_status(self):
"""
Handle provider-specific errors regarding a non-successful
:class:`~api.providers.TransactionStatusEnum`.
"""

def decode_logs(self, abi: Union[EventABI, "ContractEvent"]) -> Iterator[ContractLog]:
"""
Decode the logs on the receipt.
Expand Down Expand Up @@ -266,3 +284,14 @@ def await_confirmations(self) -> "ReceiptAPI":
time.sleep(time_to_sleep)

return self

@raises_not_implemented
def show_trace(self, verbose: bool = False, file: IO[str] = sys.stdout):
"""
Display the complete sequence of contracts and methods called during
the transaction.

Args:
verbose (bool): Set to ``True`` to include more information.
file (IO[str]): The file to send output to. Defaults to stdout.
"""
8 changes: 5 additions & 3 deletions src/ape/managers/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,8 @@ def __setitem__(self, address: AddressType, contract_type: ContractType):
contract_type (ContractType): The contract's type.
"""

if self.get(address):
return # Already cached
if self.get(address) and self._is_live_network:
return

self._local_contracts[address] = contract_type

Expand Down Expand Up @@ -432,10 +432,12 @@ def get(

Args:
address (AddressType): The address of the contract.
default (Optional[ContractType]): A default contract when none is found.
Defaults to ``None``.

Returns:
Optional[ContractType]: The contract type if it was able to get one,
otherwise ``None``.
otherwise the default parameter.
"""

contract_type = self._local_contracts.get(address)
Expand Down
2 changes: 1 addition & 1 deletion src/ape/managers/project/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class LocalDependency(DependencyAPI):

@property
def path(self) -> Path:
given_path = Path(self.local)
given_path = Path(self.local).absolute()
if not given_path.exists():
raise ProjectError(f"No project exists at path '{given_path}'.")

Expand Down
Loading