Landing Transactions Key Points
Landing a transaction means a leader includes it in a block while its recent blockhash is still valid, so the signature moves from "unknown" to a confirmed status you can show in product UX.
Search across all documentation pages
Landing a transaction means a leader includes it in a block while its recent blockhash is still valid, so the signature moves from "unknown" to a confirmed status you can show in product UX.
This page is the conceptual map for Priority Fees & Transaction Optimization - why txs stall, how CU price and limits interact, how clients retry safely, when ALTs and Jito help, and how assembly choices shape local fee markets on Agave 4.1.1.
A client builds a message (instructions, account metas, fee payer, recent blockhash), signs it, and submits the wire transaction through RPC or a block engine. The node may run preflight simulation, then forward the packet toward upcoming leaders.
Landing is inclusion in a produced block. Confirmation is how far that block has progressed through votes (processed → confirmed → finalized). Product success almost always means "landed and succeeded under the commitment you chose," not "RPC accepted the send."
sendTransaction returning a signature only proves the node accepted the submission path. The signature can remain unknown forever if the packet never wins a slot before the blockhash expires (~150 slots, often about a minute of wall clock).
| Outcome | What you observe | Typical cause |
|---|---|---|
| Never included | Status unknown / null after wait | Underpriced, dropped, expired blockhash, oversized packet, bad peer |
| Included, program failed | Signature found, meta.err set | Logic, accounts, CU exceeded during execution |
| Included, succeeded | Status at chosen commitment, no err | Healthy path |
Only the first row is a pure landing problem. CU budgeting still matters for both landing economics (price × limit) and for the second row (execution failure after inclusion).
Fees have two layers. A base fee covers signatures. A priority fee is set with Compute Budget instructions: set compute unit limit and set compute unit price (microLamports per CU). Priority lamports scale roughly with price × limit / 1_000_000. Leaders use fee signals when many transactions compete for block capacity and account locks.
That competition is often local: hot accounts (a mint vault, popular pool, shared config) create a local fee market for transactions that write those keys, even when the rest of the network is quiet.
Leaders have finite capacity per slot. Under load they prefer higher-value work. Your transaction also races blockhash validity: after lastValidBlockHeight, validators reject the message.
Common drop paths:
Treat landing rate (sends that reach confirmed without exhausting rebuilds) and p95 time-to-confirmed as product metrics.
Use getRecentPrioritizationFees (optionally scoped to accounts your transaction locks) or a provider fee API. Target a percentile: p50 quiet, p75 default UX, p90 mints and other contention. Apply a small safety factor and a hard cap so fee spikes cannot drain users.
priority_fee_lamports ≈ (microLamports_per_CU × compute_unit_limit) / 1_000_000
total_user_fee ≈ base_signature_fee + priority_fee_lamports (+ optional tip)Price and limit multiply. A bloated CU limit with an aggressive price overpays; a tight limit with a high price still fails if execution exceeds the limit after inclusion. Fix limit from measurement first, then bid price for inclusion.
Default budgets are not tuned for your route. Simulate the fully assembled transaction, read unitsConsumed, and set SetComputeUnitLimit to roughly consumed × 1.1–1.2 headroom for state variance.
On Agave 4.1.1-era stacks, per-transaction CU ceilings are finite. Simulation that errors is a correctness problem; simulation that succeeds with high consumption is a fee and risk signal. Local tests (Anchor 0.32.1, LiteSVM, Surfpool) profile CU in development; mainnet fee percentiles still need live RPC samples.
Two different operations:
getLatestBlockhash, new message, and new signatures (different transaction identity).Prefer application control: often low or zero RPC maxRetries, then your loop waits for confirmation, rebroadcasts the same wire form until height expiry, and only then rebuilds with a fresh blockhash and fee sample. Track lastValidBlockHeight and stop rebroadcasting after it passes. Durable nonces replace short-lived recent blockhashes for slow multi-signer flows.
Idempotency matters: if the first attempt might still land late, a second rebuild can double-execute unless the program path is safe to retry.
Versioned v0 transactions plus address lookup tables replace many 32-byte keys with 1-byte indices into an on-chain table. That shrinks packets so multi-hop swaps and multi-instruction assemblies stay under size limits leaders will propagate.
Lifecycle: create → extend with stable pubkeys → wait for activation (~1 slot) → compile v0 with lookups → optionally freeze. Clients using @solana/kit 7.0.0 fetch the ALT before compile so indices match on-chain order. ALTs do not raise priority by themselves; they remove a structural drop reason and free room for budget and tip instructions.
Jito block engines accept bundles: ordered transactions that land together atomically, typically with a tip transfer. Use them when ordering and atomicity matter (mint + tip, multi-leg paths) or when public mempool exposure is unacceptable for high-value flow.
Bundles complement native priority fees; they do not replace correct CU limits or valid blockhashes. Tip markets have their own cost curve - reserve for contention windows and high-value routes.
Instruction order is part of landing reliability and fee efficiency:
Compile with the right message version, complete signer set, and minimal writable account set. Over-marking writable accounts increases lock contention and can worsen the local fee market you bid into. Simulate the final wire form before mainnet send.
fetch blockhash + fee samples (+ ALT accounts)
→ prepend CU limit + price → core ixs (+ optional tip)
→ compile v0 with ALTs → sign → simulate
→ send (RPC and/or Jito) → wait commitment
unknown & hash valid → rebroadcast same bytes
expired / timed out → rebuild (new hash, fees, sign)
landed + err → fix program/accounts (do not blind retry)
landed + ok → doneLocal fee markets form around contended writable accounts. Sampling prioritization fees with the accounts your route locks often beats empty global samples when congestion is path-specific. Maintain fee profiles per template (transfer vs swap vs mint) with separate floors, percentiles, and caps.
SWQoS and private RPC improve the chance packets reach leaders. They pair with fee policy; they do not replace it. Production send paths usually want a paid tier and dual-path send for critical routes (RPC plus block engine).
Cost UX: show estimated priority SOL from price × limit, plus base fee and optional tip. Cap multipliers during spikes. Feature-flag aggressive percentiles so you can decay off-peak without a deploy crisis.
Measurement: log signature, route id, microLamports, CU limit, units consumed (sim and landed meta), tip lamports, attempts, and time-to-confirmed. Landing rate and fee per successful confirm steer percentile choice.
| Situation | Prefer |
|---|---|
| Quiet mainnet, simple ix | Modest CU price floor, standard retry |
| Shared hot accounts | Account-scoped fee samples, higher percentile |
| Large account lists | v0 + ALT maintenance job |
| Atomic multi-tx or mint day | Jito bundle + tip policy |
| Multisig / slow sign | Durable nonce |
| Sim fails | Fix program or accounts before raising fees |
Devnet caveat: fee markets and drop rates do not match mainnet. Validate assembly, ALT activation, and retry state machines on devnet; validate fee percentiles and landing SLOs with small mainnet probes.
A leader included your transaction in a block before its recent blockhash became invalid, so the signature is discoverable on-chain (success or program error).
Landing is inclusion. Confirmation is how many validators have voted on that block (processed, confirmed, finalized). UX usually waits for at least confirmed.
Simulation checks execution against a bank snapshot. It does not reserve leader capacity, win a fee auction, or guarantee packet propagation before blockhash expiry.
Compute unit price is microLamports per CU. Priority fee paid scales with that price times the compute unit limit you request (base signature fees are separate).
Assemble the real transaction, simulate it, read unitsConsumed, add about 10–20% headroom, and set SetComputeUnitLimit. Details in Estimating Compute Units.
Start around p75 with a small multiplier and a hard cap for normal UX; raise toward p90 for mints and hot windows; measure landing rate and adjust. See Setting Priority Fees.
Rebroadcast the same signed transaction while lastValidBlockHeight is still ahead. Rebuild and re-sign when the hash expires or you must change fees or instructions. See Retries & Blockhash Management.
If the transaction is included and fails during execution, inclusion fees still apply. Dropped transactions that never land pay nothing on-chain.
When account lists make legacy messages too large or leave no room for budget and tip instructions. Use v0 compilation with maintained ALTs. See Address Lookup Tables in Practice.
When you need atomic multi-transaction ordering, stronger inclusion incentives via tips, or reduced public mempool exposure for high-value flows. See Jito Bundles.
Fee pressure concentrated on transactions that lock the same hot writable accounts (pools, mints, shared vaults), which can outpace quiet global averages. Sample fees with those accounts when possible.
Compute budget first, then account setup, then core business instructions, then optional tips or cleanup. Full patterns live in Transaction Assembly.
skipPreflight: true can reduce latency but sends more doomed transactions. Prefer preflight on for user wallets; selective skip is for specialist low-latency paths that already simulated offline.
No. They raise inclusion probability under contention. Program bugs, CU exhaustion, bad accounts, expired blockhashes, and path failures still prevent success.
Anchor 0.32.1 shapes on-chain programs and IDL-driven clients; @solana/kit 7.0.0 builds, signs, simulates, and sends versioned transactions. Neither removes the need for fee, CU, blockhash, and confirmation policy.
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, Rust 1.91.1, and @solana/kit 7.0.0.
Reviewed by Chris St. John·Last updated Jul 15, 2026