trace
Documentation for eth_defi.trace Python module.
Symbolic transaction tracing and human-readable Solidity stack traces.
This code is very preliminary and has not been througly tested with different smart contracts, so patches welcome
Internally use evm-trace library from Ape
Currently only works with Anvil (
eth_defi.anvil) backend
Functions
|
Make a Web3.call and if it fails get the Solidity stack trace. |
Checks if a transaction succeeds and give a verbose explanation why not.. |
|
|
Print a symbolic trace of an Ethereum transaction. |
|
Trace a Solidity function call. |
|
Trace a (failed) transaction. |
Classes
A EVM trace tree that can resolve contract names and functions. |
|
What kind of transaction tracing method we use. |
Exceptions
Tracing is not enabled on the backend. |
|
Exception thrown when unit test transaction asset fails. |
- exception TraceNotEnabled
Bases:
ExceptionTracing is not enabled on the backend.
- __init__(*args, **kwargs)
- __new__(**kwargs)
- add_note()
Exception.add_note(note) – add a note to the exception
- with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- exception TransactionAssertionError
Bases:
AssertionErrorException thrown when unit test transaction asset fails.
See
assert_transaction_success_with_explanation().- __init__(message, revert_reason='', solidity_stack_trace='')
- __new__(**kwargs)
- add_note()
Exception.add_note(note) – add a note to the exception
- with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- class TraceMethod
Bases:
enum.EnumWhat kind of transaction tracing method we use.
- geth = 'geth'
Use debug_traceTransaction
- parity = 'parity'
Use trace_transaction
- trace_evm_transaction(web3, tx_hash, trace_method=TraceMethod.parity)
Trace a (failed) transaction.
See
print_symbolic_trace()for usageExtract an EVM transaction stack trace from a node, using GoEthereum compatible debug_traceTransaction
Currently only works with Anvil backend and if steps_trace=True
- Parameters
web3 (web3.main.Web3) – Anvil connection
tx_hash (hexbytes.main.HexBytes | str) – Transaction to trace
trace_method (eth_defi.trace.TraceMethod) –
How to trace.
Choose between debug_traceTransaction and trace_transaction RPCs.
- Return type
evm_trace.base.CallTreeNode
- trace_evm_call(web3, tx, trace_method=TraceMethod.parity, block_reference='latest')
Trace a Solidity function call.
See
print_symbolic_trace()for usageExtract an EVM transaction stack trace from a node, using GoEthereum compatible debug_traceTransaction
Currently only works with Anvil backend and if steps_trace=True
Warning
Currently not implemented. Anvil does not support trace_call RPC yet.
- Parameters
web3 (web3.main.Web3) – Anvil connection
tx (dict) – Transaction object for the call
trace_method (eth_defi.trace.TraceMethod) –
How to trace.
Choose between debug_traceTransaction and trace_transaction RPCs.
- Return type
evm_trace.base.CallTreeNode
- print_symbolic_trace(contract_registry, calltree)
Print a symbolic trace of an Ethereum transaction.
Contracts by name
Functions by name
Notes about tracing:
Currently only works with Anvil backend and if steps_trace=True
Transaction must have its gas parameter set, otherwise transaction is never broadcasted because it fails in estimate gas phase
Example output:
E AssertionError: Transaction failed: AttributeDict({'hash': HexBytes('0xaa70b2f76ad9f32f7c722390535d5a806b4d815f3d8d460e5d18cdba3b1c8c2d'), 'nonce': 2, 'blockHash': HexBytes('0x1d2a1d36185bebb373639e1eb4ddbe9f7f3347fa6dd7bcbbe5e5905fe6a1f4ed'), 'blockNumber': 3, 'transactionIndex': 0, 'from': '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', 'to': '0x5FbDB2315678afecb367f032d93F642f64180aa3', 'value': 0, 'gasPrice': 768647811, 'gas': 500000, 'input': '0x25ad8c83000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512', 'v': 1, 'r': HexBytes('0x43336f08be93aec7ecf456c724d3c29c6cebc589ab3fe6199ee783a627bbcda8'), 's': HexBytes('0x74002a6cdd84b81932e36ac0725591460b09eaaa6b0dd615c0c5d43171467c8a'), 'type': 2, 'accessList': [], 'maxPriorityFeePerGas': 0, 'maxFeePerGas': 1768647811, 'chainId': 31337}) E Revert reason: execution reverted: Big bada boom E Solidity stack trace: E CALL: RevertTest.revert2(second=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512) [3284 gas] E └── CALL: RevertTest2.boom() [230 gas]See also
eth_defi.anvil.launch_anvil().
Usage example:
reverter = deploy_contract(web3, "RevertTest.json", deployer) tx_hash = reverter.functions.revert1().transact({"from": deployer, "gas": 500_000}) receipt = web3.eth.wait_for_transaction_receipt(tx_hash) assert receipt["status"] == 0 # Tx failed # Get the debug trace from the node and transform it to a list of call items trace_data = trace_evm_transaction(web3, tx_hash) # Transform the list of call items to a human-readable output, # use ABI data from deployed contracts to enrich the output trace_output = print_symbolic_trace(get_or_create_contract_registry(web3), trace_data) assert trace_output == "CALL: [reverted] RevertTest.<revert1> [500000 gas]"
- Parameters
contract_registry (Dict[str, web3.contract.contract.Contract]) –
The registered contracts for which we have symbolic information available.
See
eth_defi.deploy.deploy_contract()for registering. All contracts deployed using this function should be registered by default.calltree (evm_trace.base.CallTreeNode) –
Call tree output.
From
trace_evm_transaction().
- Returns
Unicode print output
- assert_transaction_success_with_explanation(web3, tx_hash, RaisedException=<class 'eth_defi.trace.TransactionAssertionError'>, tracing=False, func=None, timeout=120.0)
Checks if a transaction succeeds and give a verbose explanation why not..
Designed to be used on Anvil backend based tests.
If it’s a failure then print
The revert reason string
Solidity stack trace where the transaction reverted
Example usage:
tx_hash = contract.functions.myFunction().transact({"from": fund_owner, "gas": 1_000_000}) assert_transaction_success_with_explaination(web3, tx_hash)
Example output:
E AssertionError: Transaction failed: AttributeDict({'hash': HexBytes('0xaa70b2f76ad9f32f7c722390535d5a806b4d815f3d8d460e5d18cdba3b1c8c2d'), 'nonce': 2, 'blockHash': HexBytes('0x1d2a1d36185bebb373639e1eb4ddbe9f7f3347fa6dd7bcbbe5e5905fe6a1f4ed'), 'blockNumber': 3, 'transactionIndex': 0, 'from': '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', 'to': '0x5FbDB2315678afecb367f032d93F642f64180aa3', 'value': 0, 'gasPrice': 768647811, 'gas': 500000, 'input': '0x25ad8c83000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512', 'v': 1, 'r': HexBytes('0x43336f08be93aec7ecf456c724d3c29c6cebc589ab3fe6199ee783a627bbcda8'), 's': HexBytes('0x74002a6cdd84b81932e36ac0725591460b09eaaa6b0dd615c0c5d43171467c8a'), 'type': 2, 'accessList': [], 'maxPriorityFeePerGas': 0, 'maxFeePerGas': 1768647811, 'chainId': 31337}) E Revert reason: execution reverted: Big bada boom E Solidity stack trace: E CALL: RevertTest.revert2(second=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512) [3284 gas] E └── CALL: RevertTest2.boom() [230 gas]You can also pass Web3
ContractFunctioninstance for more information:# Settle deposit queue 9 USDC -> 0 USDC settle_func = vault.settle_via_trading_strategy_module() tx_hash = settle_func.transact({ "from": asset_manager, "gas": 1_000_000, }) assert_transaction_success_with_explanation(web3, tx_hash, func=settle_func)
See also
print_symbolic_trace().Note
TODO: Currently does not work with failed contract deployment transactions.
- Parameters
web3 (web3.main.Web3) – Web3 instance
tx_hash (hexbytes.main.HexBytes | str) –
A transaction (mined/not mined) we want to make sure has succeeded.
Gas limit must have been set for this transaction.
RaisedException – Raise a custom exception instead of
TransactionAssertionError.tracing (bool) – Force turn on transaction tracing to use in e.g testing.
func (web3.contract.contract.ContractFunction) –
Bound ContractFunction instance with arguments.
Used for diagnostics and exception messages only.
timeout (float) – How long to wait for the transaction receipt, seconds.
- Raises
TransactionAssertionError – Outputs a verbose AssertionError on what went wrong.
- Return tx_receipt
Output transaction receipt if no error is raised
- Return type
web3.types.TxReceipt
- assert_call_success_with_explanation(func, transaction=None)
Make a Web3.call and if it fails get the Solidity stack trace.
We do debug_traceCall first to see if the call fails
If it does not fail we do the actual eth_call
Note
Because Anvil does not support trace_call yet, we just do this as sending the transaction. We assume the call does not change any state. See notes in
trace_evm_call().If not gas given, assume 1,000,000 gas units.
- Parameters
func (web3.contract.contract.ContractFunction) – Prepared
ContractFunctioncall.transaction (Optional[web3.types.TxParams]) – Transactional parameters for the call, like gas limit and sender.
- Raises
TransactionAssertionError – Outputs a verbose AssertionError on what went wrong.
- Returns
Same results as you would have with func.call(transaction)
- Return type
- class SymbolicTreeRepresentation
Bases:
objectA EVM trace tree that can resolve contract names and functions.
Lifted from eth_trace.display module.
See
print_symbolic_trace()for more information.