light_client/rpc/
rpc_trait.rs

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 photon_url: Option<String>,
31    pub api_key: Option<String>,
32    pub fetch_active_tree: bool,
33}
34
35impl LightClientConfig {
36    pub fn new(url: String, photon_url: Option<String>, api_key: Option<String>) -> Self {
37        Self {
38            url,
39            photon_url,
40            api_key,
41            commitment_config: Some(CommitmentConfig::confirmed()),
42            fetch_active_tree: true,
43        }
44    }
45    pub fn local_no_indexer() -> Self {
46        Self {
47            url: RpcUrl::Localnet.to_string(),
48            commitment_config: Some(CommitmentConfig::confirmed()),
49            photon_url: None,
50            api_key: None,
51            fetch_active_tree: false,
52        }
53    }
54
55    pub fn local() -> Self {
56        Self {
57            url: RpcUrl::Localnet.to_string(),
58            commitment_config: Some(CommitmentConfig::confirmed()),
59            photon_url: Some("http://127.0.0.1:8784".to_string()),
60            api_key: None,
61            fetch_active_tree: false,
62        }
63    }
64
65    pub fn devnet(photon_url: Option<String>, api_key: Option<String>) -> Self {
66        Self {
67            url: RpcUrl::Devnet.to_string(),
68            photon_url,
69            api_key,
70            commitment_config: Some(CommitmentConfig::confirmed()),
71            fetch_active_tree: true,
72        }
73    }
74}
75
76#[async_trait]
77pub trait Rpc: Send + Sync + Debug + 'static {
78    async fn new(config: LightClientConfig) -> Result<Self, RpcError>
79    where
80        Self: Sized;
81
82    fn should_retry(&self, error: &RpcError) -> bool {
83        match error {
84            // Do not retry transaction errors.
85            RpcError::ClientError(error) => error.kind.get_transaction_error().is_none(),
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    // TODO: add send transaction with config
100
101    async fn confirm_transaction(&self, signature: Signature) -> Result<bool, RpcError>;
102
103    /// Returns an account struct.
104    async fn get_account(&self, address: Pubkey) -> Result<Option<Account>, RpcError>;
105
106    /// Returns an a borsh deserialized account.
107    /// Deserialization skips the discriminator.
108    async fn get_anchor_account<T: BorshDeserialize>(
109        &self,
110        pubkey: &Pubkey,
111    ) -> Result<Option<T>, RpcError> {
112        match self.get_account(*pubkey).await? {
113            Some(account) => {
114                let data = T::deserialize(&mut &account.data[8..]).map_err(RpcError::from)?;
115                Ok(Some(data))
116            }
117            None => Ok(None),
118        }
119    }
120
121    async fn get_minimum_balance_for_rent_exemption(
122        &self,
123        data_len: usize,
124    ) -> Result<u64, RpcError>;
125
126    async fn airdrop_lamports(&mut self, to: &Pubkey, lamports: u64)
127        -> Result<Signature, RpcError>;
128
129    async fn get_balance(&self, pubkey: &Pubkey) -> Result<u64, RpcError>;
130    async fn get_latest_blockhash(&mut self) -> Result<(Hash, u64), RpcError>;
131    async fn get_slot(&self) -> Result<u64, RpcError>;
132    async fn get_transaction_slot(&self, signature: &Signature) -> Result<u64, RpcError>;
133    async fn get_signature_statuses(
134        &self,
135        signatures: &[Signature],
136    ) -> Result<Vec<Option<TransactionStatus>>, RpcError>;
137
138    async fn send_transaction(&self, transaction: &Transaction) -> Result<Signature, RpcError>;
139
140    async fn send_transaction_with_config(
141        &self,
142        transaction: &Transaction,
143        config: RpcSendTransactionConfig,
144    ) -> Result<Signature, RpcError>;
145
146    async fn process_transaction(
147        &mut self,
148        transaction: Transaction,
149    ) -> Result<Signature, RpcError>;
150
151    async fn process_transaction_with_context(
152        &mut self,
153        transaction: Transaction,
154    ) -> Result<(Signature, Slot), RpcError>;
155
156    async fn create_and_send_transaction_with_event<T>(
157        &mut self,
158        instructions: &[Instruction],
159        authority: &Pubkey,
160        signers: &[&Keypair],
161    ) -> Result<Option<(T, Signature, Slot)>, RpcError>
162    where
163        T: BorshDeserialize + Send + Debug;
164
165    async fn create_and_send_transaction<'a>(
166        &'a mut self,
167        instructions: &'a [Instruction],
168        payer: &'a Pubkey,
169        signers: &'a [&'a Keypair],
170    ) -> Result<Signature, RpcError> {
171        let blockhash = self.get_latest_blockhash().await?.0;
172        let transaction =
173            Transaction::new_signed_with_payer(instructions, Some(payer), signers, blockhash);
174        self.process_transaction(transaction).await
175    }
176
177    async fn create_and_send_transaction_with_public_event(
178        &mut self,
179        instruction: &[Instruction],
180        payer: &Pubkey,
181        signers: &[&Keypair],
182    ) -> Result<Option<(PublicTransactionEvent, Signature, Slot)>, RpcError>;
183
184    async fn create_and_send_transaction_with_batched_event(
185        &mut self,
186        instruction: &[Instruction],
187        payer: &Pubkey,
188        signers: &[&Keypair],
189    ) -> Result<Option<(Vec<BatchPublicTransactionEvent>, Signature, Slot)>, RpcError>;
190
191    fn indexer(&self) -> Result<&impl Indexer, RpcError>;
192    fn indexer_mut(&mut self) -> Result<&mut impl Indexer, RpcError>;
193
194    /// Fetch the latest state tree addresses from the cluster.
195    async fn get_latest_active_state_trees(&mut self) -> Result<Vec<TreeInfo>, RpcError>;
196
197    /// Gets state tree infos.
198    /// State trees are cached and have to be fetched or set.
199    fn get_state_tree_infos(&self) -> Vec<TreeInfo>;
200
201    /// Gets a random state tree info.
202    /// State trees are cached and have to be fetched or set.
203    fn get_random_state_tree_info(&self) -> Result<TreeInfo, RpcError>;
204
205    fn get_address_tree_v1(&self) -> TreeInfo;
206
207    // TODO: add with v2 release
208    // fn get_address_tree_v2(&self) -> Result<Vec<Pubkey>, RpcError>;
209}