上主网前测试 USDT 付款:Nile 改了什么,沙箱模拟什么
付款集成应当在比主网便宜的地方碰到它的第一次失败,而在 TRON 上有两个这样的地方。Nile 是一条公共测试网:一条真实的链,交易在上面签名并落入区块,跑的是它自己的一套参数。像我们这样的沙箱,是在一条模拟链上复刻 API,这放弃了真实的网络,换来了真实网络不会应要求给出的那些结果。我们在 2026 年 9 月 3 日读了主网和 Nile 的链上参数,第二天在 Nile 上签了交易。
Nile 与主网相同的地方
Nile 和主网一样回应 getchainparameters 调用,给转账定价的那些参数回来的值完全一致。能量在两个网络上都是每单位 100 sun,所以能量不够的转账在两边都按同样的费率烧 TRX。免费带宽、创建账户的费用、备注费以及三个动态能量参数,也都一致。
| 链上参数,读于 2026 年 9 月 3 日 | 主网 | Nile |
|---|---|---|
每单位能量费用(sun),getEnergyFee | 100 | 100 |
每个账户的免费带宽,getFreeNetLimit | 600 | 600 |
创建账户的费用(sun),getCreateAccountFee | 100,000 | 100,000 |
备注费(sun),getMemoFee | 1,000,000 | 1,000,000 |
动态能量阈值,getDynamicEnergyThreshold | 5,000,000,000 | 5,000,000,000 |
动态能量增长系数,getDynamicEnergyIncreaseFactor | 2,000 | 2,000 |
动态能量最大系数,getDynamicEnergyMaxFactor | 34,000 | 34,000 |
解押等待天数,getUnfreezeDelayDays | 14 | 1 |
代理锁定的最长区块数,getMaxDelegateLockPeriod | 864,000 | 144,000 |
维护周期,getMaintenanceTimeInterval | 21,600,000 | 1,800,000 |
单笔交易的 CPU 时间上限,getMaxCpuTimeOfOneTx | 80 | 160 |
Nile 有什么不同
对处理能量的人来说,第一个不同是解押:在 Nile 上要一天,主网上要十四天,所以先质押 TRX 再提取的测试,比同样的流程在生产环境里早十三天结束。代理最长能带的锁定,Nile 上是 144,000 个区块,按每块三秒是五天,主网上是 864,000 个区块,即三十天。超过五天的锁定在 Nile 上根本没法预演;锁定会拒绝什么在两个网络上是一样的。
主网返回的参数里,有八个在 Nile 上取值不同。除了那两个,还有维护周期、表里的 CPU 上限,以及四个管区块生产者、提案和合约特性的参数。这六个里的任何一个,我们都没有追到付款流程里去看。
质押得到的能量数也不同,因为每个网络都把同样的能量上限分摊给自己的质押总量,而 Nile 的质押总量要小得多。在我们 9 月 4 日的两次 Nile 运行里,我们代理出去的那份质押,在接收账户上都显示为 7,376 单位能量。同样的质押放在主网上,按前一天读到的总量算,是 958 单位,所以 Nile 发出的能量几乎是主网的八倍。按 Nile 定出的质押量,放到主网钱包上会不够。
| 质押得到的能量 | 主网,2026 年 9 月 3 日 | Nile,2026 年 9 月 4 日 |
|---|---|---|
全网的能量上限,TotalEnergyLimit | 180,000,000,000 | 180,000,000,000 |
为能量质押的总量,TotalEnergyWeight | 18,770,236,993 | 2,440,088,105 |
| 代理 100 TRX 后接收方得到的能量 | 958 单位,算出 | 7,376 单位,实测 |
测试 USDT 是另一个合约
付款代码带着它所调用的 USDT 合约的地址。2026 年 10 月 27 日,我们向一个 Nile 节点询问主网 USDT 地址 TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t 上的合约,答复是一个空对象 {}:测试网上这个地址没有合约。Nile 上的测试代币来自另一个地址上的另一个合约,所以合约地址应当和节点 URL 一起放在配置里,把它写死的构建,会在两个网络中的一个上调用错误的地址。
一笔 Nile 测试代币转账要花多少能量,我们没有量过。Nile 每单位收的费用相同,但代币是另一个合约,所以 Nile 上没有任何东西能印证主网上转给持有者约 65,000 单位、转给没有 USDT 的地址约 131,000 单位这两个数。测试用的 TRX 来自水龙头,而它们是限量发放的:我们 9 月用的那一个,每个钱包、每个 IP 每 24 小时只允许申请一次。
已签名的交易也只留在它构建时所对的那个网络上。每笔 TRON 交易都带着对自己那条链上一个较新区块的引用,而我们的 API 在买任何能量之前,会拿这个引用去对照主网。对着 Nile 构建的 mode B 交易会被拒绝,返回 400,details.reason 为 ref_block_unknown。当链没有回应我们的检查时,订单会未经检查就被接受,而交付之后节点的拒绝是要计费的,所以每一笔交易在发送之前,都要对着当前主网的区块来构建。
沙箱模拟什么
我们的沙箱在 https://sandbox.nrg.market/v1 应答,跑的是和生产环境同一套代码,用的是测试资金、一条模拟链和模拟的能量卖方。那里的密钥以 nrg_test_ 开头,从沙箱控制台签发,注册是自助的。两个环境什么都不共享:数据库、余额、webhooks 和密钥都是分开的。集成在那里跑通之后,您只需改 base URL 和密钥;API 流程在两边是一样的。
测试资金不需要水龙头。确认邮箱会记入一笔起始余额,POST /v1/sandbox/deposit 则沿着真实充值走的同一条路径记入更多:账目里一行 deposit,txid 以 sandbox- 开头,并发出一个真实的 deposit.credited webhook。在生产环境里这条路径不存在,返回 404。
| 沙箱里的测试资金 | 按 API 契约 |
|---|---|
| 确认邮箱时,或首次 Google 登录时 | 10000 TRX |
一次 POST /v1/sandbox/deposit 调用 | 最多 100000 TRX |
| 每个客户每个 UTC 日的充值调用次数 | 10 |
测试网不会应要求给出某个特定的结果。沙箱把几个地址接到固定的行为上,做法和测试卡号一样:它们是有效的 TRON 地址,背后没有私钥。收款方决定能量的类型,以及 ready 之后会发生什么;发送方决定采购和代理怎么进行。
| 地址 | 角色 | 沙箱的行为 |
|---|---|---|
TLLmUhBYgU125KkPpeTdP1vz1zqhoZwn9v | 收款方 | 不持有 USDT,所以是 kind: double。它同样未激活,不管有多少笔转账落到它上面,它始终是空的。 |
TDUvBqzR3cYY6zYopYdJ9jWrxQRs9QmvQM | 收款方 | 不会出现任何转账。条目停在 ready,变成 expired 的时刻是 send_before,并且扣费,和生产环境一样。 |
TKLeQhXSUba1GG1wdznyMc49oqModZ8Fbm | 收款方 | 在 USDT 黑名单上:订单被拒绝,返回 422 blacklisted_recipient。 |
TQ6ey8qT87bnzBJXj7gVTGCkrU4wUJ1EWQ | 发送方 | 采购在每个卖方那里都失败。条目以 failed 收场,带着 purchase_failed,预留被释放。 |
TYWZsWdM9u8QKJTi6XEmenpvCPwg1xmPCC | 发送方 | 第一个卖方不可用,故障转移成功。响应里没有任何东西提示这一点。 |
TNhq25t5XTEuk3mC9cTcAGB5rr3xuCkGyr | 发送方 | 代理在大约 25 秒后确认,给必须等待的代码用。 |
| 任何其他有效地址 | 两者皆可 | 作为收款方,它持有 USDT;作为发送方,代理在 2 到 8 秒内确认。 |
两边可以组合,所以把那个必定失败的发送方和普通发送方混在一起的批量订单,不用特别要求什么,就会以 partially_completed 收场(这个状态对账单意味着什么)。场景发送方由这个环境的所有客户共用,所以当被测的恰恰是时序时,请用您自己的一个全新的发送地址:它得到的是普通的 2 到 8 秒,它的代理也只属于它自己。
这个环境里的价格就是真实价格。沙箱的价目表落后生产环境大约两分钟,最差三分钟,所以在那里预演的估价,返回的是生产环境两三分钟前报出的价格。mode B 不需要真正的密钥:模拟链不校验签名,所以任何一把一次性密钥签出的交易,都会像生产环境那样被解析,并依次走过 broadcasting、broadcasted 和 confirmed,广播大约三秒后确认。
只有主网能显示的东西
沙箱证明不了链负责的那一部分:能量在它上面从未真正到达任何地方,在那里被确认的代理,只是关于我们模拟器的一个事实。Nile 对我们的服务来说同样定不了这件事,因为我们在任何测试网上都不卖能量。真实的能量有没有落到真实的钱包上,转账随后有没有不烧 TRX 就成功,您只能在生产环境里知道。
有些分支在这两个环境的任何一个里,都无法用任何请求触发:503 capacity_unavailable,以及条目错误 broadcast_failed、transaction_reverted 和 broadcast_window_missed。每一个都取决于能量供应、取决于链,或者取决于服务被我们暂停。这部分处理逻辑要依据契约和 webhook 请求体来写,并当作从未运行过的代码来审查。
生产环境里相当一部分,演练起来不花钱。POST /v1/estimate 最多接受 500 个收款方,返回订单会算出的同样的 kind、energy_units 和 warnings,而 POST /v1/webhooks/{webhook_id}/test 会给您的接收端发一次真实的、带签名的投递。POST /v1/orders 在每种模式下都花真实的 TRX,这就让只有一笔转账的第一个实盘订单成了最后一次排练,也是唯一能看到能量落地的一次。
本文里的每一个场景地址,都在这个环境里应答,用测试资金和您自己的 nrg_test_ 密钥:打开沙箱控制台,签发一把 →