light_client/rpc/
rpc_trait.rs

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