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::{versioned::VersionedTransaction, 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>,
32 pub fetch_active_tree: bool,
33}
34
35impl LightClientConfig {
36 pub fn new(url: String, photon_url: Option<String>) -> Self {
37 Self {
38 url,
39 photon_url,
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 fetch_active_tree: false,
50 }
51 }
52
53 pub fn local() -> Self {
54 Self {
55 url: RpcUrl::Localnet.to_string(),
56 commitment_config: Some(CommitmentConfig::processed()),
57 photon_url: Some("http://127.0.0.1:8784".to_string()),
58 fetch_active_tree: false,
59 }
60 }
61
62 pub fn devnet(photon_url: Option<String>) -> Self {
63 Self {
64 url: RpcUrl::Devnet.to_string(),
65 photon_url,
66 commitment_config: Some(CommitmentConfig::confirmed()),
67 fetch_active_tree: true,
68 }
69 }
70}
71
72#[async_trait]
73pub trait Rpc: Send + Sync + Debug + 'static {
74 async fn new(config: LightClientConfig) -> Result<Self, RpcError>
75 where
76 Self: Sized;
77
78 fn should_retry(&self, error: &RpcError) -> bool {
79 match error {
80 RpcError::ClientError(error) => error.kind.get_transaction_error().is_none(),
82 RpcError::SigningError(_) | RpcError::TransactionBuildError(_) => false,
84 _ => true,
85 }
86 }
87
88 fn get_payer(&self) -> &Keypair;
89 fn get_url(&self) -> String;
90
91 async fn health(&self) -> Result<(), RpcError>;
92
93 async fn get_program_accounts(
94 &self,
95 program_id: &Pubkey,
96 ) -> Result<Vec<(Pubkey, Account)>, RpcError>;
97
98 async fn get_program_accounts_with_discriminator(
99 &self,
100 program_id: &Pubkey,
101 discriminator: &[u8],
102 ) -> Result<Vec<(Pubkey, Account)>, RpcError>;
103
104 async fn confirm_transaction(&self, signature: Signature) -> Result<bool, RpcError>;
107
108 async fn get_account(&self, address: Pubkey) -> Result<Option<Account>, RpcError>;
110
111 async fn get_multiple_accounts(
113 &self,
114 addresses: &[Pubkey],
115 ) -> Result<Vec<Option<Account>>, RpcError>;
116
117 async fn get_anchor_account<T: BorshDeserialize>(
120 &self,
121 pubkey: &Pubkey,
122 ) -> Result<Option<T>, RpcError> {
123 match self.get_account(*pubkey).await? {
124 Some(account) => {
125 let data = T::deserialize(&mut &account.data[8..]).map_err(RpcError::from)?;
126 Ok(Some(data))
127 }
128 None => Ok(None),
129 }
130 }
131
132 async fn get_minimum_balance_for_rent_exemption(
133 &self,
134 data_len: usize,
135 ) -> Result<u64, RpcError>;
136
137 async fn airdrop_lamports(&mut self, to: &Pubkey, lamports: u64)
138 -> Result<Signature, RpcError>;
139
140 async fn get_balance(&self, pubkey: &Pubkey) -> Result<u64, RpcError>;
141 async fn get_latest_blockhash(&mut self) -> Result<(Hash, u64), RpcError>;
142 async fn get_block_height(&self) -> Result<u64, RpcError>;
143 async fn get_slot(&self) -> Result<u64, RpcError>;
144 async fn get_transaction_slot(&self, signature: &Signature) -> Result<u64, RpcError>;
145 async fn get_signature_statuses(
146 &self,
147 signatures: &[Signature],
148 ) -> Result<Vec<Option<TransactionStatus>>, RpcError>;
149
150 async fn send_transaction(&self, transaction: &Transaction) -> Result<Signature, RpcError>;
151
152 async fn send_transaction_with_config(
153 &self,
154 transaction: &Transaction,
155 config: RpcSendTransactionConfig,
156 ) -> Result<Signature, RpcError>;
157
158 async fn send_versioned_transaction_with_config(
159 &self,
160 transaction: &VersionedTransaction,
161 config: RpcSendTransactionConfig,
162 ) -> Result<Signature, RpcError>;
163
164 async fn process_transaction(
165 &mut self,
166 transaction: Transaction,
167 ) -> Result<Signature, RpcError>;
168
169 async fn process_versioned_transaction(
170 &mut self,
171 transaction: VersionedTransaction,
172 ) -> Result<Signature, RpcError>;
173
174 async fn process_transaction_with_context(
175 &mut self,
176 transaction: Transaction,
177 ) -> Result<(Signature, Slot), RpcError>;
178
179 async fn create_and_send_transaction_with_event<T>(
180 &mut self,
181 instructions: &[Instruction],
182 authority: &Pubkey,
183 signers: &[&Keypair],
184 ) -> Result<Option<(T, Signature, Slot)>, RpcError>
185 where
186 T: BorshDeserialize + Send + Debug;
187
188 async fn create_and_send_transaction<'a>(
189 &'a mut self,
190 instructions: &'a [Instruction],
191 payer: &'a Pubkey,
192 signers: &'a [&'a Keypair],
193 ) -> Result<Signature, RpcError> {
194 let blockhash = self.get_latest_blockhash().await?.0;
195 let mut transaction = Transaction::new_with_payer(instructions, Some(payer));
196 transaction
197 .try_sign(signers, blockhash)
198 .map_err(|e| RpcError::SigningError(e.to_string()))?;
199 self.process_transaction(transaction).await
200 }
201
202 async fn create_and_send_versioned_transaction<'a>(
203 &'a mut self,
204 instructions: &'a [Instruction],
205 payer: &'a Pubkey,
206 signers: &'a [&'a Keypair],
207 address_lookup_tables: &'a [AddressLookupTableAccount],
208 ) -> Result<Signature, RpcError>;
209
210 async fn create_and_send_transaction_with_public_event(
211 &mut self,
212 instruction: &[Instruction],
213 payer: &Pubkey,
214 signers: &[&Keypair],
215 ) -> Result<Option<(PublicTransactionEvent, Signature, Slot)>, RpcError>;
216
217 async fn create_and_send_transaction_with_batched_event(
218 &mut self,
219 instruction: &[Instruction],
220 payer: &Pubkey,
221 signers: &[&Keypair],
222 ) -> Result<Option<(Vec<BatchPublicTransactionEvent>, Signature, Slot)>, RpcError>;
223
224 fn indexer(&self) -> Result<&impl Indexer, RpcError>;
225 fn indexer_mut(&mut self) -> Result<&mut impl Indexer, RpcError>;
226
227 async fn get_latest_active_state_trees(&mut self) -> Result<Vec<TreeInfo>, RpcError>;
229
230 fn get_state_tree_infos(&self) -> Vec<TreeInfo>;
233
234 fn get_random_state_tree_info(&self) -> Result<TreeInfo, RpcError>;
238
239 fn get_random_state_tree_info_v1(&self) -> Result<TreeInfo, RpcError>;
242
243 fn get_address_tree_v1(&self) -> TreeInfo;
244
245 fn get_address_tree_v2(&self) -> TreeInfo;
246}