#[cfg(not(target_arch = "wasm32"))]
use tokio::time::{sleep, Duration};
use crate::{
error::{Result, RialoError},
rpc::{
traits::RpcClient,
types::{Signature, SignatureStatus},
},
};
#[cfg(not(target_arch = "wasm32"))]
#[tracing::instrument(skip(client))]
pub async fn wait_for_confirmation(
client: &impl RpcClient,
signature: &Signature,
timeout_ms: Option<u32>,
) -> Result<SignatureStatus> {
const CHECK_INTERVAL_MS: u32 = 50;
let timeout_ms = timeout_ms.unwrap_or(5000);
let max_attempts = timeout_ms.div_ceil(CHECK_INTERVAL_MS);
for _ in 0..max_attempts {
let statuses = client.get_signature_statuses(&[*signature]).await?;
if let Some(status) = statuses.into_iter().next() {
if status.executed {
return Ok(status);
}
}
sleep(Duration::from_millis(CHECK_INTERVAL_MS as u64)).await;
}
Err(RialoError::TransactionTimeout)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::rpc::mock_client::MockRpcClient;
#[cfg(not(target_arch = "wasm32"))]
#[tokio::test]
async fn test_confirmation_success_immediate() {
let mock_rpc = MockRpcClient::new().with_signature_statuses(vec![Some(SignatureStatus {
slot: 100,
executed: true,
err: None,
})]);
let signature = Signature::new_unique();
let result = wait_for_confirmation(&mock_rpc, &signature, None).await;
assert!(result.is_ok(), "Should confirm immediately");
let status = result.unwrap();
assert!(status.err.is_none(), "Should have no error");
}
#[cfg(not(target_arch = "wasm32"))]
#[tokio::test]
async fn test_confirmation_with_onchain_error() {
let mock_rpc = MockRpcClient::new().with_signature_statuses(vec![Some(SignatureStatus {
slot: 100,
executed: true,
err: Some("InstructionError: RegistryAlreadyInitialized".to_string()),
})]);
let signature = Signature::new_unique();
let result = wait_for_confirmation(&mock_rpc, &signature, None).await;
assert!(result.is_ok(), "Should return Ok even with on-chain error");
let status = result.unwrap();
assert!(status.err.is_some(), "Should have on-chain error");
assert!(status.err.unwrap().contains("RegistryAlreadyInitialized"));
}
#[cfg(not(target_arch = "wasm32"))]
#[tokio::test]
async fn test_confirmation_timeout() {
let mock_rpc = MockRpcClient::new().with_signature_statuses(vec![Some(SignatureStatus {
slot: 100,
err: None,
executed: false,
})]);
let signature = Signature::new_unique();
let result = wait_for_confirmation(&mock_rpc, &signature, Some(100)).await;
assert!(result.is_err(), "Should timeout");
assert!(
matches!(result.unwrap_err(), RialoError::TransactionTimeout),
"Should be TransactionTimeout error"
);
}
#[cfg(not(target_arch = "wasm32"))]
#[tokio::test]
async fn test_confirmation_with_custom_timeout() {
let mock_rpc = MockRpcClient::new().with_signature_statuses(vec![Some(SignatureStatus {
slot: 100,
err: None,
executed: true,
})]);
let signature = Signature::new_unique();
let result = wait_for_confirmation(&mock_rpc, &signature, Some(10000)).await;
assert!(result.is_ok(), "Should confirm with custom timeout");
}
}