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

Solana blockhash 是什么、为什么过期、生产交易里怎么管。行得通的模式,和悄悄丢交易的模式。

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

延伸阅读

返回博客列表