Surfpool v1.4.0: Jito bundle simulation, slot subscriptions, and snapshot exports
Surfpool v1.4.0 ships simulateBundle for local Jito bundle testing, slotUpdatesSubscribe for real-time slot streaming, and filtered snapshot exports. Plus four bug fixes that affect snapshot loading and getSignaturesForAddress.
Surfpool v1.4.0 dropped on June 20th with three new features and four bug fixes. The headline is simulateBundle — local execution of Jito bundles, which makes Surfpool useful for the MEV and bundle-aware part of the Solana ecosystem that previously had no clean local testing path.
If you're new to Surfpool, start with the overview. This article covers what's new in this release.
simulateBundle: test Jito bundles locally
Jito bundles are groups of up to five transactions that execute atomically — all succeed or all fail, in order, with no other transactions interleaved. They're how MEV bots and sophisticated protocols guarantee ordering and atomicity on Solana. Until now, testing bundle logic meant either deploying to mainnet or building a bespoke simulation harness.
v1.4.0 adds simulateBundle directly to Surfpool's RPC surface. Pass an array of transactions; they execute against your local (possibly mainnet-forked) state in atomic sequence, returning per-transaction results and logs:
import { Connection, Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"
const connection = new Connection("http://localhost:8899")
// Build two transactions that must execute atomically
const tx1 = new Transaction().add(
SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: recipient1,
lamports: 1 * LAMPORTS_PER_SOL,
})
)
const tx2 = new Transaction().add(
SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: recipient2,
lamports: 0.5 * LAMPORTS_PER_SOL,
})
)
// Simulate as an atomic Jito bundle
const result = await connection.rpcRequest("simulateBundle", [
{
transactions: [
tx1.serialize({ requireAllSignatures: false }).toString("base64"),
tx2.serialize({ requireAllSignatures: false }).toString("base64"),
],
},
{ encoding: "base64" },
])
// result.value contains per-tx simulation results
for (const txResult of result.value.transactionResults) {
console.log("err:", txResult.err)
console.log("logs:", txResult.logs)
console.log("units consumed:", txResult.unitsConsumed)
}The practical use case: test your arbitrage logic, liquidation bundle, or any atomicity-dependent flow against real mainnet account state (fork it first with surfpool start --fork mainnet) before submitting a single bundle to a Jito block engine.
slotUpdatesSubscribe: WebSocket slot streaming
v1.4.0 implements the slotUpdatesSubscribe WebSocket method — part of the standard Solana RPC WebSocket spec but previously missing from Surfpool. It pushes granular slot lifecycle events in real time: firstShredReceived, completed, createdBank, frozen, dead, and optimisticallyConfirmed.
import WebSocket from "ws"
const ws = new WebSocket("ws://localhost:8900")
ws.on("open", () => {
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "slotUpdatesSubscribe",
}))
})
ws.on("message", (data) => {
const msg = JSON.parse(data.toString())
if (msg.method === "slotNotification") {
const { slot, type, timestamp } = msg.params.result
console.log(`slot ${slot} → ${type} at ${timestamp}`)
}
})This fills the last remaining gap between Surfpool's WebSocket surface and what a production RPC exposes. If your app uses slotUpdatesSubscribe to drive optimistic UI updates or slot-aware logic, it now works identically against the local validator.
surfnet_exportSnapshot with filters
surfnet_exportSnapshot already let you export current local state as a snapshot file. v1.4.0 adds two filter parameters:
- Sysvar filter — include or exclude sysvar accounts (
SysvarClock,SysvarEpochSchedule, etc.) from the export. Useful when you want a clean snapshot that doesn't bake in a specific timestamp or epoch. - Feature-gate filter — include or exclude feature-gate accounts. When importing a snapshot into a network with a different feature set, you typically want to strip these so the destination validator's own features take effect.
# Export snapshot excluding sysvars and feature gates
curl -X POST http://localhost:8899 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "surfnet_exportSnapshot",
"params": [{
"excludeSysvars": true,
"excludeFeatureGates": true
}]
}'Bug fixes
Four fixes worth knowing about if you hit these edges before:
- SlotHashes sysvar for initial slots. The first 31 slots after startup were missing
SlotHashessysvar data, which caused programs that read slot history to fail or behave incorrectly immediately after boot. Fixed in PR #686. - Snapshot loading order. When loading a snapshot, programdata accounts were being processed after program accounts. This caused upgradeable programs to fail to load correctly from snapshots. Fixed in PR #687 — programdata now loads first.
getSignaturesForAddressmemo and block_time. For transactions executed locally (not forked from mainnet),getSignaturesForAddresswas returning null for bothmemoandblockTime. Fixed in PR #693 — both are now populated correctly. This affects any code that indexes or displays local transaction history.- Pinocchio in Framework::FromStr. The CLI framework parser now handles Pinocchio as a valid framework identifier (PR #689), replacing the previous
todo!()panic with a properunimplemented!()error. Relevant if you use Pinocchio and run into framework detection in the CLI.
Upgrade
# Re-run the installer to get v1.4.0
curl -sL https://run.surfpool.run/ | bash
# Confirm version
surfpool --version
# surfpool 1.4.0References
Keep reading
Drop-in alternative to solana-test-validator. Fork Mainnet state on demand, set any account or token balance via RPC cheatcodes, deploy via Infrastructure-as-Code, watch it in a real-time dashboard.
Restaking lets your staked SOL pull double duty: secure Solana, then secure other services for extra yield. Jito coined NCNs, Solayer split endogenous vs exogenous AVS, Fragmetric built it on Token-2022. The model, the three players, and the honest question — where's the real slashing risk and demand?
No public mempool, leader-based blocks, off-chain orderflow — MEV on Solana looks nothing like Ethereum. It runs through Jito's bundle auctions; sandwiching migrated to private validator deals after Jito killed its mempool in 2024. swQoS, and Paladin's economic counter-attack. The mechanics.