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 RpcError::ClientError(error) => error.kind.get_transaction_error().is_none(),
85 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 async fn confirm_transaction(&self, signature: Signature) -> Result<bool, RpcError>;
103
104 async fn get_account(&self, address: Pubkey) -> Result<Option<Account>, RpcError>;
106
107 async fn get_multiple_accounts(
109 &self,
110 addresses: &[Pubkey],
111 ) -> Result<Vec<Option<Account>>, RpcError>;
112
113 async fn get_anchor_account<T: BorshDeserialize>(
116 &self,
117 pubkey: &Pubkey,
118 ) -> Result<Option<T>, RpcError> {
119 match self.get_account(*pubkey).await? {
120 Some(account) => {
121 let data = T::deserialize(&mut &account.data[8..]).map_err(RpcError::from)?;
122 Ok(Some(data))
123 }
124 None => Ok(None),
125 }
126 }
127
128 async fn get_minimum_balance_for_rent_exemption(
129 &self,
130 data_len: usize,
131 ) -> Result<u64, RpcError>;
132
133 async fn airdrop_lamports(&mut self, to: &Pubkey, lamports: u64)
134 -> Result<Signature, RpcError>;
135
136 async fn get_balance(&self, pubkey: &Pubkey) -> Result<u64, RpcError>;
137 async fn get_latest_blockhash(&mut self) -> Result<(Hash, u64), RpcError>;
138 async fn get_slot(&self) -> Result<u64, RpcError>;
139 async fn get_transaction_slot(&self, signature: &Signature) -> Result<u64, RpcError>;
140 async fn get_signature_statuses(
141 &self,
142 signatures: &[Signature],
143 ) -> Result<Vec<Option<TransactionStatus>>, RpcError>;
144
145 async fn send_transaction(&self, transaction: &Transaction) -> Result<Signature, RpcError>;
146
147 async fn send_transaction_with_config(
148 &self,
149 transaction: &Transaction,
150 config: RpcSendTransactionConfig,
151 ) -> Result<Signature, RpcError>;
152
153 async fn process_transaction(
154 &mut self,
155 transaction: Transaction,
156 ) -> Result<Signature, RpcError>;
157
158 async fn process_transaction_with_context(
159 &mut self,
160 transaction: Transaction,
161 ) -> Result<(Signature, Slot), RpcError>;
162
163 async fn create_and_send_transaction_with_event<T>(
164 &mut self,
165 instructions: &[Instruction],
166 authority: &Pubkey,
167 signers: &[&Keypair],
168 ) -> Result<Option<(T, Signature, Slot)>, RpcError>
169 where
170 T: BorshDeserialize + Send + Debug;
171
172 async fn create_and_send_transaction<'a>(
173 &'a mut self,
174 instructions: &'a [Instruction],
175 payer: &'a Pubkey,
176 signers: &'a [&'a Keypair],
177 ) -> Result<Signature, RpcError> {
178 let blockhash = self.get_latest_blockhash().await?.0;
179 let mut transaction = Transaction::new_with_payer(instructions, Some(payer));
180 transaction
181 .try_sign(signers, blockhash)
182 .map_err(|e| RpcError::SigningError(e.to_string()))?;
183 self.process_transaction(transaction).await
184 }
185
186 async fn create_and_send_versioned_transaction<'a>(
187 &'a mut self,
188 instructions: &'a [Instruction],
189 payer: &'a Pubkey,
190 signers: &'a [&'a Keypair],
191 address_lookup_tables: &'a [AddressLookupTableAccount],
192 ) -> Result<Signature, RpcError>;
193
194 async fn create_and_send_transaction_with_public_event(
195 &mut self,
196 instruction: &[Instruction],
197 payer: &Pubkey,
198 signers: &[&Keypair],
199 ) -> Result<Option<(PublicTransactionEvent, Signature, Slot)>, RpcError>;
200
201 async fn create_and_send_transaction_with_batched_event(
202 &mut self,
203 instruction: &[Instruction],
204 payer: &Pubkey,
205 signers: &[&Keypair],
206 ) -> Result<Option<(Vec<BatchPublicTransactionEvent>, Signature, Slot)>, RpcError>;
207
208 fn indexer(&self) -> Result<&impl Indexer, RpcError>;
209 fn indexer_mut(&mut self) -> Result<&mut impl Indexer, RpcError>;
210
211 async fn get_latest_active_state_trees(&mut self) -> Result<Vec<TreeInfo>, RpcError>;
213
214 fn get_state_tree_infos(&self) -> Vec<TreeInfo>;
217
218 fn get_random_state_tree_info(&self) -> Result<TreeInfo, RpcError>;
222
223 fn get_random_state_tree_info_v1(&self) -> Result<TreeInfo, RpcError>;
226
227 fn get_address_tree_v1(&self) -> TreeInfo;
228
229 fn get_address_tree_v2(&self) -> TreeInfo;
230}