You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solana主网转账遇TransactionExpiredBlockheightExceededError求助

解决方案

1. 修正计算预算指令的添加顺序

你当前在交易签名后添加ComputeBudgetProgram.setComputeUnitPrice指令,这会直接导致交易签名失效——因为签名是基于签名前的交易数据生成的,后续修改交易内容会让节点拒绝该签名。必须在签名前添加计算预算指令:

// 先创建交易并添加所有核心指令
const transaction = new Transaction();

if (!accountInfo) {
  const associatedTokenAddress = await getAssociatedTokenAddress(
    mintAddress,
    to,
  );
  transaction.add(
    createAssociatedTokenAccountInstruction(
      from,
      associatedTokenAddress,
      to,
      mintAddress,
      TOKEN_PROGRAM_ID,
    ),
  );
}

transaction.add(
  createTransferInstruction(
    fromTokenAccount,
    toTokenAccount,
    from,
    amount,
    [],
    TOKEN_PROGRAM_ID,
  ),
);

// 先添加计算预算指令,再进行签名
transaction.add(
  ComputeBudgetProgram.setComputeUnitPrice({
    microLamports: 100_000,
  }),
);

// 获取blockhash及有效截止块高
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('finalized');
transaction.recentBlockhash = blockhash;
transaction.lastValidBlockHeight = lastValidBlockHeight; // 关键:设置交易过期的块高阈值

// 最后执行签名操作
transaction.sign({ publicKey: from, secretKey: signer });

2. 显式设置交易的lastValidBlockHeight

getLatestBlockhash会返回lastValidBlockHeight,代表当前blockhash的有效截止块高。如果不设置这个值,交易可能在默认的过期窗口内无法被节点打包。将其赋值给交易的对应属性,让节点明确知晓交易的有效期。

3. 优化sendAndConfirmTransaction的确认参数

默认的确认参数可能不够严格,导致交易未及时确认就触发超时。你可以指定更高的commitment级别和更长的超时时间:

return sendAndConfirmTransaction(connection, transaction, [
  { publicKey: from, secretKey: signer },
], {
  commitment: 'finalized', // 等待交易最终确认,避免中间状态的不确定性
  timeout: 30000, // 超时时间设为30秒,覆盖默认的较短超时窗口
  skipPreflight: false, // 保留预检查,提前发现交易格式或余额问题
})

4. 添加失败自动重试逻辑

即使做了上述优化,网络波动仍可能导致交易超时。可以捕获TransactionExpiredBlockheightExceededError并自动重试,最多重试2-3次:

async function sendWithRetry(connection, transaction, signers, maxRetries = 2) {
  let retryCount = 0;
  while (retryCount <= maxRetries) {
    try {
      // 每次重试前更新blockhash和有效块高
      const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('finalized');
      transaction.recentBlockhash = blockhash;
      transaction.lastValidBlockHeight = lastValidBlockHeight;
      // 重新签名(blockhash变更后需重新签名)
      transaction.sign(...signers);
      
      return await sendAndConfirmTransaction(connection, transaction, signers, {
        commitment: 'finalized',
        timeout: 30000,
      });
    } catch (error) {
      if (error instanceof TransactionExpiredBlockheightExceededError && retryCount < maxRetries) {
        retryCount++;
        console.log(`交易超时,正在重试第${retryCount}次`);
        await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒后重试,避免高频请求
      } else {
        throw error;
      }
    }
  }
  throw new Error('重试次数耗尽,交易失败');
}

// 替换原有的sendAndConfirmTransaction调用
console.log('> TRANSFERRING TOKENS');
return sendWithRetry(connection, transaction, [{ publicKey: from, secretKey: signer }]);

5. 检查gasStation逻辑的延迟

如果gasStation操作耗时过长,即使后续重新创建交易,也可能因为网络延迟导致新交易的blockhash很快过期。确保gasStation是快速完成的操作,若涉及SOL转账,建议给gas交易也设置高小费和严格的确认参数,减少等待时间。


内容的提问来源于stack exchange,提问作者Jonah Elbaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:27:20