light_client/indexer/types/
interface.rs1use light_sdk_types::lca::TreeType;
2use solana_account::Account;
3use solana_pubkey::Pubkey;
4
5use super::super::{base58::decode_base58_to_fixed_array, IndexerError};
6
7pub type SolanaAccountData = Account;
9
10#[derive(Clone, Copy, Debug, PartialEq)]
12pub struct InterfaceTreeInfo {
13 pub tree: Pubkey,
14 pub queue: Pubkey,
15 pub tree_type: TreeType,
16 pub seq: Option<u64>,
17 pub slot_created: u64,
19}
20
21#[derive(Clone, Debug, PartialEq)]
23pub struct ColdData {
24 pub discriminator: [u8; 8],
25 pub data: Vec<u8>,
26 pub data_hash: [u8; 32],
27}
28
29#[derive(Clone, Debug, PartialEq)]
31pub struct ColdContext {
32 pub hash: [u8; 32],
33 pub leaf_index: u64,
34 pub tree_info: InterfaceTreeInfo,
35 pub data: ColdData,
36 pub address: Option<[u8; 32]>,
37 pub prove_by_index: bool,
38}
39
40fn decode_tree_info_v2(
42 merkle_ctx: &photon_api::types::MerkleContextV2,
43 seq: Option<u64>,
44 slot_created: u64,
45) -> Result<InterfaceTreeInfo, IndexerError> {
46 let tree = Pubkey::new_from_array(decode_base58_to_fixed_array(&merkle_ctx.tree)?);
47 let queue = Pubkey::new_from_array(decode_base58_to_fixed_array(&merkle_ctx.queue)?);
48 let tree_type = TreeType::from(merkle_ctx.tree_type as u64);
49 Ok(InterfaceTreeInfo {
50 tree,
51 queue,
52 tree_type,
53 seq,
54 slot_created,
55 })
56}
57
58fn decode_account_data(data: &photon_api::types::AccountData) -> Result<ColdData, IndexerError> {
60 let disc_val = *data.discriminator;
61 let discriminator = disc_val.to_le_bytes();
62 Ok(ColdData {
63 discriminator,
64 data: base64::decode_config(&*data.data, base64::STANDARD_NO_PAD)
65 .map_err(|e| IndexerError::decode_error("data", e))?,
66 data_hash: decode_base58_to_fixed_array(&data.data_hash)?,
67 })
68}
69
70fn convert_account_v2(av2: &photon_api::types::AccountV2) -> Result<ColdContext, IndexerError> {
72 let tree_info = decode_tree_info_v2(
73 &av2.merkle_context,
74 av2.seq.as_ref().map(|s| **s),
75 *av2.slot_created,
76 )?;
77
78 let data = match &av2.data {
79 Some(d) => decode_account_data(d)?,
80 None => ColdData {
81 discriminator: [0u8; 8],
82 data: Vec::new(),
83 data_hash: [0u8; 32],
84 },
85 };
86
87 let address = av2
88 .address
89 .as_ref()
90 .map(|a| decode_base58_to_fixed_array(a))
91 .transpose()?;
92
93 Ok(ColdContext {
94 hash: decode_base58_to_fixed_array(&av2.hash)?,
95 leaf_index: *av2.leaf_index,
96 tree_info,
97 data,
98 address,
99 prove_by_index: av2.prove_by_index,
100 })
101}
102
103#[derive(Clone, Debug, PartialEq)]
105pub struct AccountInterface {
106 pub key: Pubkey,
108 pub account: SolanaAccountData,
110 pub cold: Option<ColdContext>,
112}
113
114impl AccountInterface {
115 pub fn is_hot(&self) -> bool {
117 self.cold.is_none()
118 }
119
120 pub fn is_cold(&self) -> bool {
122 self.cold.is_some()
123 }
124}
125
126fn convert_account_interface(
128 ai: &photon_api::types::AccountInterface,
129) -> Result<AccountInterface, IndexerError> {
130 let cold = ai
132 .cold
133 .as_ref()
134 .and_then(|entries| entries.first())
135 .map(convert_account_v2)
136 .transpose()?;
137
138 let data = base64::decode_config(&*ai.account.data, base64::STANDARD_NO_PAD)
139 .map_err(|e| IndexerError::decode_error("account.data", e))?;
140
141 Ok(AccountInterface {
142 key: Pubkey::new_from_array(decode_base58_to_fixed_array(&ai.key)?),
143 account: Account {
144 lamports: *ai.account.lamports,
145 data,
146 owner: Pubkey::new_from_array(decode_base58_to_fixed_array(&ai.account.owner)?),
147 executable: ai.account.executable,
148 rent_epoch: *ai.account.rent_epoch,
149 },
150 cold,
151 })
152}
153
154impl TryFrom<&photon_api::types::AccountInterface> for AccountInterface {
155 type Error = IndexerError;
156
157 fn try_from(ai: &photon_api::types::AccountInterface) -> Result<Self, Self::Error> {
158 convert_account_interface(ai)
159 }
160}