light_program_test/program_test/
test_rpc.rs

1use async_trait::async_trait;
2use light_client::rpc::{LightClient, Rpc, RpcError};
3use light_compressible::rent::SLOTS_PER_EPOCH;
4use solana_account::Account;
5use solana_sdk::{
6    clock::{Clock, Slot},
7    pubkey::Pubkey,
8};
9#[cfg(feature = "devenv")]
10use {
11    borsh::BorshDeserialize,
12    light_client::fee::{assert_transaction_params, TransactionParams},
13    light_event::event::{BatchPublicTransactionEvent, PublicTransactionEvent},
14    solana_sdk::{
15        instruction::Instruction,
16        signature::{Keypair, Signature},
17    },
18    std::{fmt::Debug, marker::Send},
19};
20
21use crate::{compressible::CompressibleAccountStore, 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    async fn warp_slot_forward(&mut self, slot: Slot) -> Result<(), RpcError>;
110
111    /// Warps forward by the specified number of epochs.
112    /// Each epoch is SLOTS_PER_EPOCH slots.
113    async fn warp_epoch_forward(&mut self, epochs: u64) -> Result<(), RpcError> {
114        let slots_to_warp = epochs * SLOTS_PER_EPOCH;
115        self.warp_slot_forward(slots_to_warp).await
116    }
117}
118
119// Implementation required for E2ETestEnv.
120#[async_trait]
121impl TestRpc for LightClient {
122    fn set_account(&mut self, _address: Pubkey, _account: Account) {
123        unimplemented!()
124    }
125
126    fn warp_to_slot(&mut self, _slot: Slot) -> Result<(), RpcError> {
127        unimplemented!()
128    }
129
130    async fn warp_slot_forward(&mut self, _slot: Slot) -> Result<(), RpcError> {
131        unimplemented!()
132    }
133}
134
135#[async_trait]
136impl TestRpc for LightProgramTest {
137    fn set_account(&mut self, address: Pubkey, account: Account) {
138        self.context
139            .set_account(address, account)
140            .expect("Setting account failed.");
141    }
142
143    fn warp_to_slot(&mut self, slot: Slot) -> Result<(), RpcError> {
144        self.context.warp_to_slot(slot);
145        Ok(())
146    }
147
148    /// Warps current slot forward by slots.
149    /// Claims and compresses compressible ctoken accounts and program PDAs (auto compress).
150    async fn warp_slot_forward(&mut self, slot: Slot) -> Result<(), RpcError> {
151        let mut current_slot = self.context.get_sysvar::<Clock>().slot;
152        current_slot += slot;
153        self.context.warp_to_slot(current_slot);
154        let mut store = CompressibleAccountStore::new();
155        crate::compressible::claim_and_compress(self, &mut store).await?;
156        for program_id in self.auto_mine_cold_state_programs.clone() {
157            crate::compressible::auto_compress_program_pdas(self, program_id).await?;
158        }
159        Ok(())
160    }
161}