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 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 async fn confirm_transaction(&self, signature: Signature) -> Result<bool, RpcError>;
97
98 async fn get_account(&self, address: Pubkey) -> Result<Option<Account>, RpcError>;
100
101 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 async fn get_latest_active_state_trees(&mut self) -> Result<Vec<TreeInfo>, RpcError>;
191
192 fn get_state_tree_infos(&self) -> Vec<TreeInfo>;
195
196 fn get_random_state_tree_info(&self) -> Result<TreeInfo, RpcError>;
199
200 fn get_address_tree_v1(&self) -> TreeInfo;
201
202 }