Solana Blockhash:为什么过期、怎么正确处理

讲清 Solana blockhash 过期:为什么交易大约 150 个区块后失效、什么时候取 blockhash 合适,以及避免 BlockhashNotFound 的重试写法。

BoltTx Team··9 min read
solanablockhashtransactionrpcsendtransaction

Debug 够多 Solana 交易失败之后,你最终都会撞到"blockhash 过期了"这一条。听起来很普通,但它实际上是生产 Solana 代码最常见的静默失败模式之一。我们聊过的大部分机器人操作者,都因为 blockhash 过期实打实亏过钱,而且过了好几周才意识到原因。

这篇过一遍 blockhash 是什么、为什么过期、该做什么、把稳健生产代码和最坏时刻失败的脆弱代码区分开的具体模式。

Blockhash 是什么

Solana blockhash 是最近某块的 hash,作为交易签名上下文的一部分使用。交易针对这个特定 hash 签名,意味着:

调 getLatestBlockhash 时拿到一个最近 blockhash 给签名。提交交易时 validator 检查 blockhash 是否仍够最近。

为什么过期

150 块有效期窗口有两个目的:

  1. 防重放。 上周签的交易现在不能重新提交
  2. 费市场清醒。 老交易不堆积当网络对 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 选 commitment

getLatestBlockhash 接受 commitment 参数:

大多数生产代码用 "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 文档。

这周可以做什么

如果你看到交易静默失败或不一致上链:

  1. 审重试逻辑。 跨重试复用 blockhash 吗?是就大概是原因。
  2. 设 sendTransaction 调用 maxRetries: 0。 自己用新 blockhash 管重试。
  3. getLatestBlockhash 用 "confirmed" commitment,除非有具体理由用 "processed"。
  4. 超过 2 次别重试。 两次没上链就不会上了。
  5. 加每笔签名级别的遥测。 交易失败时日志 blockhash、尝试次数、提交时 lastValidBlockHeight。让你看哪些失败是 blockhash 相关。
  6. 长签名流程考虑 durable nonce。 否则积极刷新 blockhash。

BoltTx 提供什么

BoltTx 在处理交易提交时,默认就用了对的参数:

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 在交易上链前更可能过期。

延伸阅读

← 返回博客列表