111 lines
3.7 KiB
Rust
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();
|
|
} |