light_client/rpc/
rpc_trait.rs

1use std::fmt::Debug;
2
3use async_trait::async_trait;
4use borsh::BorshDeserialize;
5use light_compressed_account::indexer_event::event::{
6    BatchPublicTransactionEvent, PublicTransactionEvent,
7};
8use solana_account::Account;
9use solana_clock::Slot;
10use solana_commitment_config::CommitmentConfig;
11use solana_hash::Hash;
12use solana_instruction::Instruction;
13use solana_keypair::Keypair;
14use solana_pubkey::Pubkey;
15use solana_rpc_client_api::config::RpcSendTransactionConfig;
16use solana_signature::Signature;
17use solana_transaction::Transaction;
18use solana_transaction_status_client_types::TransactionStatus;
19
20use super::client::RpcUrl;
21use crate::{
22    indexer::{Indexer, TreeInfo},
23    rpc::errors::RpcError,
24};
25
26#[derive(Debug, Clone)]
27pub struct LightClientConfig {
28    pub url: String,
29    pub commitment_config: Option<CommitmentConfig>,
30    pub with_indexer: bool,
31    pub fetch_active_tree: bool,
32}
33
34impl LightClientConfig {
35    pub fn new(url: String) -> Self {
36        Self {
37            url,
38            commitment_config: Some(CommitmentConfig::confirmed()),
39            with_indexer: true,
40            fetch_active_tree: true,
41        }
42    }
43    pub fn local_no_indexer() -> Self {
44        Self {
45            url: RpcUrl::Localnet.to_string(),
46            commitment_config: Some(CommitmentConfig::confirmed()),
47            with_indexer: false,
48            fetch_active_tree: false,
49        }
50    }
51
52    pub fn local() -> Self {
53        Self {
54            url: RpcUrl::Localnet.to_string(),
55            commitment_config: Some(CommitmentConfig::confirmed()),
56            with_indexer: true,
57            fetch_active_tree: false,
58        }
59    }
60
61    pub fn devnet() -> Self {
62        Self {
63            url: RpcUrl::Devnet.to_string(),
64            commitment_config: Some(CommitmentConfig::confirmed()),
65            with_indexer: true,
66            fetch_active_tree: true,
67        }
68    }
69}
70
71#[async_trait]
72pub trait Rpc: Send + Sync + Debug + 'static {
73    async fn new(config: LightClientConfig) -> Result<Self, RpcError>
74    where
75        Self: Sized;
76
77    fn should_retry(&self, error: &RpcError) -> bool {
78        match error {
79            // Do not retry transaction errors.
80            RpcError::ClientError(error) => error.kind.get_transaction_error().is_none(),
81            _ => true,
82        }
83    }
84
85    fn get_payer(&self) -> &Keypair;
86    fn get_url(&self) -> String;
87
88    async fn health(&self) -> Result<(), RpcError>;
89
90    async fn get_program_accounts(
91        &self,
92        program_id: &Pubkey,
93    ) -> Result<Vec<(Pubkey, Account)>, RpcError>;
94    // TODO: add send transaction with config
95
96    async fn confirm_transaction(&self, signature: Signature) -> Result<bool, RpcError>;
97
98    /// Returns an account struct.
99    async fn get_account(&self, address: Pubkey) -> Result<Option<Account>, RpcError>;
100
101    /// Returns an a borsh deserialized account.
102    /// Deserialization skips the discriminator.
103    async fn get_anchor_account<T: BorshDeserialize>(
104        &self,
105        pubkey: &Pubkey,
106    ) -> Result<Option<T>, RpcError> {
107        match self.get_account(*pubkey).await? {
108            Some(account) => {
109                let data = T::deserialize(&mut &account.data[8..]).map_err(RpcError::from)?;
110                Ok(Some(data))
111            }
112            None => Ok(None),
113        }
114    }
115
116    async fn get_minimum_balance_for_rent_exemption(
117        &self,
118        data_len: usize,
119    ) -> Result<u64, RpcError>;
120
121    async fn airdrop_lamports(&mut self, to: &Pubkey, lamports: u64)
122        -> Result<Signature, RpcError>;
123
124    async fn get_balance(&self, pubkey: &Pubkey) -> Result<u64, RpcError>;
125    async fn get_latest_blockhash(&mut self) -> Result<(Hash, u64), RpcError>;
126    async fn get_slot(&self) -> Result<u64, RpcError>;
127    async fn get_transaction_slot(&self, signature: &Signature) -> Result<u64, RpcError>;
128    async fn get_signature_statuses(
129        &self,
130        signatures: &[Signature],
131    ) -> Result<Vec<Option<TransactionStatus>>, RpcError>;
132
133    async fn send_transaction(&self, transaction: &Transaction) -> Result<Signature, RpcError>;
134
135    async fn send_transaction_with_config(
136        &self,
137        transaction: &Transaction,
138        config: RpcSendTransactionConfig,
139    ) -> Result<Signature, RpcError>;
140
141    async fn process_transaction(
142        &mut self,
143        transaction: Transaction,
144    ) -> Result<Signature, RpcError>;
145
146    async fn process_transaction_with_context(
147        &mut self,
148        transaction: Transaction,
149    ) -> Result<(Signature, Slot), RpcError>;
150
151    async fn create_and_send_transaction_with_event<T>(
152        &mut self,
153        instructions: &[Instruction],
154        authority: &Pubkey,
155        signers: &[&Keypair],
156    ) -> Result<Option<(T, Signature, Slot)>, RpcError>
157    where
158        T: BorshDeserialize + Send + Debug;
159
160    async fn create_and_send_transaction<'a>(
161        &'a mut self,
162        instructions: &'a [Instruction],
163        payer: &'a Pubkey,
164        signers: &'a [&'a Keypair],
165    ) -> Result<Signature, RpcError> {
166        let blockhash = self.get_latest_blockhash().await?.0;
167        let transaction =
168            Transaction::new_signed_with_payer(instructions, Some(payer), signers, blockhash);
169        self.process_transaction(transaction).await
170    }
171
172    async fn create_and_send_transaction_with_public_event(
173        &mut self,
174        instruction: &[Instruction],
175        payer: &Pubkey,
176        signers: &[&Keypair],
177    ) -> Result<Option<(PublicTransactionEvent, Signature, Slot)>, RpcError>;
178
179    async fn create_and_send_transaction_with_batched_event(
180        &mut self,
181        instruction: &[Instruction],
182        payer: &Pubkey,
183        signers: &[&Keypair],
184    ) -> Result<Option<(Vec<BatchPublicTransactionEvent>, Signature, Slot)>, RpcError>;
185
186    fn indexer(&self) -> Result<&impl Indexer, RpcError>;
187    fn indexer_mut(&mut self) -> Result<&mut impl Indexer, RpcError>;
188
189    /// Fetch the latest state tree addresses from the cluster.
190    async fn get_latest_active_state_trees(&mut self) -> Result<Vec<TreeInfo>, RpcError>;
191
192    /// Gets state tree infos.
193    /// State trees are cached and have to be fetched or set.
194    fn get_state_tree_infos(&self) -> Vec<TreeInfo>;
195
196    /// Gets a random state tree info.
197    /// State trees are cached and have to be fetched or set.
198    fn get_random_state_tree_info(&self) -> Result<TreeInfo, RpcError>;
199
200    fn get_address_tree_v1(&self) -> TreeInfo;
201
202    // TODO: add with v2 release
203    // fn get_address_tree_v2(&self) -> Result<Vec<Pubkey>, RpcError>;
204}