Docs
Testing

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:

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.

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:

terminal
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 match

Show decoded message bodies

With --show-bodies, Acton adds decoded fields under the transaction line.

Small bodies stay compact:

terminal
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:

terminal
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=309

How to read the main line

  • N/A -> sender A is 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.
  • FmRoute and FmDelivered are message names resolved from ABI opcodes. empty means an empty body. Unknown opcodes are printed as hex, for example 0x1.
  • 0.6 GRAM is the incoming message value for that transaction.
  • sender, fm_linear_root, and fm_linear_mid are display names for participants. When Acton knows a symbolic name, it prints that name. Otherwise, it falls back to a shortened address.
  • A, B, C are local aliases for addresses inside the current printed result. They make repeated participants easier to follow.
  • gas=1782 is compute gas usage for the transaction.
  • exit_code=63 means that compute phase failed with this exit code.
  • aborted means 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

terminal
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

terminal
N/A -> sender A
└── FmBouncePing 0.2 GRAM -> EQAAAA..ALrXfh B                          compute phase skipped aborted

compute 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

terminal
N/A -> external
└── ext-in FmExternalTrigger -> fm_external_root A                              gas=2757
    ├── ext-out FmExternalNoneDest -> none
    └── ext-out FmExternalAddressDest -> 0xa1b2c3d4 (32 bits)
  • ext-in is an external inbound message.
  • ext-out lines are external messages emitted by the transaction.
  • External destinations are shown either as none or as raw external address bytes.

Extra diagnostic lines

Transactions can print extra lines under the main row:

terminal
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 GRAM

Common extra lines:

  • account created and account destroyed show storage lifecycle changes.
  • Compute phase failed: ... explains a non-zero exit_code.
  • Action phase failed and action_result_code=... describe action-phase errors.
  • Decoded body fields may appear before child transactions when --show-bodies is enabled and ABI is known.
  • Executed actions: shows parsed out actions such as sendMsg and reserve.
  • 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") or net.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-bodies to print decoded message fields in the terminal tree.
  • Rerun with acton test --backtrace full for source locations on compute or action failures.
  • Switch to acton test --ui when the tree is too large for clickable transactions, fee tables, or grouped logs.

Last updated on

On this page