surfpool_core/surfnet/
remote.rs1use solana_account_decoder::{encode_ui_account, UiAccountEncoding};
2use solana_client::{
3 nonblocking::rpc_client::RpcClient,
4 rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
5 rpc_filter::RpcFilterType,
6 rpc_request::TokenAccountsFilter,
7 rpc_response::RpcKeyedAccount,
8};
9use solana_commitment_config::CommitmentConfig;
10use solana_epoch_info::EpochInfo;
11use solana_pubkey::Pubkey;
12use solana_sdk::bpf_loader_upgradeable::get_program_data_address;
13use solana_signature::Signature;
14use solana_transaction_status::UiTransactionEncoding;
15
16use super::GetTransactionResult;
17use crate::{
18 error::{SurfpoolError, SurfpoolResult},
19 surfnet::GetAccountResult,
20};
21
22pub struct SurfnetRemoteClient {
23 pub client: RpcClient,
24}
25impl Clone for SurfnetRemoteClient {
26 fn clone(&self) -> Self {
27 let remote_rpc_url = self.client.url();
28 SurfnetRemoteClient {
29 client: RpcClient::new(remote_rpc_url),
30 }
31 }
32}
33
34pub trait SomeRemoteCtx {
35 fn get_remote_ctx<T>(&self, input: T) -> Option<(SurfnetRemoteClient, T)>;
36}
37
38impl SomeRemoteCtx for Option<SurfnetRemoteClient> {
39 fn get_remote_ctx<T>(&self, input: T) -> Option<(SurfnetRemoteClient, T)> {
40 self.as_ref()
41 .map(|remote_rpc_client| (remote_rpc_client.clone(), input))
42 }
43}
44
45impl SurfnetRemoteClient {
46 pub fn new(remote_rpc_url: &str) -> Self {
47 SurfnetRemoteClient {
48 client: RpcClient::new(remote_rpc_url.to_string()),
49 }
50 }
51
52 pub async fn get_epoch_info(&self) -> SurfpoolResult<EpochInfo> {
53 self.client.get_epoch_info().await.map_err(Into::into)
54 }
55
56 pub async fn get_account(
57 &self,
58 pubkey: &Pubkey,
59 commitment_config: CommitmentConfig,
60 ) -> SurfpoolResult<GetAccountResult> {
61 let res = self
62 .client
63 .get_account_with_commitment(pubkey, commitment_config)
64 .await
65 .map_err(|e| SurfpoolError::get_account(*pubkey, e))?;
66
67 let result = match res.value {
68 Some(account) => {
69 if !account.executable {
70 GetAccountResult::FoundAccount(
71 *pubkey, account,
72 true,
74 )
75 } else {
76 let program_data_address = get_program_data_address(pubkey);
77
78 let program_data = self
79 .client
80 .get_account_with_commitment(&program_data_address, commitment_config)
81 .await
82 .map_err(|e| SurfpoolError::get_account(*pubkey, e))?;
83
84 GetAccountResult::FoundProgramAccount(
85 (*pubkey, account),
86 (program_data_address, program_data.value),
87 )
88 }
89 }
90 None => GetAccountResult::None(*pubkey),
91 };
92 Ok(result)
93 }
94
95 pub async fn get_multiple_accounts(
96 &self,
97 pubkeys: &[Pubkey],
98 commitment_config: CommitmentConfig,
99 ) -> SurfpoolResult<Vec<GetAccountResult>> {
100 let remote_accounts = self
101 .client
102 .get_multiple_accounts(pubkeys)
103 .await
104 .map_err(SurfpoolError::get_multiple_accounts)?;
105
106 let mut accounts_result = vec![];
107 for (pubkey, remote_account) in pubkeys.iter().zip(remote_accounts) {
108 if let Some(remote_account) = remote_account {
109 if !remote_account.executable {
110 accounts_result.push(GetAccountResult::FoundAccount(
111 *pubkey,
112 remote_account,
113 true,
115 ));
116 } else {
117 let program_data_address = get_program_data_address(pubkey);
118
119 let program_data = self
120 .client
121 .get_account_with_commitment(&program_data_address, commitment_config)
122 .await
123 .map_err(|e| SurfpoolError::get_account(*pubkey, e))?;
124
125 accounts_result.push(GetAccountResult::FoundProgramAccount(
126 (*pubkey, remote_account),
127 (program_data_address, program_data.value),
128 ));
129 }
130 }
131 }
132 Ok(accounts_result)
133 }
134
135 pub async fn get_transaction(
136 &self,
137 signature: Signature,
138 encoding: Option<UiTransactionEncoding>,
139 latest_absolute_slot: u64,
140 ) -> GetTransactionResult {
141 match self
142 .client
143 .get_transaction(
144 &signature,
145 encoding.unwrap_or(UiTransactionEncoding::Base64),
146 )
147 .await
148 {
149 Ok(tx) => GetTransactionResult::found_transaction(signature, tx, latest_absolute_slot),
150 Err(_) => GetTransactionResult::None(signature),
151 }
152 }
153
154 pub async fn get_token_accounts_by_owner(
155 &self,
156 owner: Pubkey,
157 token_program: Pubkey,
158 ) -> SurfpoolResult<Vec<RpcKeyedAccount>> {
159 self.client
160 .get_token_accounts_by_owner(&owner, TokenAccountsFilter::ProgramId(token_program))
161 .await
162 .map_err(|e| SurfpoolError::get_token_accounts(owner, token_program, e))
163 }
164
165 pub async fn get_program_accounts(
166 &self,
167 program_id: &Pubkey,
168 account_config: RpcAccountInfoConfig,
169 filters: Option<Vec<RpcFilterType>>,
170 ) -> SurfpoolResult<Vec<RpcKeyedAccount>> {
171 let encoding = account_config.encoding.unwrap_or(UiAccountEncoding::Base64);
172 let data_slice = account_config.data_slice;
173 self.client
174 .get_program_accounts_with_config(
175 program_id,
176 RpcProgramAccountsConfig {
177 filters,
178 with_context: Some(false),
179 account_config,
180 ..Default::default()
181 },
182 )
183 .await
184 .map(|accounts| {
185 accounts
186 .iter()
187 .map(|(pubkey, account)| RpcKeyedAccount {
188 pubkey: pubkey.to_string(),
189 account: encode_ui_account(pubkey, account, encoding, None, data_slice),
190 })
191 .collect()
192 })
193 .map_err(|e| SurfpoolError::get_program_accounts(*program_id, e))
194 }
195}