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 is a mapping from accounts to account data, maintained as a Merkle Patricia Trie so the full state is reducible to a single root hash stored on the blockchain.

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 transactionsCreateSmartContract (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 global account trie at the parent block. The TVM reads from and writes to this 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 — depth 1024. Each item is a 256-bit word, chosen for compatibility with 256-bit cryptography (such as Keccak-256 hashes and secp256k1 signatures). This is what PUSH / POP / DUP / SWAP operate on. Source: actuator/.../vm/program/Program.java:111 (MAX_STACK_SIZE = 1024).
  • Call stack — depth 64. Counts nested contract-to-contract calls (including recursive self-calls). Exceeding this depth throws a require-style exception — see VM exception handling. Source: Program.java:109 (MAX_DEPTH = 64).

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

The per-call memory cap is 3 MiB, enforced as MEM_LIMIT = 3 * 1024 * 1024 in actuator/.../vm/EnergyCost.java:26. Any opcode that grows memory beyond this limit halts execution with OUT_OF_ENERGY. This is a TVM-specific protocol limit; the EVM has no fixed memory cap and is bounded only by quadratic gas cost.

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

A TVM execution ends in one of three categories, recorded in receipt.result (16 enum values — see the receipt-result table in Tron.proto:393-411):

  • 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 — exceeded the 80 ms per-transaction execution budget (chain parameter #13 getMaxCpuTimeOfOneTx).
    • STACK_TOO_LARGE (operand stack overflow), STACK_TOO_SMALL (underflow), JVM_STACK_OVER_FLOW (call-frame overflow at the implementation level).
    • BAD_JUMP_DESTINATION, ILLEGAL_OPERATION, INVALID_CODE.
    • PRECOMPILED_CONTRACT — error inside a precompiled contract.
    • TRANSFER_FAILED — internal TRX or TRC-10 transfer failed.

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. The Energy budget for a single call is bounded by the smaller of:

  • The contract caller's fee_limit divided by the current energyPrice (chain param #11).
  • The deployer's origin_energy_limit.
  • The chain-wide maximum (chain param #47 getMaxFeeLimit, currently 15,000 TRX).

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

Hardfork model

The TVM tracks Ethereum hardforks incrementally. Each set of new opcodes is gated by a dedicated chain parameter — getAllowTvmConstantinople, getAllowTvmIstanbul, getAllowTvmLondon, getAllowTvmShangHai, getAllowTvmCancun, getAllowTvmBlob — flipped by SR committee proposals. Until the gate is enabled on a given network, the corresponding opcodes are treated as ILLEGAL_OPERATION. For the full hardfork matrix and which opcodes each adds, 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 (0x010x0a and the TRON-specific 0x10000050x1000015)
actuator/.../vm/config/VMConfig.javaReads chain-parameter gates that toggle hardfork features and per-opcode behavior

Related resources