Skip to content

Instantly share code, notes, and snippets.

@ssadler
Created May 21, 2025 14:57
Show Gist options
  • Select an option

  • Save ssadler/e2830d6f969d23eeb3f571877344c53a to your computer and use it in GitHub Desktop.

Select an option

Save ssadler/e2830d6f969d23eeb3f571877344c53a to your computer and use it in GitHub Desktop.
use bincode::deserialize;
use litesvm::types::{FailedTransactionMetadata, SimulatedTransactionInfo, TransactionResult};
use litesvm::LiteSVM;
use solana_transaction::Transaction;
#[get("/")]
async fn index() -> &'static str {
"Hi!"
}
#[get("/latest_blockhash")]
async fn latest_blockhash(litesvm: Session) -> Json<String> {
Json(litesvm.lock().latest_blockhash().to_string())
}
#[get("/get_sigverify")]
async fn get_sigverify(litesvm: Session) -> Json<bool> {
Json(litesvm.lock().get_sigverify())
}
#[get("/get_clock")]
async fn get_clock(litesvm: Session) -> Json<solana_clock::Clock> {
Json(litesvm.lock().get_sysvar::<solana_clock::Clock>())
}
#[get("/get_account")]
async fn get_account(litesvm: Session, args: Query<GetAccount>) -> Json<Option<solana_account::Account>> {
let account = litesvm.lock().get_account(&args.pubkey);
eprintln!("{:?}", account);
Json(litesvm.lock().get_account(&args.pubkey))
}
#[derive(serde::Deserialize)]
struct GetAccount { pubkey: Pubkey }
#[post("/airdrop")]
async fn airdrop(litesvm: Session, args: Query<Airdrop>) -> Json<TransactionResult> {
Json(litesvm.lock().airdrop(&args.pubkey, args.lamports))
}
#[derive(serde::Deserialize)]
struct Airdrop { pubkey: Pubkey, lamports: u64 }
#[post("/expire_blockhash")]
async fn expire_blockhash(litesvm: Session) -> Json<()> {
Json(litesvm.lock().expire_blockhash())
}
#[post("/simulate_transaction")]
async fn simulate_transaction(litesvm: Session, input: Bytes)
-> Json<Result<SimulatedTransactionInfo, FailedTransactionMetadata>>
{
let litesvm = litesvm.lock().clone().with_sigverify(false);
let tx: Transaction = deserialize(&input).unwrap();
let res = litesvm.simulate_transaction(tx);
Json(res)
}
#[post("/send_transaction")]
async fn send_transaction(litesvm: Session, input: Bytes) -> Json<TransactionResult> {
let tx: Transaction = deserialize(&input).unwrap();
let res = litesvm.lock().send_transaction(tx);
Json(res)
}
#[post("/add_program_from_file")]
async fn add_program_from_file(litesvm: Session, args: Query<AddProgramFromFile>) -> &'static str {
litesvm.lock().add_program_from_file(*args.program_id, &args.path).unwrap();
""
}
#[derive(serde::Deserialize)]
struct AddProgramFromFile { program_id: Pubkey, path: String }
use std::str::FromStr;
use std::collections::HashMap;
use std::future::ready;
use std::sync::Arc;
use parking_lot::Mutex;
struct Session(Arc<Mutex<LiteSVM>>);
impl std::ops::Deref for Session {
type Target = Arc<Mutex<LiteSVM>>;
fn deref(&self) -> &Self::Target { &self.0 }
}
struct Sessions(Mutex<HashMap<String, Arc<Mutex<LiteSVM>>>>);
impl Sessions {
pub fn new() -> Self {
Sessions(Default::default())
}
}
use std::{convert::Infallible, future::Ready};
use actix_web::web::{Bytes, Data, Json, Query};
use actix_web::middleware::Logger;
use actix_web::{get, post, web, App, FromRequest, HttpServer};
impl FromRequest for Session {
type Future = Ready<Result<Session, Infallible>>;
type Error = Infallible;
fn from_request(req: &actix_web::HttpRequest, _payload: &mut actix_web::dev::Payload) -> Self::Future {
let session_id = req.match_info().get("session_id").unwrap();
let state = req.app_data::<Data<Sessions>>().unwrap();
let m = state.0.lock()
.entry(session_id.to_string())
.or_insert_with(|| Arc::new(Mutex::new(LiteSVM::new()))).clone();
ready(Ok(Session(m)))
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
let sessions = Data::new(Sessions::new());
HttpServer::new(move || {
App::new()
.wrap(Logger::default())
.app_data(sessions.clone())
.service(index)
.service(
web::scope("/chain/{session_id}")
.service(latest_blockhash)
.service(get_sigverify)
.service(get_clock)
.service(get_account)
.service(airdrop)
.service(expire_blockhash)
.service(add_program_from_file)
.service(simulate_transaction)
.service(send_transaction)
.service(add_program_from_file)
)
})
.bind(("127.0.0.1", 8088))?
.run()
.await
}
struct Pubkey(solana_pubkey::Pubkey);
impl<'de> serde::Deserialize<'de> for Pubkey {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
solana_pubkey::Pubkey::from_str(s.as_str()).map(Pubkey)
.map_err(|_| serde::de::Error::custom("invalid pubkey"))
}
}
impl std::ops::Deref for Pubkey {
type Target = solana_pubkey::Pubkey;
fn deref(&self) -> &Self::Target { &self.0 }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment