When sending a transaction using Solana web3, it sometimes shows this error:
Error: failed to send transaction: Transaction simulation failed: Blockhash not found
What is the proper way of dealing with this error other than retrying for x amount of times?
Is there a way to guarantee this issue won't happen when sending transactions?
Here is an example of how I'm sending a transaction:
const web3 = require("@solana/web3.js")
const bs58 = require('bs58')
const publicKey = new web3.PublicKey(new Uint8Array(bs58.decode("BASE_58_PUBLIC_KEY").toJSON().data))
const secretKey = new Uint8Array(bs58.decode("BASE_58_SECRET_KEY").toJSON().data)
const connection = new web3.Connection(
";, "finalized",
{
mitment: "finalized",
confirmTransactionInitialTimeout: 30000
}
)
const transaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: publicKey,
lamports: 1
})
)
web3.sendAndConfirmTransaction(
connection,
transaction,
[{publicKey: publicKey, secretKey: secretKey}],
{mitment: "finalized"}
)
How can I improve this to avoid the Blockhash not found
error?
When sending a transaction using Solana web3, it sometimes shows this error:
Error: failed to send transaction: Transaction simulation failed: Blockhash not found
What is the proper way of dealing with this error other than retrying for x amount of times?
Is there a way to guarantee this issue won't happen when sending transactions?
Here is an example of how I'm sending a transaction:
const web3 = require("@solana/web3.js")
const bs58 = require('bs58')
const publicKey = new web3.PublicKey(new Uint8Array(bs58.decode("BASE_58_PUBLIC_KEY").toJSON().data))
const secretKey = new Uint8Array(bs58.decode("BASE_58_SECRET_KEY").toJSON().data)
const connection = new web3.Connection(
"https://api.mainnet-beta.solana.", "finalized",
{
mitment: "finalized",
confirmTransactionInitialTimeout: 30000
}
)
const transaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: publicKey,
lamports: 1
})
)
web3.sendAndConfirmTransaction(
connection,
transaction,
[{publicKey: publicKey, secretKey: secretKey}],
{mitment: "finalized"}
)
How can I improve this to avoid the Blockhash not found
error?
- I ended up doing a retry backoff as I can't think of anything else. Please let me know if there's a better way to do this! – Brynne Harmon Commented Jan 15, 2022 at 3:04
- 1 Hey, can you post your solution. I have the same error and none of the reference below solve it. Thank you! – Julia Commented Jan 24, 2022 at 23:03
4 Answers
Reset to default 4Retrying is not a bad thing! In some situations, it's actually the preferred way to handle dropped transactions. For example, that means doing:
// assuming you have a transaction named `transaction` already
const blockhashResponse = await connection.getLatestBlockhashAndContext();
const lastValidBlockHeight = blockhashResponse.context.slot + 150;
const rawTransaction = transaction.serialize();
let blockheight = await connection.getBlockHeight();
while (blockheight < lastValidBlockHeight) {
connection.sendRawTransaction(rawTransaction, {
skipPreflight: true,
});
await sleep(500);
blockheight = await connection.getBlockHeight();
}
You may like to read through this cookbook entry about retrying transactions: https://solanacookbook./guides/retrying-transactions.html
Specifically, it explains how to implement some retry logic: https://solanacookbook./guides/retrying-transactions.html#customizing-rebroadcast-logic
And what retrying means specifically: https://solanacookbook./guides/retrying-transactions.html#when-to-re-sign-transactions
You can use the maxRetries
option: For web3 / Solana native:
web3.sendAndConfirmTransaction(
connection,
transaction,
{
maxRetries: 5
}
)
Or for SPL tokens:
const signature = await transfer(
connection,
sender,
senderTokenAccount.address,
recipientTokenAccount.address,
sender.publicKey,
amount,
[],
{
maxRetries: 6,
}
);
The Strata foundation has a package for solana and it's production grade.
I've used it at production applications.
const signature = await sendAndConfirmWithRetry(
connection,
tx.serialize(),
{
maxRetries: 5,
skipPreflight: true
},
"processed");
From here
RecentBlockhash is an important value for a transaction. Your transaction will be rejected if you use an expired recent blockhash (after 150 blocks)
solana has block time of 400ms. that means
150 * 400ms = 60 seconds
That is why you need to query and send transaction very fast. otherwise, your transaction will be dropped for good and you will get that error. correct error response should have been "Blockhash expired"