python
Send a transaction over UDP from Python using the standard library socket module. No extra dependencies beyond what you already use to sign Solana transactions.
Minimal Example
python
import socket
ENDPOINT = ("fra.blocksprint.io", 5000)
API_KEY = b"YOUR_API_KEY"
def send_udp(tx_bytes: bytes) -> None:
"""Fire-and-forget UDP submission. tx_bytes must be the serialized Solana transaction."""
pkt = bytes([len(API_KEY)]) + API_KEY + tx_bytes
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(pkt, ENDPOINT)
sock.close()Full Example: Sign + Send with solders
python
import socket
from solders.hash import Hash
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.system_program import TransferParams, transfer
from solders.transaction import VersionedTransaction
ENDPOINT = ("fra.blocksprint.io", 5000)
API_KEY = b"YOUR_API_KEY"
# One of your tip recipient addresses — see the Tipping doc for the full list
TIP_ADDRESS = Pubkey.from_string("YOUR_TIP_ADDRESS")
TIP_LAMPORTS = 1_000_000 # 0.001 SOL (minimum)
def build_and_send(payer: Keypair, recipient: Pubkey, amount_lamports: int, recent_blockhash: Hash) -> str:
instructions = [
# Your transfer
transfer(TransferParams(
from_pubkey=payer.pubkey(),
to_pubkey=recipient,
lamports=amount_lamports,
)),
# Tip
transfer(TransferParams(
from_pubkey=payer.pubkey(),
to_pubkey=TIP_ADDRESS,
lamports=TIP_LAMPORTS,
)),
]
message = Message.new_with_blockhash(instructions, payer.pubkey(), recent_blockhash)
tx = VersionedTransaction(message, [payer])
tx_bytes = bytes(tx) # Solana wire bytes
pkt = bytes([len(API_KEY)]) + API_KEY + tx_bytes
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(pkt, ENDPOINT)
sock.close()
return str(tx.signatures[0])
# Usage
payer = Keypair() # your wallet keypair
recent_blockhash = Hash.from_string("RECENT_BLOCKHASH") # from getLatestBlockhash on your own Solana RPC
signature = build_and_send(payer, Pubkey.from_string("RECIPIENT_ADDRESS"), 1_000_000, recent_blockhash)
print(f"Sent signature: {signature}")Reusing the Socket (High Throughput)
For bots submitting many transactions, create the socket once and reuse it:
python
import socket
class UdpSender:
def __init__(self, host: str, port: int, api_key: str):
self.endpoint = (host, port)
self.api_key = api_key.encode("ascii")
self.key_prefix = bytes([len(self.api_key)]) + self.api_key
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def send(self, tx_bytes: bytes) -> None:
self.sock.sendto(self.key_prefix + tx_bytes, self.endpoint)
def close(self) -> None:
self.sock.close()
# Usage
sender = UdpSender("fra.blocksprint.io", 5000, "YOUR_API_KEY")
try:
for tx_bytes in pending_transactions:
sender.send(tx_bytes)
finally:
sender.close()Async Version
python
import asyncio
import socket
class AsyncUdpSender:
def __init__(self, host: str, port: int, api_key: str):
self.endpoint = (host, port)
self.api_key = api_key.encode("ascii")
self.key_prefix = bytes([len(self.api_key)]) + self.api_key
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setblocking(False)
async def send(self, tx_bytes: bytes) -> None:
loop = asyncio.get_running_loop()
await loop.sock_sendto(self.sock, self.key_prefix + tx_bytes, self.endpoint)
async def main():
sender = AsyncUdpSender("fra.blocksprint.io", 5000, "YOUR_API_KEY")
await sender.send(tx_bytes)
asyncio.run(main())Notes
- No response.
sendtoreturns once the OS has accepted the packet — there is no acknowledgement from BlockSprint. Record the signature client-side and poll status yourself. - Silent drops. Invalid keys, missing tips or tips below 0.001 SOL, and rate-limit hits all cause silent drops with no error returned.
- MTU. Keep the total packet under ~1300 bytes (
1 + key_len + ≤ 1232tx bytes). - Transaction V1. Build it with
solders0.29 or later (MessageV1with aTransactionConfigthat sets the compute-unit limit and the loaded-accounts data size limit).bytes(tx)then gives the V1 wire bytes. Keep V1 datagrams within about 1,400 bytes, and send larger V1 transactions (up to 4,096 bytes) via QUIC or sendTransaction. - Encoding.
API_KEYmust be plain ASCII bytes — do not base64-encode or hash it.
