surfpool_core/surfnet/
remote.rs

1use solana_client::{
2    nonblocking::rpc_client::RpcClient, rpc_request::TokenAccountsFilter,
3    rpc_response::RpcKeyedAccount,
4};
5use solana_commitment_config::CommitmentConfig;
6use solana_epoch_info::EpochInfo;
7use solana_pubkey::Pubkey;
8use solana_sdk::bpf_loader_upgradeable::get_program_data_address;
9use solana_signature::Signature;
10use solana_transaction_status::UiTransactionEncoding;
11
12use super::GetTransactionResult;
13use crate::{
14    error::{SurfpoolError, SurfpoolResult},
15    surfnet::GetAccountResult,
16};
17
18pub struct SurfnetRemoteClient {
19    pub client: RpcClient,
20}
21impl Clone for SurfnetRemoteClient {
22    fn clone(&self) -> Self {
23        let remote_rpc_url = self.client.url();
24        SurfnetRemoteClient {
25            client: RpcClient::new(remote_rpc_url),
26        }
27    }
28}
29
30pub trait SomeRemoteCtx {
31    fn get_remote_ctx<T>(&self, input: T) -> Option<(SurfnetRemoteClient, T)>;
32}
33
34impl SomeRemoteCtx for Option<SurfnetRemoteClient> {
35    fn get_remote_ctx<T>(&self, input: T) -> Option<(SurfnetRemoteClient, T)> {
36        self.as_ref()
37            .map(|remote_rpc_client| (remote_rpc_client.clone(), input))
38    }
39}
40
41impl SurfnetRemoteClient {
42    pub fn new(remote_rpc_url: &str) -> Self {
43        SurfnetRemoteClient {
44            client: RpcClient::new(remote_rpc_url.to_string()),
45        }
46    }
47
48    pub async fn get_epoch_info(&self) -> SurfpoolResult<EpochInfo> {
49        self.client.get_epoch_info().await.map_err(Into::into)
50    }
51
52    pub async fn get_account(
53        &self,
54        pubkey: &Pubkey,
55        commitment_config: CommitmentConfig,
56    ) -> SurfpoolResult<GetAccountResult> {
57        let res = self
58            .client
59            .get_account_with_commitment(pubkey, commitment_config)
60            .await
61            .map_err(|e| SurfpoolError::get_account(*pubkey, e))?;
62
63        let result = match res.value {
64            Some(account) => {
65                if !account.executable {
66                    GetAccountResult::FoundAccount(
67                        *pubkey, account,
68                        // Mark this account as needing to be updated in the SVM, since we fetched it
69                        true,
70                    )
71                } else {
72                    let program_data_address = get_program_data_address(pubkey);
73
74                    let program_data = self
75                        .client
76                        .get_account_with_commitment(&program_data_address, commitment_config)
77                        .await
78                        .map_err(|e| SurfpoolError::get_account(*pubkey, e))?;
79
80                    GetAccountResult::FoundProgramAccount(
81                        (*pubkey, account),
82                        (program_data_address, program_data.value),
83                    )
84                }
85            }
86            None => GetAccountResult::None(*pubkey),
87        };
88        Ok(result)
89    }
90
91    pub async fn get_multiple_accounts(
92        &self,
93        pubkeys: &[Pubkey],
94        commitment_config: CommitmentConfig,
95    ) -> SurfpoolResult<Vec<GetAccountResult>> {
96        let remote_accounts = self
97            .client
98            .get_multiple_accounts(pubkeys)
99            .await
100            .map_err(SurfpoolError::get_multiple_accounts)?;
101
102        let mut accounts_result = vec![];
103        for (pubkey, remote_account) in pubkeys.iter().zip(remote_accounts) {
104            if let Some(remote_account) = remote_account {
105                if !remote_account.executable {
106                    accounts_result.push(GetAccountResult::FoundAccount(
107                        *pubkey,
108                        remote_account,
109                        // Mark this account as needing to be updated in the SVM, since we fetched it
110                        true,
111                    ));
112                } else {
113                    let program_data_address = get_program_data_address(pubkey);
114
115                    let program_data = self
116                        .client
117                        .get_account_with_commitment(&program_data_address, commitment_config)
118                        .await
119                        .map_err(|e| SurfpoolError::get_account(*pubkey, e))?;
120
121                    accounts_result.push(GetAccountResult::FoundProgramAccount(
122                        (*pubkey, remote_account),
123                        (program_data_address, program_data.value),
124                    ));
125                }
126            }
127        }
128        Ok(accounts_result)
129    }
130
131    pub async fn get_transaction(
132        &self,
133        signature: Signature,
134        encoding: Option<UiTransactionEncoding>,
135        latest_absolute_slot: u64,
136    ) -> GetTransactionResult {
137        match self
138            .client
139            .get_transaction(
140                &signature,
141                encoding.unwrap_or(UiTransactionEncoding::Base64),
142            )
143            .await
144        {
145            Ok(tx) => GetTransactionResult::found_transaction(signature, tx, latest_absolute_slot),
146            Err(_) => GetTransactionResult::None(signature),
147        }
148    }
149
150    pub async fn get_token_accounts_by_owner(
151        &self,
152
153        owner: Pubkey,
154        token_program: Pubkey,
155    ) -> SurfpoolResult<Vec<RpcKeyedAccount>> {
156        self.client
157            .get_token_accounts_by_owner(&owner, TokenAccountsFilter::ProgramId(token_program))
158            .await
159            .map_err(|e| SurfpoolError::get_token_accounts(owner, token_program, e))
160    }
161}