light_program_test/program_test/
test_rpc.rs

1use async_trait::async_trait;
2use light_client::rpc::{LightClient, Rpc, RpcError};
3use solana_account::Account;
4use solana_sdk::{clock::Slot, pubkey::Pubkey};
5#[cfg(feature = "devenv")]
6use {
7    borsh::BorshDeserialize,
8    light_client::fee::{assert_transaction_params, TransactionParams},
9    light_compressible::rent::SLOTS_PER_EPOCH,
10    light_event::event::{BatchPublicTransactionEvent, PublicTransactionEvent},
11    solana_sdk::{
12        clock::Clock,
13        instruction::Instruction,
14        signature::{Keypair, Signature},
15    },
16    std::{fmt::Debug, marker::Send},
17};
18
19#[cfg(feature = "devenv")]
20use crate::compressible::CompressibleAccountStore;
21use crate::program_test::LightProgramTest;
22
23#[async_trait]
24pub trait TestRpc: Rpc + Sized {
25    #[cfg(feature = "devenv")]
26    async fn create_and_send_transaction_with_batched_event(
27        &mut self,
28        instructions: &[Instruction],
29        payer: &Pubkey,
30        signers: &[&Keypair],
31        transaction_params: Option<light_client::fee::TransactionParams>,
32    ) -> Result<Option<(Vec<BatchPublicTransactionEvent>, Signature, Slot)>, RpcError> {
33        let pre_balance = self.get_balance(payer).await?;
34
35        let event = <Self as Rpc>::create_and_send_transaction_with_batched_event(
36            self,
37            instructions,
38            payer,
39            signers,
40        )
41        .await?;
42
43        light_client::fee::assert_transaction_params(
44            self,
45            payer,
46            signers,
47            pre_balance,
48            transaction_params,
49        )
50        .await?;
51
52        Ok(event)
53    }
54
55    #[cfg(feature = "devenv")]
56    async fn create_and_send_transaction_with_event<T>(
57        &mut self,
58        instructions: &[Instruction],
59        payer: &Pubkey,
60        signers: &[&Keypair],
61        transaction_params: Option<TransactionParams>,
62    ) -> Result<Option<(T, Signature, Slot)>, RpcError>
63    where
64        T: BorshDeserialize + Send + Debug,
65    {
66        let pre_balance = self.get_balance(payer).await?;
67
68        let result = <Self as Rpc>::create_and_send_transaction_with_event::<T>(
69            self,
70            instructions,
71            payer,
72            signers,
73        )
74        .await?;
75        assert_transaction_params(self, payer, signers, pre_balance, transaction_params).await?;
76
77        Ok(result)
78    }
79
80    #[cfg(feature = "devenv")]
81    async fn create_and_send_transaction_with_public_event(
82        &mut self,
83        instructions: &[Instruction],
84        payer: &Pubkey,
85        signers: &[&Keypair],
86        transaction_params: Option<TransactionParams>,
87    ) -> Result<Option<(PublicTransactionEvent, Signature, Slot)>, RpcError> {
88        let pre_balance = self.get_balance(payer).await?;
89
90        let res = <Self as Rpc>::create_and_send_transaction_with_batched_event(
91            self,
92            instructions,
93            payer,
94            signers,
95        )
96        .await?;
97        assert_transaction_params(self, payer, signers, pre_balance, transaction_params).await?;
98
99        let event = res.map(|e| (e.0[0].event.clone(), e.1, e.2));
100
101        Ok(event)
102    }
103
104    fn set_account(&mut self, address: Pubkey, account: Account);
105    fn warp_to_slot(&mut self, slot: Slot) -> Result<(), RpcError>;
106
107    /// Warps current slot forward by slots.
108    /// Claims and compresses compressible ctoken accounts.
109    #[cfg(feature = "devenv")]
110    async fn warp_slot_forward(&mut self, slot: Slot) -> Result<(), RpcError>;
111
112    /// Warps forward by the specified number of epochs.
113    /// Each epoch is SLOTS_PER_EPOCH slots.
114    #[cfg(feature = "devenv")]
115    async fn warp_epoch_forward(&mut self, epochs: u64) -> Result<(), RpcError> {
116        let slots_to_warp = epochs * SLOTS_PER_EPOCH;
117        self.warp_slot_forward(slots_to_warp).await
118    }
119}
120
121// Implementation required for E2ETestEnv.
122#[async_trait]
123impl TestRpc for LightClient {
124    fn set_account(&mut self, _address: Pubkey, _account: Account) {
125        unimplemented!()
126    }
127
128    fn warp_to_slot(&mut self, _slot: Slot) -> Result<(), RpcError> {
129        unimplemented!()
130    }
131
132    #[cfg(feature = "devenv")]
133    async fn warp_slot_forward(&mut self, _slot: Slot) -> Result<(), RpcError> {
134        unimplemented!()
135    }
136}
137
138#[async_trait]
139impl TestRpc for LightProgramTest {
140    fn set_account(&mut self, address: Pubkey, account: Account) {
141        self.context
142            .set_account(address, account)
143            .expect("Setting account failed.");
144    }
145
146    fn warp_to_slot(&mut self, slot: Slot) -> Result<(), RpcError> {
147        self.context.warp_to_slot(slot);
148        Ok(())
149    }
150
151    /// Warps current slot forward by slots.
152    /// Claims and compresses compressible ctoken accounts.
153    #[cfg(feature = "devenv")]
154    async fn warp_slot_forward(&mut self, slot: Slot) -> Result<(), RpcError> {
155        let mut current_slot = self.context.get_sysvar::<Clock>().slot;
156        current_slot += slot;
157        self.context.warp_to_slot(current_slot);
158        let mut store = CompressibleAccountStore::new();
159        crate::compressible::claim_and_compress(self, &mut store).await?;
160        Ok(())
161    }
162}