diff --git a/external/photon b/external/photon index 0df2397c2c..84ddfc0f58 160000 --- a/external/photon +++ b/external/photon @@ -1 +1 @@ -Subproject commit 0df2397c2c7d8458f45df9279e999a730ba56482 +Subproject commit 84ddfc0f586806373567faf75f45158076a4f133 diff --git a/sdk-libs/client/src/indexer/types/interface.rs b/sdk-libs/client/src/indexer/types/interface.rs index 61d8d109aa..49b658cb4c 100644 --- a/sdk-libs/client/src/indexer/types/interface.rs +++ b/sdk-libs/client/src/indexer/types/interface.rs @@ -113,12 +113,12 @@ pub struct AccountInterface { } impl AccountInterface { - /// Returns true if this account is on-chain (hot) + /// Returns true if this account is on-chain (hot). pub fn is_hot(&self) -> bool { self.cold.is_none() } - /// Returns true if this account is compressed (cold) + /// Returns true if this account is compressed (cold). pub fn is_cold(&self) -> bool { self.cold.is_some() } @@ -128,7 +128,6 @@ impl AccountInterface { fn convert_account_interface( ai: &photon_api::types::AccountInterface, ) -> Result { - // Take the first compressed account entry if present let cold = ai .cold .as_ref() @@ -168,3 +167,101 @@ pub struct TokenAccountInterface { /// Parsed token data (same as CompressedTokenAccount.token) pub token: TokenData, } + +#[cfg(test)] +mod tests { + use super::*; + + fn default_tree_info() -> InterfaceTreeInfo { + InterfaceTreeInfo { + tree: Pubkey::default(), + queue: Pubkey::default(), + tree_type: TreeType::StateV2, + seq: Some(1), + slot_created: 100, + } + } + + fn make_cold_context(discriminator: [u8; 8]) -> ColdContext { + ColdContext { + hash: [1u8; 32], + leaf_index: 0, + tree_info: default_tree_info(), + data: ColdData { + discriminator, + data: vec![1, 2, 3], + data_hash: [2u8; 32], + }, + address: Some([3u8; 32]), + prove_by_index: false, + } + } + + fn make_account(lamports: u64) -> SolanaAccountData { + Account { + lamports, + data: vec![], + owner: Pubkey::default(), + executable: false, + rent_epoch: 0, + } + } + + #[test] + fn test_pure_on_chain_is_hot() { + let ai = AccountInterface { + key: Pubkey::new_unique(), + account: make_account(1_000_000), + cold: None, + }; + assert!(ai.is_hot()); + assert!(!ai.is_cold()); + } + + #[test] + fn test_compressed_is_cold() { + let ai = AccountInterface { + key: Pubkey::new_unique(), + account: make_account(0), + cold: Some(make_cold_context([1, 2, 3, 4, 5, 6, 7, 8])), + }; + assert!(ai.is_cold()); + assert!(!ai.is_hot()); + } + + #[test] + fn test_zero_discriminator_is_cold() { + let ai = AccountInterface { + key: Pubkey::new_unique(), + account: make_account(0), + cold: Some(make_cold_context([0u8; 8])), + }; + assert!(ai.is_cold()); + assert!(!ai.is_hot()); + } + + #[test] + fn test_token_account_interface_delegates_is_cold() { + let token = TokenData::default(); + + let cold_tai = TokenAccountInterface { + account: AccountInterface { + key: Pubkey::new_unique(), + account: make_account(0), + cold: Some(make_cold_context([1, 2, 3, 4, 5, 6, 7, 8])), + }, + token: token.clone(), + }; + assert!(cold_tai.account.is_cold()); + + let hot_tai = TokenAccountInterface { + account: AccountInterface { + key: Pubkey::new_unique(), + account: make_account(1_000_000), + cold: None, + }, + token, + }; + assert!(hot_tai.account.is_hot()); + } +} diff --git a/sdk-libs/client/src/rpc/client.rs b/sdk-libs/client/src/rpc/client.rs index 82d543c002..53f08dad05 100644 --- a/sdk-libs/client/src/rpc/client.rs +++ b/sdk-libs/client/src/rpc/client.rs @@ -540,16 +540,7 @@ fn cold_context_to_compressed_account( fn convert_account_interface( indexer_ai: IndexerAccountInterface, ) -> Result { - let account = Account { - lamports: indexer_ai.account.lamports, - data: indexer_ai.account.data, - owner: indexer_ai.account.owner, - executable: indexer_ai.account.executable, - rent_epoch: indexer_ai.account.rent_epoch, - }; - match indexer_ai.cold { - None => Ok(AccountInterface::hot(indexer_ai.key, account)), Some(cold) => { let compressed = cold_context_to_compressed_account( &cold, @@ -562,6 +553,16 @@ fn convert_account_interface( indexer_ai.account.owner, )) } + None => { + let account = Account { + lamports: indexer_ai.account.lamports, + data: indexer_ai.account.data, + owner: indexer_ai.account.owner, + executable: indexer_ai.account.executable, + rent_epoch: indexer_ai.account.rent_epoch, + }; + Ok(AccountInterface::hot(indexer_ai.key, account)) + } } } @@ -570,17 +571,7 @@ fn convert_token_account_interface( ) -> Result { use crate::indexer::CompressedTokenAccount; - let account = Account { - lamports: indexer_tai.account.account.lamports, - data: indexer_tai.account.account.data.clone(), - owner: indexer_tai.account.account.owner, - executable: indexer_tai.account.account.executable, - rent_epoch: indexer_tai.account.account.rent_epoch, - }; - match indexer_tai.account.cold { - None => TokenAccountInterface::hot(indexer_tai.account.key, account) - .map_err(|e| RpcError::CustomError(format!("parse error: {}", e))), Some(cold) => { let compressed_account = cold_context_to_compressed_account( &cold, @@ -600,6 +591,17 @@ fn convert_token_account_interface( indexer_tai.account.account.owner, )) } + None => { + let account = Account { + lamports: indexer_tai.account.account.lamports, + data: indexer_tai.account.account.data, + owner: indexer_tai.account.account.owner, + executable: indexer_tai.account.account.executable, + rent_epoch: indexer_tai.account.account.rent_epoch, + }; + TokenAccountInterface::hot(indexer_tai.account.key, account) + .map_err(|e| RpcError::CustomError(format!("parse error: {}", e))) + } } }