Skip to content

Commit 7d536af

Browse files
authored
fix: indexer get_compressed_account return type (#1765)
* fix: rpc return types * fix: discriminator serialization is le bytes in photon * fix: pr feedback
1 parent 2391dc8 commit 7d536af

File tree

14 files changed

+574
-83
lines changed

14 files changed

+574
-83
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ futures = "0.3.17"
119119
tokio = { version = "1.43.0", features = ["rt", "macros", "rt-multi-thread"] }
120120
async-trait = "0.1.82"
121121
bb8 = "0.8.6"
122+
lazy_static = "1.5.0"
122123

123124
# Logging
124125
log = "0.4"

sdk-libs/client/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ bs58 = { workspace = true }
5252
tokio = { workspace = true, features = ["rt", "time"] }
5353

5454
tracing = { workspace = true }
55+
lazy_static = { workspace = true }
5556

5657
[dev-dependencies]
5758
light-program-test = { workspace = true }

sdk-libs/client/src/indexer/base58.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,7 @@ impl Base58Conversions for [u8; 32] {
1919
}
2020

2121
fn from_base58(s: &str) -> Result<Self, IndexerError> {
22-
// TODO: remove vec conversion.
23-
let result = bs58::decode(s)
24-
.into_vec()
25-
.map_err(|e| IndexerError::base58_decode_error(s, e))?
26-
.try_into()
27-
.map_err(|_| IndexerError::ApiError("Try into failed.".to_string()))?;
28-
29-
Ok(result)
22+
decode_base58_to_fixed_array(s)
3023
}
3124

3225
fn to_bytes(&self) -> [u8; 32] {
@@ -39,3 +32,16 @@ impl Base58Conversions for [u8; 32] {
3932
Ok(arr)
4033
}
4134
}
35+
36+
pub fn decode_base58_to_fixed_array<const N: usize>(input: &str) -> Result<[u8; N], IndexerError> {
37+
let mut buffer = [0u8; N];
38+
let decoded_len = bs58::decode(input)
39+
.onto(&mut buffer)
40+
.map_err(|_| IndexerError::InvalidResponseData)?;
41+
42+
if decoded_len != N {
43+
return Err(IndexerError::InvalidResponseData);
44+
}
45+
46+
Ok(buffer)
47+
}

sdk-libs/client/src/indexer/mod.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,31 @@ use std::{fmt::Debug, str::FromStr};
22

33
use async_trait::async_trait;
44
use light_compressed_account::compressed_account::{
5-
CompressedAccount, CompressedAccountData, CompressedAccountWithMerkleContext, MerkleContext,
5+
CompressedAccount, CompressedAccountData, CompressedAccountWithMerkleContext,
66
};
77
use light_indexed_merkle_tree::array::IndexedElement;
88
use light_merkle_tree_metadata::QueueType;
99
use light_sdk::token::{AccountState, TokenData, TokenDataWithMerkleContext};
1010
use num_bigint::BigUint;
11-
use photon_api::models::{Account, TokenAccount, TokenAccountList, TokenBalanceList};
11+
use photon_api::models::{
12+
Account as PhotonAccount, TokenAccount, TokenAccountList, TokenBalanceList,
13+
};
1214
use solana_pubkey::Pubkey;
1315

1416
pub mod photon_indexer;
1517

1618
mod base58;
1719
mod error;
20+
pub(crate) mod tree_info;
1821
mod types;
1922

2023
pub use base58::Base58Conversions;
2124
pub use error::IndexerError;
2225
//
2326
pub use types::ProofRpcResultV2;
2427
pub use types::{
25-
Address, AddressWithTree, Hash, MerkleProof, MerkleProofWithContext, ProofOfLeaf,
26-
ProofRpcResult,
28+
Account, Address, AddressWithTree, Hash, MerkleContext, MerkleProof, MerkleProofWithContext,
29+
ProofOfLeaf, ProofRpcResult, TreeContextInfo,
2730
};
2831

2932
#[derive(Debug, Clone)]
@@ -49,6 +52,11 @@ pub trait Indexer: std::marker::Send + std::marker::Sync {
4952
hashes: Vec<String>,
5053
) -> Result<Vec<MerkleProof>, IndexerError>;
5154

55+
async fn get_compressed_accounts_by_owner(
56+
&self,
57+
owner: &Pubkey,
58+
) -> Result<Vec<CompressedAccountWithMerkleContext>, IndexerError>;
59+
5260
async fn get_compressed_accounts_by_owner_v2(
5361
&self,
5462
owner: &Pubkey,
@@ -179,15 +187,15 @@ pub struct AddressMerkleTreeAccounts {
179187
}
180188

181189
pub trait IntoPhotonAccount {
182-
fn into_photon_account(self) -> Account;
190+
fn into_photon_account(self) -> PhotonAccount;
183191
}
184192

185193
pub trait IntoPhotonTokenAccount {
186194
fn into_photon_token_account(self) -> TokenAccount;
187195
}
188196

189197
impl IntoPhotonAccount for CompressedAccountWithMerkleContext {
190-
fn into_photon_account(self) -> Account {
198+
fn into_photon_account(self) -> PhotonAccount {
191199
let address = self.compressed_account.address.map(|a| a.to_base58());
192200
let hash = self.hash().unwrap().to_base58();
193201

@@ -202,7 +210,7 @@ impl IntoPhotonAccount for CompressedAccountWithMerkleContext {
202210
}));
203211
}
204212

205-
Account {
213+
PhotonAccount {
206214
address,
207215
hash: hash.to_string(),
208216
lamports: self.compressed_account.lamports,
@@ -246,14 +254,14 @@ impl IntoPhotonTokenAccount for TokenDataWithMerkleContext {
246254
}
247255
}
248256

249-
pub struct LocalPhotonAccount(Account);
257+
pub struct LocalPhotonAccount(PhotonAccount);
250258

251259
impl TryFrom<LocalPhotonAccount> for CompressedAccountWithMerkleContext {
252260
type Error = Box<dyn std::error::Error>;
253261

254262
fn try_from(local_account: LocalPhotonAccount) -> Result<Self, Self::Error> {
255263
let account = local_account.0;
256-
let merkle_context = MerkleContext {
264+
let merkle_context = light_compressed_account::compressed_account::MerkleContext {
257265
merkle_tree_pubkey: Pubkey::from_str(&account.tree)?,
258266
queue_pubkey: Default::default(),
259267
leaf_index: account.leaf_index,

sdk-libs/client/src/indexer/photon_indexer.rs

Lines changed: 104 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
1-
use std::{fmt::Debug, str::FromStr, time::Duration};
1+
use std::{fmt::Debug, time::Duration};
22

33
use async_trait::async_trait;
44
use bs58;
55
use light_compressed_account::compressed_account::{
66
CompressedAccount, CompressedAccountData, CompressedAccountWithMerkleContext, MerkleContext,
77
};
88
use light_merkle_tree_metadata::QueueType;
9-
use light_sdk::token::{AccountState, TokenData, TokenDataWithMerkleContext};
9+
use light_sdk::token::TokenDataWithMerkleContext;
1010
use photon_api::{
1111
apis::configuration::{ApiKey, Configuration},
12-
models::{
13-
Account, GetCompressedAccountsByOwnerPostRequestParams,
14-
GetCompressedTokenAccountsByOwnerPostRequestParams,
15-
GetCompressedTokenAccountsByOwnerV2PostRequest, TokenBalanceList,
16-
},
12+
models::{GetCompressedAccountsByOwnerPostRequestParams, TokenBalanceList},
1713
};
1814
use solana_pubkey::Pubkey;
1915
use tracing::{debug, error, warn};
2016

2117
use super::{
22-
AddressQueueIndex, BatchAddressUpdateIndexerResponse, MerkleProofWithContext, ProofRpcResult,
18+
types::Account, BatchAddressUpdateIndexerResponse, MerkleProofWithContext, ProofRpcResult,
2319
};
2420
use crate::indexer::{
25-
Address, AddressWithTree, Base58Conversions, FromPhotonTokenAccountList, Hash, Indexer,
26-
IndexerError, MerkleProof, NewAddressProofWithContext,
21+
tree_info::QUEUE_TREE_MAPPING, Address, AddressWithTree, Base58Conversions,
22+
FromPhotonTokenAccountList, Hash, Indexer, IndexerError, MerkleProof,
23+
NewAddressProofWithContext,
2724
};
2825

2926
pub struct PhotonIndexer {
@@ -239,6 +236,65 @@ impl Indexer for PhotonIndexer {
239236
.await
240237
}
241238

239+
async fn get_compressed_accounts_by_owner(
240+
&self,
241+
owner: &Pubkey,
242+
) -> Result<Vec<CompressedAccountWithMerkleContext>, IndexerError> {
243+
self.retry(|| async {
244+
let request = photon_api::models::GetCompressedAccountsByOwnerPostRequest {
245+
params: Box::from(GetCompressedAccountsByOwnerPostRequestParams {
246+
cursor: None,
247+
data_slice: None,
248+
filters: None,
249+
limit: None,
250+
owner: owner.to_string(),
251+
}),
252+
..Default::default()
253+
};
254+
let result = photon_api::apis::default_api::get_compressed_accounts_by_owner_post(
255+
&self.configuration,
256+
request,
257+
)
258+
.await?;
259+
let accs = result.result.ok_or(IndexerError::AccountNotFound)?.value;
260+
let mut accounts: Vec<CompressedAccountWithMerkleContext> = Vec::new();
261+
262+
for acc in accs.items {
263+
let compressed_account = CompressedAccount {
264+
owner: Pubkey::from(Hash::from_base58(&acc.owner)?),
265+
lamports: acc.lamports,
266+
address: acc
267+
.address
268+
.map(|address| Hash::from_base58(&address).unwrap()),
269+
data: acc.data.map(|data| CompressedAccountData {
270+
discriminator: data.discriminator.to_le_bytes(),
271+
data: base64::decode(data.data).unwrap(),
272+
data_hash: Hash::from_base58(&data.data_hash).unwrap(),
273+
}),
274+
};
275+
let tree_info = QUEUE_TREE_MAPPING
276+
.get(&acc.tree)
277+
.ok_or(IndexerError::InvalidResponseData)?;
278+
let merkle_context = MerkleContext {
279+
merkle_tree_pubkey: tree_info.tree,
280+
queue_pubkey: tree_info.queue,
281+
leaf_index: acc.leaf_index,
282+
tree_type: tree_info.tree_type,
283+
prove_by_index: false,
284+
};
285+
286+
let account = CompressedAccountWithMerkleContext {
287+
compressed_account,
288+
merkle_context,
289+
};
290+
accounts.push(account);
291+
}
292+
293+
Ok(accounts)
294+
})
295+
.await
296+
}
297+
242298
async fn get_compressed_accounts_by_owner_v2(
243299
&self,
244300
_owner: &Pubkey,
@@ -265,8 +321,7 @@ impl Indexer for PhotonIndexer {
265321
request,
266322
)
267323
.await?;
268-
269-
let accs = result.result.unwrap().value;
324+
let accs = result.result.ok_or(IndexerError::AccountNotFound)?.value;
270325
let mut accounts: Vec<CompressedAccountWithMerkleContext> = Vec::new();
271326

272327
for acc in accs.items {
@@ -277,8 +332,8 @@ impl Indexer for PhotonIndexer {
277332
.address
278333
.map(|address| Hash::from_base58(&address).unwrap()),
279334
data: acc.data.map(|data| CompressedAccountData {
280-
discriminator: data.discriminator.to_be_bytes(),
281-
data: data.data.as_bytes().to_vec(),
335+
discriminator: data.discriminator.to_le_bytes(),
336+
data: base64::decode(data.data).unwrap(),
282337
data_hash: Hash::from_base58(&data.data_hash).unwrap(),
283338
}),
284339
};
@@ -320,16 +375,19 @@ impl Indexer for PhotonIndexer {
320375
unimplemented!("get_compressed_token_accounts_by_owner_v2");
321376
#[cfg(feature = "v2")]
322377
{
378+
use std::str::FromStr;
323379
let owner = _owner;
324380
let mint = _mint;
325381
self.retry(|| async {
326-
let request = GetCompressedTokenAccountsByOwnerV2PostRequest {
327-
params: Box::from(GetCompressedTokenAccountsByOwnerPostRequestParams {
328-
cursor: None,
329-
limit: None,
330-
mint: mint.map(|x| x.to_string()),
331-
owner: owner.to_string(),
332-
}),
382+
let request = photon_api::models::GetCompressedTokenAccountsByOwnerV2PostRequest {
383+
params: Box::from(
384+
photon_api::models::GetCompressedTokenAccountsByOwnerPostRequestParams {
385+
cursor: None,
386+
limit: None,
387+
mint: mint.map(|x| x.to_string()),
388+
owner: owner.to_string(),
389+
},
390+
),
333391
..Default::default()
334392
};
335393
let result =
@@ -344,7 +402,7 @@ impl Indexer for PhotonIndexer {
344402
let mut token_data: Vec<TokenDataWithMerkleContext> = Vec::new();
345403
for account in accounts.items.iter() {
346404
let token_data_with_merkle_context = TokenDataWithMerkleContext {
347-
token_data: TokenData {
405+
token_data: light_sdk::token::TokenData {
348406
mint: Pubkey::from_str(&account.token_data.mint).unwrap(),
349407
owner: Pubkey::from_str(&account.token_data.owner).unwrap(),
350408
amount: account.token_data.amount,
@@ -356,9 +414,9 @@ impl Indexer for PhotonIndexer {
356414
state: if account.token_data.state
357415
== photon_api::models::account_state::AccountState::Initialized
358416
{
359-
AccountState::Initialized
417+
light_sdk::token::AccountState::Initialized
360418
} else {
361-
AccountState::Frozen
419+
light_sdk::token::AccountState::Frozen
362420
},
363421
tlv: None,
364422
},
@@ -423,10 +481,11 @@ impl Indexer for PhotonIndexer {
423481
)
424482
.await?;
425483
let response = Self::extract_result("get_compressed_account", result.result)?;
426-
response
484+
let response = response
427485
.value
428486
.ok_or(IndexerError::AccountNotFound)
429-
.map(|boxed| *boxed)
487+
.map(|boxed| *boxed)?;
488+
Account::try_from(&response)
430489
})
431490
.await
432491
}
@@ -539,7 +598,12 @@ impl Indexer for PhotonIndexer {
539598
.await?;
540599

541600
let response = Self::extract_result("get_multiple_compressed_accounts", result.result)?;
542-
Ok(response.value.items)
601+
response
602+
.value
603+
.items
604+
.iter()
605+
.map(Account::try_from)
606+
.collect::<Result<Vec<Account>, IndexerError>>()
543607
})
544608
.await
545609
}
@@ -753,13 +817,15 @@ impl Indexer for PhotonIndexer {
753817

754818
async fn get_validity_proof_v2(
755819
&self,
756-
hashes: Vec<Hash>,
757-
new_addresses_with_trees: Vec<AddressWithTree>,
820+
_hashes: Vec<Hash>,
821+
_new_addresses_with_trees: Vec<AddressWithTree>,
758822
) -> Result<super::types::ProofRpcResultV2, IndexerError> {
759823
#[cfg(not(feature = "v2"))]
760824
unimplemented!("get_validity_proof_v2");
761825
#[cfg(feature = "v2")]
762826
{
827+
let hashes = _hashes;
828+
let new_addresses_with_trees = _new_addresses_with_trees;
763829
self.retry(|| async {
764830
let request = photon_api::models::GetValidityProofV2PostRequest {
765831
params: Box::new(photon_api::models::GetValidityProofPostRequestParams {
@@ -823,7 +889,7 @@ impl Indexer for PhotonIndexer {
823889
let addresses = response
824890
.addresses
825891
.iter()
826-
.map(|x| AddressQueueIndex {
892+
.map(|x| crate::indexer::AddressQueueIndex {
827893
address: Hash::from_base58(x.address.clone().as_ref()).unwrap(),
828894
queue_index: x.queue_index,
829895
})
@@ -884,15 +950,19 @@ impl Indexer for PhotonIndexer {
884950

885951
async fn get_queue_elements(
886952
&mut self,
887-
pubkey: [u8; 32],
888-
queue_type: QueueType,
889-
num_elements: u16,
890-
start_offset: Option<u64>,
953+
_pubkey: [u8; 32],
954+
_queue_type: QueueType,
955+
_num_elements: u16,
956+
_start_offset: Option<u64>,
891957
) -> Result<Vec<MerkleProofWithContext>, IndexerError> {
892958
#[cfg(not(feature = "v2"))]
893959
unimplemented!("get_queue_elements");
894960
#[cfg(feature = "v2")]
895961
{
962+
let pubkey = _pubkey;
963+
let queue_type = _queue_type;
964+
let num_elements = _num_elements;
965+
let start_offset = _start_offset;
896966
self.retry(|| async {
897967
let request: photon_api::models::GetQueueElementsPostRequest =
898968
photon_api::models::GetQueueElementsPostRequest {

0 commit comments

Comments
 (0)