Solana Congestion: How to Best Send Solana Transactions
Introduction
"Transaction simulation failed: Blockhash not found." "Failed to send transaction." These error messages have become all too familiar. Network congestion has turned even basic transactions into a game of chance. This suffering is unnecessary.
This guide explores simple strategies for effectively navigating high-traffic periods to ensure your transactions land. We'll cover comprehensive approaches to handling network congestion, including priority fees, compute unit optimization, and Helius exclusive secret hack to always land your transactions.
In this guide, we'll explore:
- Using serialized transactions for priority fees
- Using account keys for priority fees
- Advanced priority fee strategies
- Transaction optimization techniques
- Leveraging staked endpoints for guaranteed delivery
Priority Fees
Priority fees serve as a bidding mechanism, allowing you to signal the importance of your transaction to validators. These fees, priced in micro-lamports per compute unit, are determined by the specific accounts your transaction interacts with, creating independent fee markets for each account. By strategically setting these fees based on account-specific congestion, you can significantly improve your transaction's chances of being included in the next block.
Next, we’ll look at how you can set the priority fees correctly with various approaches using Helius’s Priority Fee API:
Serialized Transaction
The most straightforward method of setting priority fees is to use a serialized transaction. A serialized transaction is a binary representation of a transaction converted into a wire-format buffer that can be transmitted across the network.
1. Serialize your transaction and pass it to the API:
const serializedTx = transaction.serialize();
const response = await fetch(heliusEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'helius-example',
method: 'getPriorityFeeEstimate',
params: [{
transaction: serializedTx,
options: { recommended: true }
}]
}),
});
const { result } = await response.json();
const priorityFee = result.priorityFeeEstimate;
2. Add the recommended fee to your transaction — the ordering of instructions does not matter:
transaction.add(
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee
})
);
Account Keys
An alternative approach is to provide a list of account keys involved in the transaction to the Priority Fee API:
1. Extract account keys from your transaction:
const transaction = new Transaction();
// Add your instructions to the transaction
// Extract all account keys from the transaction
const accountKeys = transaction.compileMessage().accountKeys;
// Convert PublicKeys to base58 strings
const publicKeys = accountKeys.map(key => key.toBase58());
2. Pass the account keys to the Priority Fee API:
const response = await fetch(heliusEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'helius-example',
method: 'getPriorityFeeEstimate',
params: [{
accountKeys: publicKeys,
options: { recommended: true }
}]
}),
});
const { result } = await response.json();
const priorityFee = result.priorityFeeEstimate;
3. Add the recommended fee to your transaction:
transaction.add(
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee
})
);
While both methods work, the serialized transactions method is recommended. Using account keys requires manually tracking and including all relevant accounts, which can lead to inaccurate fee estimates if any accounts are missed.
The serialized transaction method eliminates this risk by automatically including all necessary accounts and providing more accurate fee estimates based on the complete transaction context.
Advanced Priority Fee Strategies
For most scenarios, using a serialized transaction with the recommended priority fee is sufficient. However, for more granular control, the Priority Fee API allows you to request estimates for different priority levels and enable empty slot evaluations.
Priority Levels
Here's an example of how to request all priority fee levels:
const response = await fetch(heliusEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'helius-example',
method: 'getPriorityFeeEstimate',
params: [{
transaction: serializedTx,
options: {
includeAllPriorityFeeLevels: true
}
}]
}),
});
const { result } = await response.json();
console.log(result.priorityFeeLevels);
This will return an object with different priority levels:
{
"priorityFeeLevels": {
"min": 10000.0,
"low": 10000.0,
"medium": 10000.0,
"high": 100000.0,
"veryHigh": 5483924.800000011,
"unsafeMax": 8698904817.0
}
}
The priority levels correspond to different percentiles of recent transaction fees:
- min: 0th percentile
- low: 25th percentile
- medium: 50th percentile
- high: 75th percentile
- veryHigh: 95th percentile
- unsafeMax: 100th percentile (use with caution)
To further improve transaction landing rates, consider using the high or very high priority levels. However, be cautious using higher priority levels, especially veryHigh and unsafeMax, as they can significantly increase transaction costs.
Note: When using the recommended: true option, the API returns the medium (50th percentile) priority fee if it exceeds 10,000. If the medium is less than 10,000, the API will return 10,000. This ensures a baseline priority fee for your transactions.
Empty Slot Evaluation
A recent update to the Priority Fee API allows for smarter fee estimation by considering empty slots. When blocks contain no transactions for a particular account, you can configure the API to evaluate these slots as having zero fees, providing more accurate estimates during low network activity:
const response = await fetch(heliusEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'helius-example',
method: 'getPriorityFeeEstimate',
params: [{
transaction: serializedTx,
options: {
recommended: true,
evaluateEmptySlotAsZero: true
}
}]
}),
});
When evaluateEmptySlotAsZero is enabled, the API:
- Identifies blocks without transactions for your accounts
- Counts these empty slots as having zero fees
- Adjusts estimates downward during low congestion
- Prevents overpaying when network activity is low
Transaction Optimization Strategies
Beyond priority fees, optimizing transactions involves several key components that work together to improve landing rates:
Compute Unit Management
1. Use the Helius SDK to get the optimal compute units for your transaction:
const response = await helius.rpc.getComputeUnits({
transaction: serializedTransaction
});
const computeUnits = response.computeUnits;
2. Add compute unit limit to your transaction:
transaction.add(
ComputeBudgetProgram.setComputeUnitLimit({
units: computeUnits
})
);
Commitment Levels
For most applications, using a processed commitment level provides the best balance. It:
- Provides the fastest confirmation time
- Is sufficient security for most use cases
- Reduces risk of block hash expiration
- Minimizes dropped transactions during congestion
Always use the same commitment level for sending and confirming transactions to maintain consistency in your application's behavior.
RPC Configuration
Set maxRetries to 0 and implement your own retry logic for better control over transaction resubmission. Use skipPreflight: true to reduce latency. This is especially useful during high-congestion periods:
const signature = await connection.sendTransaction(transaction, {
maxRetries: 0,
skipPreflight: true
});
Using a Staked Endpoint
Helius staked endpoint provides direct, guaranteed access to staked connections, eliminating the need for manual priority fee optimization:
const connection = new Connection(
'https://staked.helius-rpc.com?api-key=YOUR_API_KEY'
);
// Transaction will be processed with optimal priority
const signature = await connection.sendTransaction(transaction);
The staked endpoint:
- Gives guaranteed staked bandwidth
- Reduces transaction failures during congestion
- Offers faster transaction propagation through dedicated infrastructure
Conclusion
Effective use of priority fees is crucial for successfully landing transactions on Solana, especially during network congestion. By leveraging the Helius Priority Fee API and implementing the strategies discussed, you can significantly improve transaction success rates while balancing cost considerations. Stay informed and adapt to network conditions for optimal results.
If you've read this far, thank you! We hope this guide has helped you understand how to optimize your transactions on Solana. Be sure to subscribe to our newsletter so you'll never miss an update about what's new on Solana.
Ready to dive deeper?
Explore the latest articles on the Helius blog and continue your Solana journey, today.