TRON Virtual Machine (TVM)

The TRON Virtual Machine is the deterministic, stack-based runtime that executes smart-contract code on every TRON node — the chain's state-transition function for the smart-contract layer.

📘

Prerequisites

The TRON Virtual Machine (TVM) is the runtime environment for TRON smart contracts. Each node in the network maintains a TVM instance. The TRON protocol keeps the continuous, uninterrupted, and immutable operation of this state machine. At any given block in the chain, TRON has one and only one canonical state, and the TVM defines the rules for computing a new valid state from one block to the next.

From ledger to state machine

The analogy of a "distributed ledger" is often used to describe blockchains like Bitcoin, which enables a decentralized currency using fundamental tools of cryptography. A native token on a blockchain behaves like a regular currency by following rules that govern what can and cannot be done to modify the ledger — for example, an address cannot spend more than it has previously received. These rules underpin all transactions.

TRON has its own native token TRX that follows the same intuitive rules, but TRON also enables a more powerful functionality: smart contracts. Instead of a simple distributed ledger, TRON is a distributed state machine. TRON's state is a large data structure that holds not only all account information, but also a machine state, which can change from block to block according to a pre-defined set of rules and can execute arbitrary bytecode.

State transition function

The TVM behaves like a mathematical function: given an input, it produces a deterministic output. TRON can therefore be described formally as having a state transition function:

Y(S, T) = S'

Given an old valid state S and a new set of valid transactions T, the TRON state transition function Y(S, T) produces a new valid output state S'.

A core protocol invariant follows from this: every node must reproduce the same S' given the same (S, T). The TVM is the part of TRON that guarantees this for smart-contract execution — every opcode is specified to produce identical results on every implementation, with no source of nondeterminism (no wall-clock reads, no thread scheduling, no floating-point arithmetic).

State

The TRON world state maps accounts to their balances, contract code and storage, resources, and permissions.

Each account has:

  • Balance — TRX held by the account, in sun.
  • Code — bytecode (only set for contract accounts).
  • Storage — a 256-bit-key → 256-bit-value mapping (only used by contract accounts).
  • Resource state — Bandwidth and Energy accounting (see Resource Model).
  • Permissions — owner / active / witness permission sets (see Account Permission Management).

TRON distinguishes two account categories: EOAs (externally owned accounts, controlled by a private key) and contract accounts (controlled by their deployed bytecode). Only contract accounts have non-empty code and storage. For the full account model and address formats, see Accounts and keys.

📘

Replay protection without a nonce

TRON accounts do not have a nonce field for replay protection. Replay protection is provided by TAPOS — a transaction references a recent block ID and expires 60 seconds later by default.

Transactions

Transactions are cryptographically signed instructions from accounts. They divide into two categories:

  • System contract transactions — built-in operations such as TRX transfers (TransferContract), TRC-10 issuance and transfer, voting, and staking. These are executed by per-type actuators in actuator/src/main/java/org/tron/core/actuator/ and do not enter the TVM.
  • Smart contract transactions — CreateSmartContract (deploying new bytecode) and TriggerSmartContract (invoking an existing contract). These are the only transactions that invoke the TVM. They are handled by VMActuator.

Contract creation generates a new contract account containing compiled smart-contract bytecode. Whenever another account makes a message call to that contract, the corresponding bytecode runs on the TVM.

For the full transaction structure and contract-type list, see Transactions and System contract types.

Execution context

