Files
lapa_v3/src/utils.rs

111 lines
3.7 KiB
Rust

use std::path::{Path, PathBuf};
use std::fs as std_fs;
use std::time::{SystemTime, UNIX_EPOCH};
use std::convert::TryFrom;
use tracing_subscriber::EnvFilter;
use anyhow::{anyhow, Context, Result};
use bs58;
use tokio::fs;
use yellowstone_grpc_proto::geyser::SubscribeUpdateTransaction;
use yellowstone_grpc_proto::prost::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, Signer};
/// Carga un keypair desde un JSON (array de 64 u 32 enteros) y devuelve (Keypair, Pubkey).
/// - 64 bytes: clave secreta completa (secret + public) -> `Keypair::from_bytes`.
/// - 32 bytes: semilla ed25519 -> `Keypair::from_seed`.
pub fn load_keypair_and_pubkey_from_json() -> Result<(Keypair, Pubkey)> {
let wallet_path = std::env::var("WALLET_PATH")?;
let path_ref = Path::new(&wallet_path);
let data = std_fs::read_to_string(path_ref)
.with_context(|| format!("Leyendo wallet JSON: {}", path_ref.display()))?;
// Parse JSON array of integers into Vec<u8>
let vec_bytes: Vec<u8> = serde_json::from_str(&data)
.with_context(|| "Parseando JSON de la wallet (se espera array de enteros)")?;
let kp = match vec_bytes.len() {
64 => {
// from_bytes returns Result<Keypair, _>
Keypair::try_from(&vec_bytes[..])
.map_err(|e| anyhow!("Keypair::try_from falló (¿array de 64 bytes válido?): {e}"))?
}
32 => {
let mut seed = [0u8; 32];
seed.copy_from_slice(&vec_bytes);
// new_from_array exists in solana-keypair and constructs from a 32-byte secret
Keypair::new_from_array(seed)
}
n => {
return Err(anyhow!(
"Formato de wallet no soportado: se esperaban 64 o 32 bytes, recibidos {n}"
))
}
};
let pubkey = kp.pubkey();
Ok((kp, pubkey))
}
// Save file from tx received
pub async fn save_tx_update(txu: &SubscribeUpdateTransaction) -> Result<(PathBuf, PathBuf)> {
// 1) Carpetas
let base = PathBuf::from("./logs/frames");
let bin_dir = base.join("bin");
let txt_dir = base.join("txt");
fs::create_dir_all(&bin_dir).await?;
fs::create_dir_all(&txt_dir).await?;
// 2) Timestamp (ms) + slot + firma corta (si existe)
let ts_ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis();
let slot = txu.slot;
// Firma corta integrada aquí (si existe)
let sig_short = if let Some(ref tx) = txu.transaction {
if !tx.signature.is_empty() {
// firma viene como bytes -> base58 -> recorta
bs58::encode(&tx.signature).into_string().chars().take(12).collect::<String>()
} else {
"nosig".to_string()
}
} else {
"nosig".to_string()
};
// 3) Nombres de archivo
let bin_name = format!("{}_slot{}_{}_tx.bin", ts_ms, slot, sig_short);
let txt_name = format!("{}_slot{}_{}_tx.txt", ts_ms, slot, sig_short);
let bin_path = bin_dir.join(bin_name);
let txt_path = txt_dir.join(txt_name);
// 4) BIN: protobuf crudo
let bytes = txu.encode_to_vec();
fs::write(&bin_path, &bytes).await?;
// 5) TXT: volcado legible
let pretty = format!("{:#?}", txu);
fs::write(&txt_path, pretty).await?;
Ok((bin_path, txt_path))
}
pub fn init_tracing() {
let filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("info"));
// No peta si ya estaba inicializado (devuelve Err y lo ignoramos)
let _ = tracing_subscriber::fmt()
.with_env_filter(filter)
.with_target(false)
.try_init();
}