Understanding Traces
Forge can produce traces either for failing tests (-vvv
) or all tests (-vvvv
).
Traces follow the same general format:
[<Gas Usage>] <Contract>::<Function>(<Parameters>)
ββ [<Gas Usage>] <Contract>::<Function>(<Parameters>)
β ββ β <Return Value>
ββ β <Return Value>
Each trace can have many more subtraces, each denoting a call to a contract and a return value.
If your terminal supports color, the traces will also come with a variety of colors:
- Green: For calls that do not revert
- Red: For reverting calls
- Blue: For calls to cheat codes
- Cyan: For emitted logs
- Yellow: For contract deployments
The gas usage (marked in square brackets) is for the entirety of the function call. You may notice, however, that sometimes the gas usage of one trace does not exactly match the gas usage of all its subtraces:
[24661] OwnerUpOnlyTest::testIncrementAsOwner()
ββ [2262] OwnerUpOnly::count()
β ββ β 0
ββ [20398] OwnerUpOnly::increment()
β ββ β ()
ββ [262] OwnerUpOnly::count()
β ββ β 1
ββ β ()
The gas unaccounted for is due to some extra operations happening between calls, such as arithmetic and store reads/writes.
Forge will try to decode as many signatures and values as possible, but sometimes this is not possible. In these cases, the traces will appear like so:
[<Gas Usage>] <Address>::<Calldata>
ββ β <Return Data>
Some traces might be harder to grasp at first glance. These include:
- The
OOG
shorthand stands for βOut Of Gasβ. - The acronym
EOF
stands for βEthereum Object Formatβ, which introduces an extensible and versioned container format for EVM bytecode. For more information, read here. NotActivated
means the feature or opcode is not activated. Some versions of the EVM only support certain opcodes. You may need to use a more recent version usign the--evm_version
flag. For example, thePUSH0
opcode is only available since the Shanghai hardfork.InvalidFEOpcode
means that an undefined bytecode value has been encountered during execution. The EVM catches the unknown bytecode and returns theINVALID
opcode instead, of value0xFE
. You can find out more here.
For a deeper insight into the various traces, you can explore the revm source code.
ZKsync Limitations
In addition to the above anomalies of incorrect gas and un-decodable traces, there are additional caveats within the ZKsync context:
- The events emitted from within the zkEVM will not show on traces. See events in zkEVM.
- The system call traces from within the zkEVMβs bootloader are currently ignored in order to simplify the trace output.
- Executing each
CREATE
orCALL
in its own zkEVM has additional bootloader gas costs, which may sometimes not be accounted in the traces. The ignored bootloader system calls, have a heuristic in-place to sum up their gas usage to the nearest non-system parent call, but this may also not add up accurately.