Debug 够多 Solana 交易失败之后,你最终都会撞到"blockhash 过期了"这一条。听起来很普通,但它实际上是生产 Solana 代码最常见的静默失败模式之一。我们聊过的大部分机器人操作者,都因为 blockhash 过期实打实亏过钱,而且过了好几周才意识到原因。
这篇过一遍 blockhash 是什么、为什么过期、该做什么、把稳健生产代码和最坏时刻失败的脆弱代码区分开的具体模式。
Blockhash 是什么
Solana blockhash 是最近某块的 hash,作为交易签名上下文的一部分使用。交易针对这个特定 hash 签名,意味着:
- 交易只能在 blockhash 仍然最近(约 150 块、60-90 秒内)时被处理
- 那个窗口后交易不再被接受
- 这是特性不是 bug——防止重放攻击
调 getLatestBlockhash 时拿到一个最近 blockhash 给签名。提交交易时 validator 检查 blockhash 是否仍够最近。
为什么过期
150 块有效期窗口有两个目的:
- 防重放。 上周签的交易现在不能重新提交
- 费市场清醒。 老交易不堆积当网络对 priority fee 的认知演化时
Solana 上窗口短——比以太坊上类似机制短得多(那里交易能无限期坐 mempool)。这是 Solana 快出块时间的后果:60-90 秒是很多 slot。
实际后果:你的交易需要用新 blockhash 提交,重试逻辑需要在尝试间刷新 blockhash。
Blockhash 过期怎么造成静默失败
咬大多数人的模式:
// 生产里别这么做
const tx = new Transaction().add(instruction);
const { blockhash } = await connection.getLatestBlockhash();
tx.recentBlockhash = blockhash;
tx.sign(payer);
for (let i = 0; i < 5; i++) {
try {
const sig = await connection.sendTransaction(tx, [payer]);
return sig;
} catch (e) {
await sleep(2000); // 重试间 2 秒
}
}
5 次重试加 2 秒间隔后你花了 10 秒。仍在 blockhash 有效期内——通常。但 RPC 每次都慢、或被限流等更久,能很容易超 60 秒。最后几次重试在用过期 blockhash 提交。RPC 可能暴露错误、可能静默丢、可能返回成功但交易从不上链。
结果:机器人以为提交了;什么都没上链;你不知道为什么。
行得通的模式
重试间刷新 blockhash:
async function sendWithRetry(buildTx, connection, signers, maxAttempts = 2) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
// 每次尝试新 blockhash
const { blockhash, lastValidBlockHeight } =
await connection.getLatestBlockhash("confirmed");
const tx = buildTx(blockhash);
tx.sign(...signers);
try {
const sig = await connection.sendTransaction(tx, signers, {
skipPreflight: true,
maxRetries: 0,
});
const confirmed = await waitWithDeadline(
connection, sig, lastValidBlockHeight, 30_000
);
if (confirmed) return sig;
} catch (e) {
// 日志、决定是否继续
}
}
throw new Error("重试后失败");
}
要点:
- 每次尝试拿新 blockhash
- RPC 侧
maxRetries: 0;我们自己管重试 - 用
lastValidBlockHeight作为确认截止 - 别超过 2 次重试;两次没上链机会大概没了
Blockhash 选 commitment
getLatestBlockhash 接受 commitment 参数:
"processed"——最快但短分叉能让 blockhash 失效"confirmed"——稍老但稳定"finalized"——完全终结、最老
大多数生产代码用 "confirmed" 是对的。你要的是一个既稳定到不会被 reorg、又新到能给你留够多有效期的 blockhash。
"processed" blockhash 对延迟敏感代码诱人(拿最新可能),但被失效的罕见情况花你整笔交易。大多数负载不值得这优化。
常见 Blockhash 反模式
我们在生产代码里见过造成问题的:
预取 blockhash。 启动时调一次 getLatestBlockhash 复用的代码。前几笔行;一分钟后崩。
缓存 blockhash。 有些代码"缓存 blockhash 5 秒减少 RPC 调用"。常常缓存的 blockhash 在被用时已经老于此。
签名前长时间构建交易。 你构建交易(带 blockhash)排队稍后签名提交、blockhash 在你提交时已经老。
不处理"blockhash not found"错误。 RPC 告诉你 blockhash 不识别;很多机器人代码库就重试用同一 hash 而不刷新。
提交前过度模拟。 模拟交易花时间;提交前模拟太多次,你针对的 blockhash 可能不再有效。
长重试链。 "我重试最多 10 次每次 1 秒间隔。"那是 10+ 秒延迟,深进 blockhash 过期领域。
特殊情况:Durable Nonce
签名长时间运行交易里 blockhash 过期结构性是问题、Solana 有 durable nonce。专用 nonce 账户不在 blockhash 窗口过期——给离线签名、多签流程、签名比提交早得多的任何情况有用。
简短概览:
// 创建 nonce 账户
const noneAccount = await createNonceAccount(connection, payer);
// 用 nonce 值作为最近 blockhash
const tx = new Transaction({ feePayer: payer.publicKey, recentBlockhash: nonceValue });
tx.add(SystemProgram.nonceAdvance({ noncePubkey: noneAccount, authorizedPubkey: payer.publicKey }));
tx.add(yourActualInstruction);
99% 交易机器人用例不需要 durable nonce——只要用新近 blockhash。Durable nonce 给签名提交差几分几小时的情况。
完整论述见 durable nonce 文档。
这周可以做什么
如果你看到交易静默失败或不一致上链:
- 审重试逻辑。 跨重试复用 blockhash 吗?是就大概是原因。
- 设 sendTransaction 调用
maxRetries: 0。 自己用新 blockhash 管重试。 getLatestBlockhash用"confirmed"commitment,除非有具体理由用"processed"。- 超过 2 次别重试。 两次没上链就不会上了。
- 加每笔签名级别的遥测。 交易失败时日志 blockhash、尝试次数、提交时 lastValidBlockHeight。让你看哪些失败是 blockhash 相关。
- 长签名流程考虑 durable nonce。 否则积极刷新 blockhash。
BoltTx 提供什么
BoltTx 在处理交易提交时,默认就用了对的参数:
- 亚秒级确认让交易在 blockhash 有效期内上链
- 每笔签名级别的投递遥测——任何交易看是 blockhash 过期还是其他原因被拒
- 原生 Anti-MEV 路由让交易不被三明治前置耽误
- 专属 SWQoS + 优先级连接,拥堵下也能保证上链(blockhash 问题飙升时)
import { Connection } from "@solana/web3.js";
const connection = new Connection(
"https://bolttx.io/?api-key=YOUR_API_KEY",
"processed"
);
免费档注册。用真实负载跑一周对比 blockhash 相关失败率。
常见问题
Blockhash 有效多久? 约 150 块、看网络速度大约 60-90 秒。
Blockhash 和 lastValidBlockHeight 区别? Blockhash 是你针对签名的值;lastValidBlockHeight 是这个 blockhash 后不再被接受的块号。两个都用做对的重试逻辑。
getLatestBlockhash 总用 "confirmed" commitment 吗?
生产是。"processed" 更快但能被 reorg 失效。罕见失效成本超过延迟节省。
maxRetries 设高有用吗? 没——通常导致重试链中静默 blockhash 过期。设 0 自己管重试。
拥堵期间 blockhash 问题更常见吗? 是。拥堵延迟包含,意味着 blockhash 在交易上链前更可能过期。