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 nonceTRON 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 inactuator/src/main/java/org/tron/core/actuator/and do not enter the TVM. - Smart contract transactions —
CreateSmartContract(deploying new bytecode) andTriggerSmartContract(invoking an existing contract). These are the only transactions that invoke the TVM. They are handled byVMActuator.
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:
- World state — the global account trie at the parent block. The TVM reads from and writes to this state through the host interface.
- 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). - Transaction context — the signed
TriggerSmartContract/CreateSmartContracttransaction. Available viaORIGIN(0x32),GASPRICE(0x3A, returns the chain'senergyPrice). - 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/SWAPoperate 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:
- The Solidity compiler compiles the source contract into bytecode that the TVM can execute.
- The TVM processes the bytecode opcode by opcode, deterministically on every node.
- When an opcode needs blockchain data (account balances, current block, storage), the TVM accesses it through the host interface.
- 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:
| Region | Lifetime | Addressing | Cost model |
|---|---|---|---|
| Stack | per call frame | top-of-stack only | per-opcode flat cost |
| Memory | per call frame (volatile) | byte-addressable | linear up to 724 bytes, quadratic above; capped at 3 MiB |
| Storage | persists across transactions | 256-bit key → 256-bit value | SET_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 reachedSTOP,RETURN, orSELFDESTRUCTcleanly.REVERT— bytecode executed aREVERTopcode (also triggered by Solidityrequire/ 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#13getMaxCpuTimeOfOneTx).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_limitdivided by the currentenergyPrice(chain param#11). - The deployer's
origin_energy_limit. - The chain-wide maximum (chain param
#47getMaxFeeLimit, 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:
| File | Role |
|---|---|
actuator/.../vm/VMActuator.java | Entry point: validates contract-call / contract-create transactions, sets up the execution context |
actuator/.../vm/program/Program.java | Execution frame: operand stack, call depth, memory, suicide / call helpers |
actuator/.../vm/Op.java | Canonical opcode table (0x00 … 0xff) |
actuator/.../vm/OperationActions.java | Opcode implementations (what each opcode does to the stack and host state) |
actuator/.../vm/EnergyCost.java | Per-opcode Energy cost functions, memory cap, SSTORE rules |
actuator/.../vm/PrecompiledContracts.java | Precompile implementations (0x01–0x0a and the TRON-specific 0x1000005–0x1000015) |
actuator/.../vm/config/VMConfig.java | Reads chain-parameter gates that toggle hardfork features and per-opcode behavior |
Related resources
- Opcodes — full TVM opcode reference
- TVM vs EVM — compatibility differences between the TVM and Ethereum's EVM
- Solidity on TRON — supported Solidity versions and TRON-specific language features
- Smart contracts introduction — what smart contracts are
- Resource Model — Bandwidth and Energy
- VM exception handling — exception types and Solidity error-handling patterns
Updated about 19 hours ago