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_pubkey::Pubkey;
13use solana_rpc_client_api::config::RpcSendTransactionConfig;
14use solana_signature::Signature;
15use solana_transaction::Transaction;
16use solana_transaction_status_client_types::TransactionStatus;
17
18use super::client::RpcUrl;
19use crate::{
20 indexer::{Indexer, TreeInfo},
21 rpc::errors::RpcError,
22};
23
24#[derive(Debug, Clone)]
25pub struct LightClientConfig {
26 pub url: String,
27 pub commitment_config: Option<CommitmentConfig>,
28 pub photon_url: Option<String>,
29 pub api_key: Option<String>,
30 pub fetch_active_tree: bool,
31}
32
33impl LightClientConfig {
34 pub fn new(url: String, photon_url: Option<String>, api_key: Option<String>) -> Self {
35 Self {
36 url,
37 photon_url,
38 api_key,
39 commitment_config: Some(CommitmentConfig::confirmed()),
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 photon_url: None,
48 api_key: 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::confirmed()),
57 photon_url: Some("http://127.0.0.1:8784".to_string()),
58 api_key: None,
59 fetch_active_tree: false,
60 }
61 }
62
63 pub fn devnet(photon_url: Option<String>, api_key: Option<String>) -> Self {
64 Self {
65 url: RpcUrl::Devnet.to_string(),
66 photon_url,
67 api_key,
68 commitment_config: Some(CommitmentConfig::confirmed()),
69 fetch_active_tree: true,
70 }
71 }
72}
73
74#[async_trait]
75pub trait Rpc: Send + Sync + Debug + 'static {
76 async fn new(config: LightClientConfig) -> Result<Self, RpcError>
77 where
78 Self: Sized;
79
80 fn should_retry(&self, error: &RpcError) -> bool {
81 match error {
82 RpcError::ClientError(error) => error.kind.get_transaction_error().is_none(),
84 RpcError::SigningError(_) => false,
86 _ => true,
87 }
88 }
89
90 fn get_payer(&self) -> &Keypair;
91 fn get_url(&self) -> String;
92
93 async fn health(&self) -> Result<(), RpcError>;
94
95 async fn get_program_accounts(
96 &self,
97 program_id: &Pubkey,
98 ) -> Result<Vec<(Pubkey, Account)>, RpcError>;
99 async fn confirm_transaction(&self, signature: Signature) -> Result<bool, RpcError>;
102
103 async fn get_account(&self, address: Pubkey) -> Result<Option<Account>, RpcError>;
105
106 async fn get_multiple_accounts(
108 &self,
109 addresses: &[Pubkey],
110 ) -> Result<Vec<Option<Account>>, RpcError>;
111
112 async fn get_anchor_account<T: BorshDeserialize>(
115 &self,
116 pubkey: &Pubkey,
117 ) -> Result<Option<T>, RpcError> {
118 match self.get_account(*pubkey).await? {
119 Some(account) => {
120 let data = T::deserialize(&mut &account.data[8..]).map_err(RpcError::from)?;
121 Ok(Some(data))
122 }
123 None => Ok(None),
124 }
125 }
126
127 async fn get_minimum_balance_for_rent_exemption(
128 &self,
129 data_len: usize,
130 ) -> Result<u64, RpcError>;
131
132 async fn airdrop_lamports(&mut self, to: &Pubkey, lamports: u64)
133 -> Result<Signature, RpcError>;
134
135 async fn get_balance(&self, pubkey: &Pubkey) -> Result<u64, RpcError>;
136 async fn get_latest_blockhash(&mut self) -> Result<(Hash, u64), RpcError>;
137 async fn get_slot(&self) -> Result<u64, RpcError>;
138 async fn get_transaction_slot(&self, signature: &Signature) -> Result<u64, RpcError>;
139 async fn get_signature_statuses(
140 &self,
141 signatures: &[Signature],
142 ) -> Result<Vec<Option<TransactionStatus>>, RpcError>;
143
144 async fn send_transaction(&self, transaction: &Transaction) -> Result<Signature, RpcError>;
145
146 async fn send_transaction_with_config(
147 &self,
148 transaction: &Transaction,
149 config: RpcSendTransactionConfig,
150 ) -> Result<Signature, RpcError>;
151
152 async fn process_transaction(
153 &mut self,
154 transaction: Transaction,
155 ) -> Result<Signature, RpcError>;
156
157 async fn process_transaction_with_context(
158 &mut self,
159 transaction: Transaction,
160 ) -> Result<(Signature, Slot), RpcError>;
161
162 async fn create_and_send_transaction_with_event<T>(
163 &mut self,
164 instructions: &[Instruction],
165 authority: &Pubkey,
166 signers: &[&Keypair],
167 ) -> Result<Option<(T, Signature, Slot)>, RpcError>
168 where
169 T: BorshDeserialize + Send + Debug;
170
171 async fn create_and_send_transaction<'a>(
172 &'a mut self,
173 instructions: &'a [Instruction],
174 payer: &'a Pubkey,
175 signers: &'a [&'a Keypair],
176 ) -> Result<Signature, RpcError> {
177 let blockhash = self.get_latest_blockhash().await?.0;
178 let mut transaction = Transaction::new_with_payer(instructions, Some(payer));
179 transaction
180 .try_sign(signers, blockhash)
181 .map_err(|e| RpcError::SigningError(e.to_string()))?;
182 self.process_transaction(transaction).await
183 }
184
185 async fn create_and_send_transaction_with_public_event(
186 &mut self,
187 instruction: &[Instruction],
188 payer: &Pubkey,
189 signers: &[&Keypair],
190 ) -> Result<Option<(PublicTransactionEvent, Signature, Slot)>, RpcError>;
191
192 async fn create_and_send_transaction_with_batched_event(
193 &mut self,
194 instruction: &[Instruction],
195 payer: &Pubkey,
196 signers: &[&Keypair],
197 ) -> Result<Option<(Vec<BatchPublicTransactionEvent>, Signature, Slot)>, RpcError>;
198
199 fn indexer(&self) -> Result<&impl Indexer, RpcError>;
200 fn indexer_mut(&mut self) -> Result<&mut impl Indexer, RpcError>;
201
202 async fn get_latest_active_state_trees(&mut self) -> Result<Vec<TreeInfo>, RpcError>;
204
205 fn get_state_tree_infos(&self) -> Vec<TreeInfo>;
208
209 fn get_random_state_tree_info(&self) -> Result<TreeInfo, RpcError>;
213
214 fn get_random_state_tree_info_v1(&self) -> Result<TreeInfo, RpcError>;
217
218 fn get_address_tree_v1(&self) -> TreeInfo;
219
220 fn get_address_tree_v2(&self) -> TreeInfo;
221}