diff --git a/xtask/src/get_signatures.rs b/xtask/src/get_signatures.rs new file mode 100644 index 0000000000..384e808afb --- /dev/null +++ b/xtask/src/get_signatures.rs @@ -0,0 +1,117 @@ +use anyhow::Result; +use clap::Parser; +use solana_client::rpc_client::GetConfirmedSignaturesForAddress2Config; +use solana_client::rpc_client::RpcClient; +use solana_sdk::signature::Signature; +use std::fs::File; +use std::io::Write; +use std::str::FromStr; +use std::u64; + +#[derive(Parser)] +pub struct Options { + /// RPC URL to connect to + #[clap(long, default_value = "https://api.devnet.solana.com")] + pub rpc_url: String, + + /// Start searching backwards from this transaction signature + #[clap(long)] + pub before: Option, + + /// Search forward until this transaction signature + #[clap(long)] + pub until: Option, + /// Search forward until this transaction signature + #[clap(long)] + pub until_slot: Option, + /// Search forward until this transaction signature + #[clap(long)] + pub before_slot: Option, + /// Maximum number of signatures to return (default: 1000, max: 1000) + #[clap(long, default_value = "1000")] + pub limit: usize, +} + +pub async fn get_signatures(options: Options) -> Result<()> { + println!("Connecting to RPC: {}", options.rpc_url); + + let client = RpcClient::new(options.rpc_url); + + // Create target directory and file + std::fs::create_dir_all("target")?; + let mut file = File::create("target/signatures.txt")?; + + let mut latest_slot = u64::MAX; + let mut before = None; + let target_until_slot = options.until_slot.unwrap_or(0); + let target_before_slot = options.before_slot.unwrap_or(u64::MAX); + + while latest_slot > target_until_slot { + let config = GetConfirmedSignaturesForAddress2Config { + before, + until: None, + limit: Some(options.limit.min(1000)), // Cap at Solana's max limit + commitment: None, + }; + let signatures = + client.get_signatures_for_address_with_config(&account_compression::ID, config)?; + + println!("\nFound {} signatures:", signatures.len()); + println!( + "{:<88} {:<10} {:<10} {}", + "Signature", "Slot", "Block Time", "Error" + ); + println!("{}", "-".repeat(120)); + + for sig_info in signatures.iter() { + let slot = sig_info.slot; + + if slot > target_before_slot { + continue; + } + if slot < target_until_slot { + continue; + } + if sig_info.err.is_some() { + continue; + } + + // Write signature to file + writeln!(file, "{}", sig_info.signature)?; + + let block_time = sig_info + .block_time + .map(|t| t.to_string()) + .unwrap_or_else(|| "unknown".to_string()); + + let error = sig_info + .err + .as_ref() + .map(|e| format!("{:?}", e)) + .unwrap_or_else(|| "none".to_string()); + + println!( + "{:<88} {:<10} {:<10} {}", + sig_info.signature, sig_info.slot, block_time, error + ); + } + before = signatures + .last() + .map(|sig| Signature::from_str(&sig.signature).unwrap()); + + latest_slot = signatures.last().map(|sig| sig.slot).unwrap_or(u64::MAX); + println!("latest slot {}", latest_slot); + println!( + "until target slot {}", + latest_slot.saturating_sub(target_until_slot) + ); + if latest_slot < options.until_slot.unwrap() { + println!( + "Reached the specified slot {} {}", + latest_slot, + options.until_slot.unwrap() + ); + } + } + Ok(()) +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index df08d63a57..35c697bd15 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -8,6 +8,7 @@ mod create_update_protocol_config_ix; mod create_vkeyrs_from_gnark_key; mod export_photon_test_data; mod fee; +mod get_signatures; mod hash_set; mod new_deployment; mod type_sizes; @@ -57,6 +58,9 @@ enum Command { InitNewDeployment(new_deployment::Options), /// cargo xtask create-update-protocol-config --slot-length CreateUpdateProtocolConfigIx(create_update_protocol_config_ix::Options), + /// Get signatures for the Light System Program ID + /// Example: cargo xtask get-signatures --rpc-url https://api.devnet.solana.com --before --until --limit 50 + GetSignatures(get_signatures::Options), } #[tokio::main] @@ -89,5 +93,6 @@ async fn main() -> Result<(), anyhow::Error> { Command::CreateUpdateProtocolConfigIx(opts) => { create_update_protocol_config_ix::create_update_protocol_config_ix(opts).await } + Command::GetSignatures(opts) => get_signatures::get_signatures(opts).await, } }