Framework for building Jito BAM external scheduler plugins on Solana.
Built by reverse-engineering the agave-scheduler-bindings interface before the official ACE Plugin SDK release.
When connected to a BAM-enabled Solana validator, your plugin becomes the transaction scheduler — you control which transactions enter blocks and in what order.
TPU (transactions) → shared memory → YOUR PLUGIN → shared memory → validator workers → block
Communication via zero-copy shared memory (no serialization overhead):
- shaq — lock-free SPSC queues for message passing
- rts-alloc — shared memory allocator for transaction data
- Unix domain socket + SCM_RIGHTS — handshake and FD transfer
cargo build --release --example priority-scheduler# Terminal 1: Start test validator
solana-test-validator --reset --ledger ./test-ledger --enable-scheduler-bindings
# Terminal 2: Connect plugin
BAM_SOCKET_PATH=./test-ledger/scheduler_bindings.ipc \
cargo run --release --example priority-scheduler
# Terminal 3: Send transactions
solana airdrop 5 && solana transfer <ADDR> 0.001 --allow-unfunded-recipient[INFO] Connected! 2 workers
[INFO] Scheduler running
[INFO] [STATS] rx=6 sched=6 ok=6/6
[dependencies]
bam-plugin-sdk = { path = "../bam-plugin-sdk" }use bam_plugin_sdk::{handshake, bindings::*};
let logon = handshake::ClientLogon {
worker_count: 2,
allocator_size: 64 * 1024 * 1024,
allocator_handles: 4,
tpu_to_pack_capacity: 16384,
progress_tracker_capacity: 256,
pack_to_worker_capacity: 1024,
worker_to_pack_capacity: 1024,
flags: 0,
};
let mut session = handshake::connect(
"/path/to/scheduler_bindings.ipc",
logon,
Duration::from_secs(5),
)?;
// Receive transactions
session.tpu_to_pack.sync();
while let Some(msg) = session.tpu_to_pack.try_read() {
// msg.transaction — raw TX bytes in shared memory
// msg.flags — vote/forwarded/staked
// msg.src_addr — sender IP
session.tpu_to_pack.finalize();
}
// Send batch for execution
let batch_msg = PackToWorkerMessage {
flags: pack_message_flags::EXECUTE,
max_working_slot: current_slot,
batch: /* ... */,
};
worker.pack_to_worker.try_write(batch_msg)?;
worker.pack_to_worker.commit();| Module | Description |
|---|---|
bindings |
#[repr(C)] message types for shared memory IPC |
handshake |
Unix socket + SCM_RIGHTS connection to validator |
tx_parser |
Raw transaction parser (priority fees, program IDs, accounts) |
consumer.sync()is required beforetry_read()— without it, the consumer never sees new messages- Only
EXECUTEflag (0x01) is accepted —DROP_ON_FAILUREandALL_OR_NOTHINGcauseINVALIDresponses - Protocol version 2 — must match
agave-scheduler-bindingsinbam-client
# Build BAM-enabled validator (one time)
git clone https://github.com/jito-labs/bam-client
cd bam-client && git submodule update --init --recursive
sudo apt-get install -y libclang-dev clang protobuf-compiler
cargo build --release -p agave-validatorMIT