Each TVM execution runs in a layered context. From outside in:

  1. World state — the parent block's ending state plus changes already made by earlier transactions in the current block. The TVM reads from and writes to this working state through the host interface.
  2. Block context — the block header being assembled (number, timestamp, witness, block hash). Available to bytecode via NUMBER (0x43), TIMESTAMP (0x42), COINBASE (0x41), BLOCKHASH (0x40), CHAINID (0x46).
  3. Transaction context — the signed TriggerSmartContract / CreateSmartContract transaction. Available via ORIGIN (0x32), GASPRICE (0x3A, returns the chain's energyPrice).
  4. Message call context (call frame) — the current invocation, pushed when one contract calls another. Each frame carries its own caller, value, callData, code, pc, operand stack, and volatile memory. Call frames nest up to the depth limit below.

Cross-frame state passes only through explicit return data and storage writes; there is no shared memory across calls.

TVM instructions

The TVM is a stack machine. Two distinct stacks bound execution and should not be confused:

  • Operand stack — holds up to 1,024 values, each 256 bits long. Instructions such as PUSH, POP, DUP, and SWAP operate on these values.
  • Call stack — limits nested contract calls, including recursive self-calls, to 64 levels. At the limit, a new low-level call returns failure. The calling contract determines whether to revert; see VM exception handling.

Compiled smart contract bytecode runs as a sequence of TVM opcodes, which perform standard stack operations like XOR, AND, ADD, and SUB. The TVM also implements blockchain-specific stack operations such as ADDRESS, BALANCE, and BLOCKHASH. For the full opcode reference, see Opcodes; for the underlying source, see the java-tron Op.java file.

The flow of a single contract call is:

  1. The Solidity compiler compiles the source contract into bytecode that the TVM can execute.
  2. The TVM processes the bytecode opcode by opcode, deterministically on every node.
  3. When an opcode needs blockchain data (account balances, current block, storage), the TVM accesses it through the host interface.
  4. When execution finishes, the result and status are written into the block; the caller queries them through the HTTP API.

Memory and storage

Each call frame has three separate data regions, each with different lifetime and cost semantics:

RegionLifetimeAddressingCost model
Stackper call frametop-of-stack onlyper-opcode flat cost
Memoryper call frame (volatile)byte-addressablelinear up to 724 bytes, quadratic above; capped at 3 MiB
Storagepersists across transactions256-bit key → 256-bit valueSET_SSTORE 20,000 / RESET_SSTORE 5,000 per write — see Opcodes appendix A7

Each contract call can use up to 3 MiB of memory. Exceeding this limit causes OUT_OF_ENERGY. Contracts that allocate large amounts of memory may therefore need changes when migrating from Ethereum, where memory growth is limited by Gas cost rather than a fixed capacity.

Storage is per-contract: contract A cannot read or write the slots of contract B except through B's externally callable functions.

Halting, exceptions, and protocol limits

The execution result is recorded in receipt.result. Common results fall into three categories; see System contract types for the full result list:

  • SUCCESS — bytecode reached STOP, RETURN, or SELFDESTRUCT cleanly.
  • REVERT — bytecode executed a REVERT opcode (also triggered by Solidity require / custom errors). Remaining Energy is refunded; state changes from the failed call are rolled back.
  • Exceptional halt — execution consumes all available Energy and rolls back state. Categories include:
    • OUT_OF_ENERGY — Energy budget exhausted.
    • OUT_OF_TIME — execution exceeded the per-transaction CPU time limit, or a specific protocol check triggered the result directly.
    • STACK_TOO_LARGE (operand stack overflow), STACK_TOO_SMALL (underflow).
    • JVM_STACK_OVER_FLOW — the Java Virtual Machine (JVM) call stack overflows while the node executes a contract.
    • BAD_JUMP_DESTINATION, ILLEGAL_OPERATION, INVALID_CODE.
    • PRECOMPILED_CONTRACT — error inside a precompiled contract.
    • TRANSFER_FAILED — internal TRX or TRC-10 transfer failed.

Once the contract call-depth limit is reached, no further nested contract call can be made. For a call such as otherContract.someFunction(), failure reverts the caller's current execution by default; the caller can instead use try/catch to handle the failure and continue. Low-level calls such as call return a failure result without automatically reverting the caller, so the contract must check the result and handle the failure.

The 80 ms execution cap is unique to TRON — the EVM does not bound execution by wall-clock time, only by gas. The cap can be bypassed on private chains via the --debug CLI flag, but doing so on a Mainnet-syncing node produces different resultCode sync failures.

For handling these conditions in Solidity, see VM exception handling.

Energy metering

Every opcode consumes a fixed or computed amount of Energy, charged before the opcode executes. The TVM is the only part of TRON that consumes Energy — system contracts pay Bandwidth instead.

For a contract call, the total execution budget is the caller's Energy limit plus the deployer's actual contribution. The caller's limit is derived by converting fee_limit from sun to Energy at the current Energy price, then applying the caller's available Energy and TRX balance constraints. The deployer's contribution is separately limited by the contract's consume_user_resource_percent, the deployer's available Energy, and origin_energy_limit.

For the full Energy-cost model, see FeeLimit & Energy cost; for the Resource Model that underlies Energy and Bandwidth, see Resource Model.

Compiler and instruction compatibility

When choosing a Solidity compiler version and compilation settings, check that the target network supports the TVM instructions generated by the compiler. Executing an instruction that has not been enabled results in ILLEGAL_OPERATION. For supported instructions and how to check their availability, see TVM vs EVM.

TVM in java-tron

The reference implementation lives entirely in the actuator and chainbase modules. Useful entry points for contributors and node operators:

FileRole
actuator/.../vm/VMActuator.javaEntry point: validates contract-call / contract-create transactions, sets up the execution context
actuator/.../vm/program/Program.javaExecution frame: operand stack, call depth, memory, suicide / call helpers
actuator/.../vm/Op.javaCanonical opcode table (0x00 … 0xff)
actuator/.../vm/OperationActions.javaOpcode implementations (what each opcode does to the stack and host state)
actuator/.../vm/EnergyCost.javaPer-opcode Energy cost functions, memory cap, SSTORE rules
actuator/.../vm/PrecompiledContracts.javaPrecompile implementations (0x01–0x0a and the TRON-specific 0x1000005–0x1000015)
actuator/.../vm/config/VMConfig.javaReads chain-parameter gates that toggle hardfork features and per-opcode behavior

Related resources