机器人在 devnet 上通过了每一项测试。上线了。第一天就在竞速里输了。
★devnet 验证的是你的代码正确。它没法验证你的代码有竞争力,因为你要竞争的那个东西在那里根本不存在。★
devnet 确实能证明什么
它是一个有真实共识的真实集群,所以一次通过的 devnet 测试,对特定的一组事情是有意义的:
指令正确性。 account meta、顺序、PDA 推导、CPI 结构 —— 完全一致。
程序逻辑。 你的链上代码行为相同。
序列化。 1232 字节上限和账户布局都一样。
API 形状。 每一个 RPC 方法的行为都和主网一致。
★如果它在 devnet 上失败,它在主网上一定失败。★ 一次在那里 revert 的 simulateTransaction,在生产环境也会 revert。反过来不成立 —— 而这个不对称正是全部要点。
它没法展示给你的
| 主网现实 | devnet 上 |
|---|---|
| 优先费市场 | ★基本不存在★ |
| 竞争的机器人 | ★没有★ |
| 区块空间争用 | ★没有★ |
| 账户写入争用 | ★没有★ |
| 高负载下的 slot 距离 | ★永远是最好情况★ |
| 真实流动性与滑点 | 没有意义 |
★上面每一条都是提交侧的属性,而提交正是交易机器人真正失败的地方。★
一个因为从来不需要重试而从没重试过的循环,是未经测试的代码。 一个因为没人竞争而永远返回下限的手续费计算,是未经测试的计算。最要紧的那些路径,恰恰是 devnet 从不触发的路径。
如果你的代码是对的、差距在竞争力上,免费领个 BoltTx key 改一行就能在主网上测测提交路径。
没有费用市场,怎么测手续费逻辑
const fees = await connection.getRecentPrioritizationFees({
lockedWritableAccounts: writableAccounts,
});
★在 devnet 上,这个每次都返回接近于无。★ 你的中位数算出来是零,你的乘数什么都没做,你的上限从没生效过。 函数跑了、产出了一个数字,什么也没证明。
改成拿录下来的主网数据去测:
// ★把真实的手续费分布喂给这个纯函数。★
const scenarios = [calmFees, busyFees, spikeFees];
for (const s of scenarios) {
const fee = computeFee(s);
assert(fee >= FLOOR && fee <= CEILING);
}
把手续费决策保持为一个纯函数,这样不需要网络就能拿真实分布测它。这是让 devnet 测试在它够不到的那部分上变得有意义的、单项收益最高的做法。
有意地测失败路径
devnet 自己不会产出这些,所以要主动诱发:
// ★过期:用一个你故意放到失效的 blockhash 签名。★
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
await waitBlocks(200); // ★超出窗口★
// 期望:判定为过期,不崩溃,而且不查就不重建。
// ★revert:构造一笔必然失败的交易。★
// 余额不足、不可能的滑点、缺失的账户。
// ★计算耗尽:把上限设到实测用量以下。★
ComputeBudgetProgram.setComputeUnitLimit({ units: 1000 });
★一个在测试里从没见过过期的机器人,会在生产环境处理它的第一次过期。★ 这些路径诱发起来很便宜,而且恰恰是承载着重复执行和记账错误风险的那些。
两个环境在运维上的差别
空投。 requestAirdrop 在 devnet 上能用,而且被限流、不可靠。主网上它不存在 —— 所以你代码里任何出资通路,按构造就只能在 devnet 用。
程序地址不同。 代币程序是一致的,但 DEX 和 launchpad 程序通常没有 devnet 部署。★一个针对特定协议交易的机器人,常常在上主网之前根本没法对着它测。★
devnet 会重置。 状态可能被清空。你部署的、出资的东西可能就没了。
可靠性。 devnet 有主网没有的故障,而排查一个只在 devnet 出现的失败,通常是白费力气。
行得通的顺序
★1. devnet 测正确性。★ 指令、程序逻辑、序列化、错误处理。便宜且可重复。
★2. 在 devnet 上诱发失败。★ 过期、revert、计算耗尽、响应丢失。确认每条路径都收敛到一个终态,而不是崩溃。
★3. 拿录制的主网数据测纯函数。★ 手续费计算、重试节奏、体积检查。不需要网络。
★4. 用最小规模上主网。★ 这是唯一能测出 slot 距离、争用和真实手续费的办法。小金额、完整日志、不对策略抱期待。
★5. 测完再放大,不是放大之前。★
第 4 步不是可选的,也没法模拟。 把它当成一项真实成本做预算 —— 一段目的是测量而不是盈利的实盘时间。
第 4 步该测什么
metrics.record({
submittedSlot,
landedSlot,
outcome, // success | reverted | expired
priorityFeeLamports,
});
★拿这个分布和你开发时假设的那个比★,并且用 computeUnitsConsumed 对照你请求的上限。一个机器人带进生产环境的几乎每一个错误假设,都会在头几百笔真实交易里显形 —— 而它们在 devnet 上一个都看不见。
上链应该是什么水平
我们投递节点上的真实交易:中位确认 336 毫秒 —— 不到一个 slot。
★在 devnet 上你会量到一个更窄的东西,并且从中学不到任何东西。★ 一个分布只有在争用条件下产出才有信息量,而争用正是 devnet 唯一供应不了的条件。
BoltTx 在这里的位置
我们负责主网上的提交 —— 而主网正是提交行为存在、可供测量的地方。
提交走我们自建的四区域投递节点,带 SWQoS 路由,不暴露公共 mempool —— 交易在落块之前、传输途中观察不到。
你在本地签名。我们不托管资金、不代签、不修改交易内容。tip 带在交易里、从你自己的钱包链上支付,交易失败时跟着一起 revert —— 这是 Solana 原子交易的机制决定的。★只有到达链上的交易才计费,这让一次小规模的测量跑起来很便宜★ —— 在你拿到数据之前,没有月费需要你去论证它值不值。
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");
常见问题
devnet 测试对 Solana 机器人有用吗? 有,对正确性有用 —— 指令、程序逻辑、序列化、错误处理。它验证不了任何和竞争有关的东西,因为那里没有手续费市场也没有争用。
我的机器人在 devnet 能用、主网为什么失败? 因为失败发生在提交侧。devnet 没有优先费市场、没有竞争的机器人、没有区块空间争用,所以那些在生产里失败的路径从没被触发过。
能在 devnet 上测优先费逻辑吗? 没法有意义地测。近期费用查询返回接近于无,所以你的计算永远产出下限。改成拿录制的主网分布去测那个手续费函数。
没有拥堵怎么测重试逻辑? 主动诱发失败。 用一个你故意放到过期的 blockhash 签名、构造一笔必然 revert 的交易、把计算上限设到实测用量以下。每一种都该干净地收敛而不是崩溃。
该用 testnet 代替 devnet 吗? testnet 是给验证节点候选版本用的,对应用测试更不稳定。两者都复现不了主网的手续费市场,所以这个选择改变不了真正要紧的那个局限。
devnet 和主网的程序地址不同吗? 代币程序一致,但大多数 DEX 和 launchpad 程序没有 devnet 部署。针对特定协议的机器人,常常要到主网才能对着它测。
devnet 会被重置吗? 会,状态可能被清空,你部署或出资的东西可能消失。把 devnet 状态当成一次性的、可脚本重建的,而不是需要维护的。
主网上有 requestAirdrop 吗? 没有。它只存在于 devnet,而且在那里也被限流 —— 所以任何围绕它建的出资通路,按构造就只能在 devnet 用。
第一次上主网该投多少? 小金额,目的明确是测量而不是盈利。把它当成一项测试成本,因为 slot 距离和真实争用没有别的办法能观察到。
第一次主网跑该测什么? "提交到落块"的 slot 距离、成功/revert/过期的分布,以及手续费开销对结果。拿它和你开发时的假设比对。
能在本地模拟主网拥堵吗? 没法模拟出能预测成交率的东西。本地验证节点没有竞争者也没有手续费市场,它复现的是正确性条件,不是竞争条件。
我的 devnet slot 距离为什么比主网好? 因为没有任何东西在争夺区块空间。devnet 永远显示接近最好的情况,这就是那里一个很窄的分布对生产什么都说明不了的原因。
本地验证节点值得测什么? 程序逻辑和集成测试,那里速度和确定性有帮助。它是正确性方面最快的环境,也是竞争力方面信息量最少的。
上线之后还该继续用 devnet 吗? 该,用于程序改动和指令正确性。它对自己一向擅长的那些事仍然有用 —— 前提是你别从它身上读出关于竞争力的结论。
上主网之前怎么知道手续费逻辑是对的? 把它保持为纯函数,拿录制的主网手续费分布跑一遍,断言输出在平静、繁忙、尖峰三种场景下都落在你的下限和上限之间。
devnet 最大的盲区是什么? ★重试循环。★ devnet 上没有东西需要重试,所以处理过期、重发和终态的那段代码,在它跑进生产环境之前实际上从没被测过。