TRON 虚拟机 (TVM)
TRON 虚拟机 (TVM) 是每个 TRON 节点执行智能合约的确定性运行时,也是智能合约层的状态转换函数。
前置阅读
TRON 虚拟机(TVM, TRON Virtual Machine)是 TRON 智能合约的执行环境。每个节点在处理合约部署或合约调用交易时,都会在本地运行同一套 TVM 规则;只要输入的父状态和交易集合相同,所有节点必须得到完全一致的新状态。
因此,TVM 不只是“运行 Solidity 字节码”的组件。它定义了智能合约如何读取账户、区块和交易上下文,如何消耗能量,如何写入存储,以及出现 REVERT、OUT_OF_ENERGY、OUT_OF_TIME 等结果时如何回滚状态。
从账本到状态机
“分布式账本”常用于描述比特币一类区块链:账户或地址围绕资产余额展开,交易只是在账本中转移价值。 TRON 同样有原生资产 TRX,也遵循余额不能凭空支出的基本规则,但 TRON 的链上状态不止余额。
在 TRON 中,状态包含账户余额、合约字节码、合约存储、资源使用量、权限配置等数据。智能合约交易会读取这些数据,并按照字节码逻辑生成新的状态。换句话说, TRON 是一个分布式状态机;TVM 是智能合约层的状态转换引擎。
状态转换函数
TVM 的核心约束是确定性。给定旧状态 S 和一组有效交易 T,节点执行后必须得到同一个新状态 S':
Y(S, T) = S'这个公式背后的协议要求很直接:任何节点只要看到相同的 S 和 T,就必须复现同一个 S'。TVM 因此不能依赖本地时钟、线程调度、浮点数等非确定性来源;每个 opcode 的行为都必须在所有节点上保持一致。
全局状态
TRON 的全局状态可以理解为“地址到账户数据”的映射。账户数据通常包括:
- 余额:账户持有的 TRX,单位为
sun。 - 代码:合约账户持有的已部署字节码。
- 存储:合约账户持久化保存的键值数据。
- 资源状态:带宽、能量以及相关恢复状态,参见资源模型。
- 权限:Owner、Active、Witness 等权限配置,参见账户权限管理。
TRON 区分两类账户:外部账户(EOA)由私钥控制,合约账户由已部署字节码控制。只有合约账户拥有非空的 code 和 storage。地址格式和账户派生过程参见账户与密钥。
注意TRON 账户没有用于防重放的 nonce 字段。交易防重放依赖 TAPOS:交易会引用近期区块 ID,并在构建后的一段时间内过期。
哪些交易会进入 TVM
TRON 交易大致分为两类:
- 系统合约交易:TRX 转账、TRC-10 Token 发行与转账、投票、质押、资源代理等协议内置操作。这类交易由对应的系统合约逻辑处理,不进入 TVM。
- 智能合约交易:
CreateSmartContract用于部署新合约,TriggerSmartContract用于调用既有合约。这两类交易会进入 TVM 执行。
合约部署成功后,网络会创建一个新的合约账户,并把编译后的字节码写入该账户。此后,其他账户对该合约发起调用时,TVM 会加载对应字节码并按 opcode 顺序执行。
执行上下文
每次 TVM 执行都运行在一组分层上下文中。由外到内可以分为四层:
- 世界状态:父区块结束时的全局账户状态。TVM 通过宿主接口读取和写入账户、余额、代码、存储等数据。
- 区块上下文:当前区块的元数据,例如区块高度、时间戳、出块 SR、父区块 ID。合约可通过
NUMBER、TIMESTAMP、COINBASE、BLOCKHASH、CHAINID等 opcode 读取部分信息。 - 交易上下文:触发本次执行的
CreateSmartContract或TriggerSmartContract交易。合约可通过ORIGIN、GASPRICE等 opcode 读取交易相关信息;在 TVM 中,GASPRICE返回当前能量单价energyPrice。 - 调用帧:当前合约调用的局部执行环境。每一帧都有自己的
caller、value、callData、code、pc、操作数栈和临时内存。合约调用另一个合约时,新的调用帧会压入调用栈。
调用帧之间不会共享操作数栈和临时内存。跨帧传递数据只能通过 calldata、RETURN / REVERT 返回数据,以及合约存储写入完成。
栈、内存与存储
TVM 是一台基于栈的虚拟机。执行时最容易混淆的是操作数栈、调用栈、内存和存储,它们的生命周期与限制不同:
| 区域 | 生命周期 | 用途 | 关键限制 |
|---|---|---|---|
| 操作数栈 | 单个调用帧内 | opcode 的直接操作对象,例如 PUSH、POP、DUP、SWAP | 最大 1024 个 256 位字 |
| 调用栈 | 一次合约执行内 | 记录合约间嵌套调用 | 最大深度 64 |
| 内存 | 单个调用帧内 | 临时、按字节寻址的数据区 | 每个调用帧最多 3 MiB |
| 存储 | 跨交易持久化 | 合约账户的持久状态 | 按 256 位键值写入,费用高于内存 |
操作数栈只保存当前 opcode 需要处理的 256 位字。调用栈则用于限制合约之间的嵌套调用深度,包括递归调用。两者不是同一个栈。
内存是临时区域,调用结束后即失效;存储属于合约账户,会跨交易保留。TVM 对每个调用帧设置了 3 MiB 的固定内存上限。EVM 没有同样的固定内存上限,主要通过 Gas 成本约束内存扩张;因此,大规模内存分配类合约在以太坊上能跑完,不代表在 TVM 上一定能通过。
TVM 指令
Solidity 合约编译后会变成 TVM opcode 序列。TVM 支持常见栈操作和算术逻辑操作,例如 PUSH、POP、ADD、SUB、AND、XOR,也支持区块链环境相关指令,例如 ADDRESS、BALANCE、BLOCKHASH、CALL、SSTORE。
单次合约调用的大致流程如下:
- Solidity 编译器将源代码编译为 TVM 可执行字节码。
- TVM 按顺序执行 opcode,并在所有节点上保持确定性结果。
- opcode 需要账户、区块、交易或存储数据时,通过执行上下文读取。
- 执行结束后,节点把结果写入交易回执,并根据执行结果提交或回滚状态变更。
完整 opcode 参考参见 Opcodes。
执行结果与异常
TVM 执行结果记录在交易回执的 receipt.result 字段中。常见结果可以分为三类:
SUCCESS:字节码正常执行到STOP、RETURN或有效的终止路径。REVERT:合约主动执行REVERT,通常来自 Solidity 的require、revert或自定义错误。该调用产生的状态变更会回滚,未消耗的能量会退还。- 异常停止:执行过程中触发协议级错误或资源耗尽,状态回滚。常见结果包括:
OUT_OF_ENERGY:分配给交易的能量预算耗尽。OUT_OF_TIME:单笔交易 TVM 执行超过 80 毫秒物理时间预算。STACK_TOO_LARGE/STACK_TOO_SMALL:操作数栈溢出或下溢。JVM_STACK_OVER_FLOW:调用深度或实现层栈限制触发。BAD_JUMP_DESTINATION:跳转目标非法。ILLEGAL_OPERATION/INVALID_CODE:遇到未启用、非法或无效的 opcode。PRECOMPILED_CONTRACT:预编译合约执行失败。TRANSFER_FAILED:合约内部 TRX 或 TRC-10 Token 转账失败。
80 毫秒执行上限TRON 除了通过能量预算限制 TVM 执行开销,还通过链参数
#13getMaxCpuTimeOfOneTx限制单笔交易占用的物理 CPU 时间。能量预算通常由调用方fee_limit、合约部署方origin_energy_limit和链级上限共同约束。私有链调试时可通过--debug绕过该限制;同步主网的节点不应启用该标志,否则本地执行结果可能与链上结果不一致,导致同步失败。
Solidity 层如何处理这些结果,参见 VM 异常处理。
能量计量
TVM 用能量(Energy)计量智能合约执行成本。系统合约交易通常只消耗带宽;智能合约部署和调用才会进入 TVM 并消耗能量。
每个 opcode 在执行前扣除固定或动态计算的能量。单次调用可使用的能量受多重边界约束,常见约束包括:
- 调用方设置的
fee_limit,按当前能量单价energyPrice折算为可购买能量。 - 合约部署方配置的
origin_energy_limit,用于限制部署方愿意为调用方承担的能量。 - 链级最大
fee_limit,由链参数#47getMaxFeeLimit控制。
如果执行耗尽能量,TVM 会返回 OUT_OF_ENERGY,回滚本次调用造成的状态变更,并消耗该交易已分配的能量预算。完整费用模型参见 FeeLimit 与能量成本,带宽与能量来源参见资源模型。
硬分叉门控
TVM 会逐步引入以太坊硬分叉中的部分 opcode 和行为,但这些功能并不是在所有网络上同时自动生效。每一组功能都有对应链参数门控,例如 getAllowTvmConstantinople、getAllowTvmIstanbul、getAllowTvmLondon、getAllowTvmShangHai、getAllowTvmCancun 和 getAllowTvmBlob。
在目标网络的门控参数启用之前,相关 opcode 会被视为 ILLEGAL_OPERATION。因此,合约是否能使用某个新 opcode,取决于当前网络的链参数状态,而不是仅取决于编译器是否支持。完整兼容矩阵参见 TVM 与 EVM 对比。
相关资源
- Opcodes — 完整 TVM opcode 参考
- TVM 与 EVM 对比 — TVM 与以太坊 EVM 的兼容性差异
- TRON 上的 Solidity — 支持的 Solidity 版本和 TRON 专有语言功能
- 智能合约简介 — 智能合约基础
- 资源模型 — 带宽与能量模型
- VM 异常处理 — 异常类型和 Solidity 错误处理模式
Updated 26 days ago