Reading transaction chains
Understand the text trace format printed for transaction results and matcher failures
The result of net.send() and net.deploy() calls can be rendered as a text tree trace of transactions. The tree can be printed:
- By passing the result as an argument to the
println()function call; - Within failure diagnostics from transaction matchers such as
toHaveTx(),toHaveSuccessfulTx(), andtoHaveFailedTx().
This trace tree is a terminal counterpart of the traces formed in the Test UI.
To use matcher failures together with this trace, see built-in matchers and helpers for predicate-based transaction search, map helpers, and out-action helpers.
Decoded message bodies are hidden by default. To show parsed fields under transactions, run acton test --show-bodies or acton script ... --show-bodies. Acton prints them only when it knows the contract compiler ABI and can decode the payload completely.
Print a trace
Use println() with the result of the net.send() or net.deploy() call to render it as a text tree:
val txs = net.send(deployer.address, msg);
println(txs);Example output:
N/A -> sender A
└── FmRoute 0.6 GRAM -> fm_linear_root B gas=1782
└── FmDelivered 0.1996 GRAM -> fm_linear_mid C gas=435 exit_code=63 aborted
└── Compute phase failed: Unable to load data from cell because prefix does not matchShow decoded message bodies
With --show-bodies, Acton adds decoded fields under the transaction line.
Small bodies stay compact:
N/A -> sender A
└── FmKnownAddressBody 0.05 GRAM -> fm_known_address_sink B gas=333
queryId: 0, newAdminAddress: 0QDx... (not_deployer)Multi-line bodies use the continuation gutter │ so they stay visually attached to the transaction header even when child transactions follow:
N/A -> sender A
└── FmWrappedKnownAddressBody 0.05 GRAM -> fm_wrapped_known_address_sink B gas=1572
│ internalTransferMsg: {
│ queryId: 0
│ newAdminAddress: 0QDx... (not_deployer)
│ tonAmount: 1000000000
│ }
└── empty 0.0096 GRAM -> sender A gas=309How to read the main line
N/A -> sender Ais the entry into this printed trace. It is not a blockchain transaction by itself. It shows where the root transaction came from inside the current result list.- The
└──and├──lines show the parent-child transaction structure. A child line is produced by the parent transaction above it. FmRouteandFmDeliveredare message names resolved from ABI opcodes.emptymeans an empty body. Unknown opcodes are printed as hex, for example0x1.0.6 GRAMis the incoming message value for that transaction.sender,fm_linear_root, andfm_linear_midare display names for participants. When Acton knows a symbolic name, it prints that name. Otherwise, it falls back to a shortened address.A,B,Care local aliases for addresses inside the current printed result. They make repeated participants easier to follow.gas=1782is compute gas usage for the transaction.exit_code=63means that compute phase failed with this exit code.abortedmeans the transaction finished in aborted state.
The A, B, C aliases are local to one printed result. They are a reading aid, not stable identifiers across different runs.
Special markers
Bounced messages
N/A -> sender A
└── (!) empty 0.2 GRAM -> fm_bounce_echo B gas=271(!) marks a bounced internal message. For bounced messages, Acton often resolves the original opcode from the bounced body, so the original message name appears instead of a generic bounce wrapper.
Compute skipped
N/A -> sender A
└── FmBouncePing 0.2 GRAM -> EQAAAA..ALrXfh B compute phase skipped abortedcompute phase skipped means TVM compute did not run for this transaction. In practice, this usually means the message reached an account where only envelope-level processing happened, so the next step is to inspect the destination and message kind.
External input and output
N/A -> external
└── ext-in FmExternalTrigger -> fm_external_root A gas=2757
├── ext-out FmExternalNoneDest -> none
└── ext-out FmExternalAddressDest -> 0xa1b2c3d4 (32 bits)ext-inis an external inbound message.ext-outlines are external messages emitted by the transaction.- External destinations are shown either as
noneor as raw external address bytes.
Extra diagnostic lines
Transactions can print extra lines under the main row:
N/A -> sender A
└── empty 0.2 GRAM -> fm_action_fail B gas=2347 aborted action_result_code=37
├── account created
├── Action phase failed
├── Description: Not enough GRAM
├── Re-run with --backtrace full to get actions location
└── Executed actions:
├── reserve 0.1 GRAM BOUNCE_ON_ACTION_FAIL balance: 0.0990612 GRAM
└── msg: 46F9C0B8D15E2DAFE7CBE4C19A6E59C3... balance: 0 GRAMCommon extra lines:
account createdandaccount destroyedshow storage lifecycle changes.Compute phase failed: ...explains a non-zeroexit_code.Action phase failedandaction_result_code=...describe action-phase errors.- Decoded body fields may appear before child transactions when
--show-bodiesis enabled and ABI is known. Executed actions:shows parsed out actions such assendMsgandreserve.Re-run with --backtrace full ...means Acton can show source locations for failed actions or compute errors after enabling full backtraces.
Make traces easier to read
- Give treasuries explicit names with
testing.treasury("deployer"). - Name arbitrary addresses with
randomAddress("name")ornet.registerAddress(...). - Label not deployed or dynamically-created contracts with
net.registerCodeCell(...). - Use matcher failures as a focused debugger: when
expect(txs).toHaveSuccessfulTx({...})fails, Acton prints the same trace tree plus the exact search parameters that were not matched. - Rerun with
acton test --show-bodiesto print decoded message fields in the terminal tree. - Rerun with
acton test --backtrace fullfor source locations on compute or action failures. - Switch to
acton test --uiwhen the tree is too large for clickable transactions, fee tables, or grouped logs.
Last updated on