Advanced
Durable Nonce & Multi-Path Submission
Sign once, submit many times. Durable Nonce lets you send the same transaction through BoltTx and any other relays in parallel — whichever lands first wins, and the nonce guarantees the transaction can only land once.
The problem with regular blockhash
Standard Solana transactions reference a recent blockhash that expires after 150 slots (~60 seconds at 400ms per slot). If you want to fan out the same signed transaction across multiple delivery paths for redundancy, the blockhash can expire before your slower paths even start — and re-signing with a fresh blockhash changes the signature, defeating the purpose.
How Durable Nonce fixes it
No expiration
Durable Nonce transactions use a stored on-chain nonce instead of a recent blockhash, so they stay valid until you explicitly advance the nonce.
Exactly-once landing
The nonce advances atomically when any copy of the transaction lands. All other copies automatically fail — there is no risk of double-execution.
One signature, many paths
Sign the transaction once, then submit the identical bytes to BoltTx plus any number of other relays in parallel. The fastest path wins.
Step 1 — Create a Nonce account
A Nonce account is a small on-chain account (80 bytes) that stores your current durable nonce. Create it once per wallet — the CLI's default funding of 0.0015 SOL is comfortably above the current rent-exempt minimum (the exact minimum depends on the cluster rent config; query getMinimumBalanceForRentExemption(80) to be precise). Your main wallet is the nonce authority.
# Generate a new keypair that will identify the nonce account
solana-keygen new -o nonce-account.json
# Create the nonce account, funded with 0.0015 SOL for rent exemption
solana -k sender.json create-nonce-account nonce-account.json 0.0015
# Query the current nonce value
solana nonce nonce-account.jsonStep 2 — Submit to BoltTx + other relays in parallel
Build one transaction with the same nonce, sign it once, then fan it out. The example below submits to BoltTx and any secondary relay (your own RPC, a Jito endpoint, etc.) concurrently.
import asyncio, base64
from solders.pubkey import Pubkey
from solders.keypair import Keypair
from solders.message import Message
from solders.transaction import Transaction
from solders.system_program import transfer, TransferParams
from solana.rpc.async_api import AsyncClient
async def submit_with_durable_nonce(
sender: Keypair,
nonce_account: Pubkey,
receiver: Pubkey,
tip_addr: Pubkey,
):
# 1. Fetch the current nonce value from the nonce account
rpc = AsyncClient("https://api.mainnet-beta.solana.com")
acc = await rpc.get_account_info(nonce_account)
nonce_hash = acc.value.data[40:72] # NonceState layout offset
await rpc.close()
# 2. Build the transaction with nonce + your instructions + BoltTx tip
instructions = [
transfer(TransferParams(
from_pubkey=sender.pubkey(),
to_pubkey=receiver,
lamports=1_000,
)),
transfer(TransferParams(
from_pubkey=sender.pubkey(),
to_pubkey=tip_addr,
lamports=800_000, # 0.0008 SOL — BoltTx Starter tip
)),
]
message = Message.new_with_nonce(
instructions,
payer=sender.pubkey(),
nonce_account_pubkey=nonce_account,
nonce_authority_pubkey=sender.pubkey(),
)
# 3. Sign ONCE with the nonce hash
tx = Transaction.new_unsigned(message)
tx.sign([sender], nonce_hash)
signed_b64 = base64.b64encode(bytes(tx)).decode()
# 4. Fan out to BoltTx + any secondary relay concurrently.
# The nonce guarantees only one copy actually lands.
import aiohttp
async with aiohttp.ClientSession() as http:
bolttx_task = http.post(
"https://bolttx.io/v1/send",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"transaction": signed_b64},
)
# Secondary path — your own RPC, Jito, etc.
backup_task = http.post(
"https://YOUR-BACKUP-RELAY/sendTransaction",
json={
"jsonrpc": "2.0", "id": 1, "method": "sendTransaction",
"params": [signed_b64, {"encoding": "base64"}],
},
)
results = await asyncio.gather(
bolttx_task, backup_task, return_exceptions=True
)
for i, r in enumerate(results):
label = ["BoltTx", "Backup"][i]
if isinstance(r, Exception):
print(f"{label}: failed — {r}")
else:
print(f"{label}: HTTP {r.status}")Step 3 — Handle the results
After any copy lands, the nonce advances on-chain. Fetch the updated nonce before sending the next transaction. Only one of the parallel submissions will succeed with an actual slot — the others will be rejected with BlockhashNotFound (Agave returns the same TransactionError::BlockhashNotFound it uses for expired blockhashes, because the stored nonce no longer matches the recent_blockhash field of the transaction). This is exactly the behavior you want: exactly-once execution with maximum redundancy.
Important caveats
- •Every Durable Nonce transaction must have nonceAdvance as its first instruction. Most Solana SDKs do this automatically when you use new_with_nonce / createNonceAccount helpers — double-check if you build messages manually.
- •Durable Nonce transactions cost the same tip as regular transactions on BoltTx. The redundancy is about landing reliability, not fee savings.
- •Do not submit the same nonce transaction to fewer than 2 paths — there's no point. Reserve this pattern for cases where landing reliability matters more than simplicity.