读懂 TRON 交易回执:消耗的能量、能量费用、带宽和结果
区块浏览器的交易页面,把一笔 USDT 转账显示成一个词、一笔费用和几个资源数字。节点通过 gettransactioninfobyid 返回同一笔交易的回执,每个数字都有名字:energy_usage、energy_usage_total、origin_energy_usage、energy_penalty_total、energy_fee、net_usage、net_fee 和 result。energy_fee 是为账户没有的那部分能量烧掉的 TRX,每单位 100 sun,net_fee 是为字节烧掉的 TRX,而本文每一份回执里,顶层的 fee 都是这两者之和。每一种值得读的情形,我们都留着主网回执:用租来的能量发出的转账、用 TRX 付费的转账、合约替调用方付了一部分能量的调用,以及停在 OUT_OF_ENERGY 或 REVERT 的转账。
字段缺失,意思是零
回执会省略每一个值为零的字段。没有为能量烧过 TRX 的转账没有 energy_fee,字节没有花钱的转账没有 net_fee。这些金额,energy_fee、net_fee 和顶层的 fee,单位都是 sun,即百万分之一个 TRX。
一笔用租来的能量,一笔用 TRX 付
下面两笔转账都消耗了 130,285 单位,这是收款方没有 USDT 余额时的数字。第一笔是我们自己的:2026 年 9 月 2 日,我们从 JustLend DAO 租了能量,代理给第二个钱包,并从它发出一个 USDT(那个订单花了多少)。第二笔是另一个发送方的,发生在 2026 年 10 月 6 日,账户上没有能量。我们是从发送方的交易列表里读到它的,那份列表把同样的字段平铺写在交易旁边,零值也包括在内,但省掉了 energy_penalty_total。
| 字段 | 租来的能量,2026 年 9 月 2 日 | 没有能量,2026 年 10 月 6 日 |
|---|---|---|
结果:receipt.result,在列表里是 contractRet | SUCCESS | SUCCESS |
energy_usage | 130,285 | 0 |
energy_fee,sun | 缺失 | 13,028,500 |
energy_usage_total | 130,285 | 130,285 |
energy_penalty_total | 100,635 | 列表里没有 |
net_usage,字节 | 缺失 | 0 |
net_fee,sun | 345,000 | 345,000 |
fee,sun | 345,000 | 13,373,500 |
| 以 TRX 计的费用 | 0.345 TRX | 13.3735 TRX |
energy_usage_total 是这次调用消耗的量。energy_usage 是发送方用它已有的能量付掉的部分,不论是质押的还是代理来的,而 energy_fee 是其余的部分,靠每单位 100 sun 烧 TRX 买来。在我们的转账上,前两个相等,第三个缺失,所以每一个单位都是代理付的。另一个发送方没有能量,13,028,500 sun 花在了 130,285 单位上,正好每单位 100 sun。
带宽的几行是一致的。两个账户都没有用自己的带宽覆盖字节,所以各付了 345,000 sun:345 字节,每字节 1,000 sun,这是我们 2026 年 9 月 2 日读到的链上参数里的费率。
合约替调用方付一部分能量的时候
合约的部署者可以承担对它每次调用的一部分能量。回执里于是带着 origin_energy_usage,即部署者的那一份。调用方付其余部分,付法和付转账一样,先用自己的能量,再靠烧。JustLend DAO 的能量市场把调用方的份额定为十分之一(consume_user_resource_percent 为 10),而在我们样本里它全部的 83 份回执上,调用方的那一份都等于 energy_usage 加上 energy_fee 的百分之一。
| 字段,2026 年 9 月 2 日 | 我们的租用调用 | 另一个租用方的归还调用 |
|---|---|---|
energy_usage | 8,429 | 24 |
energy_fee,sun | 缺失 | 739,000 |
origin_energy_usage | 75,861 | 66,721 |
energy_usage_total | 84,290 | 74,135 |
| 调用方的那一份,总量减去 origin 部分 | 8,429 | 7,414 |
net_usage,字节 | 383 | 缺失 |
net_fee,sun | 缺失 | 378,000 |
fee,sun | 缺失 | 1,117,000 |
第二个调用方自己有 24 单位,为另外的 7,390 单位烧了 739,000 sun。我们的租用调用没有 fee,尽管它给合约发过一笔预付款:那笔钱是作为这次调用所附带的 value 走的,而 fee 只计网络收走的部分(预付款去了哪里)。本文里没有一份 USDT 回执带着 origin_energy_usage:每一份上,发送方自己的能量加上它烧掉的,正好凑成整个总量。
origin_energy_usage 缺失,意味着部署者什么也没付,整个调用都由调用方付。这是最贵的情形,而它看上去和一个没人填的字段一模一样。部署者的份额出自部署者自己的能量,而且只在还有剩的时候。同一个下午,在我们租用之前不到三小时,同一个市场上另一个租用方的租用调用没有带 origin_energy_usage,全部 52,672 单位都由它自己付,其中 51,492 单位是烧的。
带宽:net_usage 对 net_fee
带宽按已签名交易的字节计量(能量与带宽并排)。net_usage 计的是账户用自己的带宽覆盖的字节,不论是每日免费额度还是带宽质押。net_fee 是它为没能覆盖的字节用 TRX 付的钱。在我们手上的每一份回执里,二者只会有其一。
我们的 JustLend 订单两种都有。上面那笔租用调用的 net_usage 是 383,没有 net_fee:钱包的免费带宽覆盖了它。我们自己的归还调用,在 144 秒后从同一个钱包发出,不在上面的表里,没有 net_usage,net_fee 是 378,000 sun。按链上的 getFreeNetLimit,免费额度是每天 600,租用调用用过之后剩下的,盖不住归还。在我们样本里的 83 份 JustLend 回执中,有 29 份为字节付了费,每字节都是 1,000 sun。
结果这个词决定什么
这个词在回执里出现两次。失败的回执,不论出了什么问题,顶层的 result 都是 FAILED,并带着十六进制的 resMessage。原因在往下一层的 receipt.result 里:SUCCESS、OUT_OF_ENERGY 或 REVERT。成功的回执压根没有顶层的 result,所以只读外层字段的脚本,会把每一种失败都归到同一个名字之下。
2026 年 10 月 6 日同一个钱包的三条记录,显示了 OUT_OF_ENERGY 是怎么来的。它们是同一笔转账签了三次,从交易列表里读出,因为 fee_limit 属于已签名的交易。第三条就是第一张表里那笔用 TRX 付费的转账。
| 2026 年 10 月 6 日 | 15:49 UTC | 16:24 UTC | 16:26 UTC |
|---|---|---|---|
fee_limit,sun | 1,100,000 | 未设置 | 13,046,000 |
结果,contractRet | OUT_OF_ENERGY | OUT_OF_ENERGY | SUCCESS |
energy_usage_total | 11,000 | 0 | 130,285 |
energy_fee,sun | 1,100,000 | 0 | 13,028,500 |
net_usage,字节 | 344 | 0 | 0 |
net_fee,sun | 0 | 339,000 | 345,000 |
| 以 TRX 计的费用 | 1.1 TRX | 0.339 TRX | 13.3735 TRX |
第一次尝试恰好停在 11,000 单位,即它的 fee_limit 除以 100 sun:节点把一次调用的能量封顶在 fee_limit 除以能量价格,不论账户持有多少。第二次没有带 fee_limit,按零算,所以它一点能量也花不了。它的回执里没有能量字段,它的 resMessage 解码出来是“Not enough energy for 'PUSH1' operation executing: curInvokeEnergyLimit[0], …”。三分钟后,同一个账户为第三次尝试付了款,可见它并不是空的。代理来的能量落在同一个封顶之下,这就是为什么我们的 API 会在买任何能量之前,拒绝一笔签名时 fee_limit 不够的 mode B 转账,返回 fee_limit_too_low。
同样那几分钟里的另外两笔 USDT 转账,把两个失败的词都显示出来了,顶层都是 FAILED。
| 字段,2026 年 10 月 6 日 | 能量耗尽 | 被合约拒绝 |
|---|---|---|
receipt.result | OUT_OF_ENERGY | REVERT |
energy_usage | 44,165 | 8,624 |
energy_fee,sun | 1,383,400 | 缺失 |
energy_usage_total | 57,999 | 8,624 |
energy_penalty_total | 25,905 | 6,640 |
net_fee,sun | 345,000 | 345,000 |
| 以 TRX 计的费用 | 1.7284 TRX | 0.345 TRX |
第一个发送方自己有 44,165 单位,为另外 13,834 单位烧了 TRX,在 57,999 处耗尽,这是它的能量和 TRX 加起来所能买到的全部。它签名的 fee_limit 允许 350,000 单位,所以这一次,限制来自账户本身。第二笔是合约拒绝了这笔转账:resMessage 读出来是“REVERT opcode executed”,而 USDT 在回滚时不给理由。我们的 API 参考文档给出两种原因:发送方已不再持有这个金额,以及发送方被代币发行方冻结(付款团队碰到的那些失败)。
只有 SUCCESS 的回执记录了代币的移动:它的 log 里有代币的 Transfer 事件,我们那笔租来能量的转账就是这样。OUT_OF_ENERGY 和 REVERT 的回执不带 log,因为没有代币移动。它们的费用照样花掉,因为调用在停下之前消耗的一切都已经付了(为什么 OUT_OF_ENERGY 之后 TRX 就没了)。
当我们在 mode B 里广播客户已签名的转账时,回执还裁定了谁来为能量付费。一份 OUT_OF_ENERGY 的回执,如果花掉的少于这笔转账的需求量——转给持有 USDT 的地址是 64,285 单位,转给不持有的是 130,285——就意味着调用运行时,我们的能量不在这个地址上。条目以 expired 收场,我们照常扣费;除非我们的记录显示,卖方在这笔转账所在的区块之前就把代理收回了,或者是您从同一个地址发出的另一笔转账把它花掉了。那时缺口算我们的,就像一份回执至少花掉了需求量、却因为我们的估算偏小而仍然耗尽时一样:条目以 failed 收场,我们把预留退回。我们手上有一份回执消耗了 108,047 单位却还是停了:假如这是一笔我们按收款方持有 USDT 来定量的转账,这个缺口就该算我们的。REVERT 我们同样扣费。
附加费计入总量
在我们那笔租来能量的转账上,总量是 130,285 单位,钱包恰好从它的代理里提用了 130,285,其中 100,635 单位带着附加费的标签。失败的转账与此一致:账户自己的能量加上烧掉的能量,等于总量,附加费也算在内。
我们手上的数值是:一笔转给没有 USDT 的地址、已完成的转账上是 100,635,两笔耗尽能量的转账上是 25,905,被合约拒绝的那一笔上是 6,640。节点对一笔转账的模拟运行,会报出与之吻合的 energy_penalty:收款方没有 USDT 时,130,285 旁边是 100,635;收款方持有一些时,64,285 旁边是 49,635。我们 2026 年 9 月 2 日读到的链上参数,动态能量是开着的(getAllowDynamicEnergy 为 1),而这个名字与一笔随收款方变贵而增长的附加费相符。我们没有拿节点的算术去对照这些参数,所以这笔附加费收的是什么,在这里仍然没有量过。
拿回执核对一次租用
租了能量之后,转账回执里的两个字段会告诉您这次租用有没有办成事:energy_fee 缺失,而且 energy_usage 加上任何 origin_energy_usage 等于 energy_usage_total。您为之租了能量的转账上出现 energy_fee,就说明它的能量终究有一部分是用 TRX 买的。可能是代理比调用小,可能是调用运行时它还没落地,可能是它已经被收回,也可能是被同一个钱包的另一笔转账先花掉了(代理怎样开始、怎样结束)。账户本身可以在发送之前读出来(怎样安全地租用能量)。
在 mode B 里把已签名的转账交给我们,回执就由我们来逐条读:API 参考文档里一个条目可能收场的每一种原因 →