wp-solana-test-core 0.1.1

Protocol-agnostic Solana test infrastructure built on LiteSVM
Documentation
//! Transaction execution helpers for [`TestContext`].
//!
//! These are async because they go through the mock RPC client, which is
//! itself async.

use anyhow::Result;
use solana_client::rpc_config::RpcTransactionConfig;
use solana_sdk::{
    instruction::Instruction,
    signature::{Keypair, Signature, Signer},
    transaction::Transaction,
};
use solana_transaction_status::{option_serializer::OptionSerializer, UiTransactionEncoding};

use crate::context::TestContext;

/// Build, sign, and send a transaction through the mock RPC client.
///
/// The payer from `ctx` is always included as the first signer.
pub async fn execute(
    ctx: &TestContext,
    ixs: &[Instruction],
    additional_signers: &[&Keypair],
) -> Result<Signature> {
    let blockhash = ctx.rpc.get_latest_blockhash().await?;

    let mut signers: Vec<&Keypair> = vec![ctx.payer.as_ref()];
    signers.extend(additional_signers);

    let tx =
        Transaction::new_signed_with_payer(ixs, Some(&ctx.payer.pubkey()), &signers, blockhash);

    let sig = ctx.rpc.send_and_confirm_transaction(&tx).await?;
    Ok(sig)
}

/// Execute a transaction and return the signature together with program logs.
pub async fn execute_with_logs(
    ctx: &TestContext,
    ixs: &[Instruction],
    additional_signers: &[&Keypair],
) -> Result<(Signature, Vec<String>)> {
    let sig = execute(ctx, ixs, additional_signers).await?;

    let config = RpcTransactionConfig {
        encoding: Some(UiTransactionEncoding::Json),
        commitment: None,
        max_supported_transaction_version: Some(0),
    };

    let tx_detail = ctx.rpc.get_transaction_with_config(&sig, config).await?;

    let logs = tx_detail
        .transaction
        .meta
        .and_then(|m| match m.log_messages {
            OptionSerializer::Some(v) => Some(v),
            _ => None,
        })
        .unwrap_or_default();

    Ok((sig, logs))
}