1use std::marker::PhantomData;
123
124use light_compressed_account::{
125 compressed_account::PackedMerkleContext,
126 instruction_data::with_account_info::{CompressedAccountInfo, InAccountInfo, OutAccountInfo},
127};
128use light_sdk_types::instruction::account_meta::CompressedAccountMetaTrait;
129use solana_pubkey::Pubkey;
130
131#[cfg(feature = "poseidon")]
132use crate::light_hasher::Poseidon;
133use crate::{
134 error::LightSdkError,
135 light_hasher::{DataHasher, Hasher, Sha256},
136 AnchorDeserialize, AnchorSerialize, LightDiscriminator,
137};
138
139const DEFAULT_DATA_HASH: [u8; 32] = [0u8; 32];
140
141pub trait Size {
142 fn size(&self) -> usize;
143}
144pub use sha::LightAccount;
145pub mod sha {
148 use super::*;
149 pub type LightAccount<A> = super::LightAccountInner<Sha256, A, true>;
152}
153
154#[cfg(feature = "poseidon")]
157pub mod poseidon {
158 use super::*;
159 pub type LightAccount<A> = super::LightAccountInner<Poseidon, A, false>;
179}
180
181#[doc(hidden)]
182pub use __internal::LightAccountInner;
183
184#[doc(hidden)]
189pub mod __internal {
190 use light_compressed_account::instruction_data::{
191 data::OutputCompressedAccountWithPackedContext, with_readonly::InAccount,
192 };
193 use light_sdk_types::instruction::account_meta::CompressedAccountMetaBurn;
194 #[cfg(feature = "v2")]
195 use light_sdk_types::instruction::account_meta::CompressedAccountMetaReadOnly;
196 use solana_program_error::ProgramError;
197
198 use super::*;
199
200 #[doc(hidden)]
201 #[derive(Debug, PartialEq)]
202 pub struct LightAccountInner<
203 H: Hasher,
204 A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + Default,
205 const HASH_FLAT: bool,
206 > {
207 owner: Pubkey,
208 pub account: A,
209 account_info: CompressedAccountInfo,
210 should_remove_data: bool,
211 pub read_only_account_hash: Option<[u8; 32]>,
213 _hasher: PhantomData<H>,
214 }
215
216 impl<
217 H: Hasher,
218 A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + Default,
219 const HASH_FLAT: bool,
220 > core::ops::Deref for LightAccountInner<H, A, HASH_FLAT>
221 {
222 type Target = A;
223
224 fn deref(&self) -> &Self::Target {
225 &self.account
226 }
227 }
228
229 impl<
230 H: Hasher,
231 A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + Default,
232 const HASH_FLAT: bool,
233 > core::ops::DerefMut for LightAccountInner<H, A, HASH_FLAT>
234 {
235 fn deref_mut(&mut self) -> &mut Self::Target {
236 assert!(
237 self.read_only_account_hash.is_none(),
238 "Cannot mutate read-only account"
239 );
240 &mut self.account
241 }
242 }
243
244 impl<
245 H: Hasher,
246 A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + Default,
247 const HASH_FLAT: bool,
248 > LightAccountInner<H, A, HASH_FLAT>
249 {
250 pub fn new_init(
251 owner: &impl crate::PubkeyTrait,
252 address: Option<[u8; 32]>,
253 output_state_tree_index: u8,
254 ) -> Self {
255 let output_account_info = OutAccountInfo {
256 output_merkle_tree_index: output_state_tree_index,
257 discriminator: A::LIGHT_DISCRIMINATOR,
258 ..Default::default()
259 };
260 Self {
261 owner: owner.to_solana_pubkey(),
262 account: A::default(),
263 account_info: CompressedAccountInfo {
264 address,
265 input: None,
266 output: Some(output_account_info),
267 },
268 should_remove_data: false,
269 read_only_account_hash: None,
270 _hasher: PhantomData,
271 }
272 }
273
274 pub fn discriminator(&self) -> &[u8; 8] {
275 &A::LIGHT_DISCRIMINATOR
276 }
277
278 pub fn lamports(&self) -> u64 {
279 if let Some(output) = self.account_info.output.as_ref() {
280 output.lamports
281 } else if let Some(input) = self.account_info.input.as_ref() {
282 input.lamports
283 } else {
284 0
285 }
286 }
287
288 pub fn lamports_mut(&mut self) -> &mut u64 {
289 if let Some(output) = self.account_info.output.as_mut() {
290 &mut output.lamports
291 } else if let Some(input) = self.account_info.input.as_mut() {
292 &mut input.lamports
293 } else {
294 panic!("No lamports field available in account_info")
295 }
296 }
297
298 pub fn address(&self) -> &Option<[u8; 32]> {
299 &self.account_info.address
300 }
301
302 pub fn owner(&self) -> &Pubkey {
303 &self.owner
304 }
305
306 pub fn in_account_info(&self) -> &Option<InAccountInfo> {
307 &self.account_info.input
308 }
309
310 pub fn out_account_info(&mut self) -> &Option<OutAccountInfo> {
311 &self.account_info.output
312 }
313 }
314
315 impl<
317 H: Hasher,
318 A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + DataHasher + Default,
319 > LightAccountInner<H, A, false>
320 {
321 pub fn new_mut(
322 owner: &impl crate::PubkeyTrait,
323 input_account_meta: &impl CompressedAccountMetaTrait,
324 input_account: A,
325 ) -> Result<Self, LightSdkError> {
326 let input_account_info = {
327 let input_data_hash = input_account.hash::<H>()?;
329 let tree_info = input_account_meta.get_tree_info();
330 InAccountInfo {
331 data_hash: input_data_hash,
332 lamports: input_account_meta.get_lamports().unwrap_or_default(),
333 merkle_context: PackedMerkleContext {
334 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
335 queue_pubkey_index: tree_info.queue_pubkey_index,
336 leaf_index: tree_info.leaf_index,
337 prove_by_index: tree_info.prove_by_index,
338 },
339 root_index: input_account_meta.get_root_index().unwrap_or_default(),
340 discriminator: A::LIGHT_DISCRIMINATOR,
341 }
342 };
343 let output_account_info = {
344 let output_merkle_tree_index = input_account_meta
345 .get_output_state_tree_index()
346 .ok_or(LightSdkError::OutputStateTreeIndexIsNone)?;
347 OutAccountInfo {
348 lamports: input_account_meta.get_lamports().unwrap_or_default(),
349 output_merkle_tree_index,
350 discriminator: A::LIGHT_DISCRIMINATOR,
351 ..Default::default()
352 }
353 };
354
355 Ok(Self {
356 owner: owner.to_solana_pubkey(),
357 account: input_account,
358 account_info: CompressedAccountInfo {
359 address: input_account_meta.get_address(),
360 input: Some(input_account_info),
361 output: Some(output_account_info),
362 },
363 should_remove_data: false,
364 read_only_account_hash: None,
365 _hasher: PhantomData,
366 })
367 }
368
369 pub fn new_empty(
370 owner: &impl crate::PubkeyTrait,
371 input_account_meta: &impl CompressedAccountMetaTrait,
372 ) -> Result<Self, LightSdkError> {
373 let input_account_info = {
374 let input_data_hash = DEFAULT_DATA_HASH;
375 let tree_info = input_account_meta.get_tree_info();
376 InAccountInfo {
377 data_hash: input_data_hash,
378 lamports: input_account_meta.get_lamports().unwrap_or_default(),
379 merkle_context: PackedMerkleContext {
380 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
381 queue_pubkey_index: tree_info.queue_pubkey_index,
382 leaf_index: tree_info.leaf_index,
383 prove_by_index: tree_info.prove_by_index,
384 },
385 root_index: input_account_meta.get_root_index().unwrap_or_default(),
386 discriminator: [0u8; 8],
387 }
388 };
389 let output_account_info = {
390 let output_merkle_tree_index = input_account_meta
391 .get_output_state_tree_index()
392 .ok_or(LightSdkError::OutputStateTreeIndexIsNone)?;
393 OutAccountInfo {
394 lamports: input_account_meta.get_lamports().unwrap_or_default(),
395 output_merkle_tree_index,
396 discriminator: A::LIGHT_DISCRIMINATOR,
397 ..Default::default()
398 }
399 };
400
401 Ok(Self {
402 owner: owner.to_solana_pubkey(),
403 account: A::default(),
404 account_info: CompressedAccountInfo {
405 address: input_account_meta.get_address(),
406 input: Some(input_account_info),
407 output: Some(output_account_info),
408 },
409 should_remove_data: false,
410 read_only_account_hash: None,
411 _hasher: PhantomData,
412 })
413 }
414
415 pub fn new_close(
416 owner: &impl crate::PubkeyTrait,
417 input_account_meta: &impl CompressedAccountMetaTrait,
418 input_account: A,
419 ) -> Result<Self, LightSdkError> {
420 let mut account = Self::new_mut(owner, input_account_meta, input_account)?;
421 account.should_remove_data = true;
422
423 Ok(account)
424 }
425
426 pub fn new_burn(
432 owner: &impl crate::PubkeyTrait,
433 input_account_meta: &CompressedAccountMetaBurn,
434 input_account: A,
435 ) -> Result<Self, LightSdkError> {
436 let input_account_info = {
437 let input_data_hash = input_account.hash::<H>()?;
439 let tree_info = input_account_meta.get_tree_info();
440 InAccountInfo {
441 data_hash: input_data_hash,
442 lamports: input_account_meta.get_lamports().unwrap_or_default(),
443 merkle_context: PackedMerkleContext {
444 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
445 queue_pubkey_index: tree_info.queue_pubkey_index,
446 leaf_index: tree_info.leaf_index,
447 prove_by_index: tree_info.prove_by_index,
448 },
449 root_index: input_account_meta.get_root_index().unwrap_or_default(),
450 discriminator: A::LIGHT_DISCRIMINATOR,
451 }
452 };
453
454 Ok(Self {
455 owner: owner.to_solana_pubkey(),
456 account: input_account,
457 account_info: CompressedAccountInfo {
458 address: input_account_meta.get_address(),
459 input: Some(input_account_info),
460 output: None,
461 },
462 should_remove_data: false,
463 read_only_account_hash: None,
464 _hasher: PhantomData,
465 })
466 }
467
468 #[cfg(feature = "v2")]
482 pub fn new_read_only(
483 owner: &impl crate::PubkeyTrait,
484 input_account_meta: &CompressedAccountMetaReadOnly,
485 input_account: A,
486 packed_account_pubkeys: &[Pubkey],
487 ) -> Result<Self, ProgramError> {
488 let input_data_hash = input_account
490 .hash::<H>()
491 .map_err(LightSdkError::from)
492 .map_err(ProgramError::from)?;
493 let tree_info = input_account_meta.get_tree_info();
494
495 let input_account_info = InAccountInfo {
496 data_hash: input_data_hash,
497 lamports: 0, merkle_context: PackedMerkleContext {
499 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
500 queue_pubkey_index: tree_info.queue_pubkey_index,
501 leaf_index: tree_info.leaf_index,
502 prove_by_index: tree_info.prove_by_index,
503 },
504 root_index: input_account_meta.get_root_index().unwrap_or_default(),
505 discriminator: A::LIGHT_DISCRIMINATOR,
506 };
507
508 let account_hash = {
510 use light_compressed_account::compressed_account::{
511 CompressedAccount, CompressedAccountData,
512 };
513
514 let compressed_account = CompressedAccount {
515 address: Some(input_account_meta.address),
516 owner: owner.to_array().into(),
517 data: Some(CompressedAccountData {
518 data: vec![], data_hash: input_data_hash, discriminator: A::LIGHT_DISCRIMINATOR,
521 }),
522 lamports: 0,
523 };
524
525 let merkle_tree_pubkey = packed_account_pubkeys
527 .get(tree_info.merkle_tree_pubkey_index as usize)
528 .ok_or(LightSdkError::InvalidMerkleTreeIndex)
529 .map_err(ProgramError::from)?
530 .to_bytes()
531 .into();
532
533 compressed_account
534 .hash(&merkle_tree_pubkey, &tree_info.leaf_index, true)
535 .map_err(LightSdkError::from)
536 .map_err(ProgramError::from)?
537 };
538
539 Ok(Self {
540 owner: owner.to_solana_pubkey(),
541 account: input_account,
542 account_info: CompressedAccountInfo {
543 address: Some(input_account_meta.address),
544 input: Some(input_account_info),
545 output: None,
546 },
547 should_remove_data: false,
548 read_only_account_hash: Some(account_hash),
549 _hasher: PhantomData,
550 })
551 }
552
553 pub fn to_account_info(mut self) -> Result<CompressedAccountInfo, ProgramError> {
554 if self.read_only_account_hash.is_some() {
555 return Err(LightSdkError::ReadOnlyAccountCannotUseToAccountInfo.into());
556 }
557
558 if let Some(output) = self.account_info.output.as_mut() {
559 if self.should_remove_data {
560 if !output.data.is_empty() {
562 return Err(LightSdkError::ExpectedNoData.into());
563 }
564 output.data_hash = DEFAULT_DATA_HASH;
565 output.discriminator = [0u8; 8];
566 } else {
567 output.data = self
568 .account
569 .try_to_vec()
570 .map_err(|_| LightSdkError::Borsh)?;
571 output.data_hash = self
573 .account
574 .hash::<H>()
575 .map_err(LightSdkError::from)
576 .map_err(ProgramError::from)?;
577 }
578 }
579 Ok(self.account_info)
580 }
581
582 #[cfg(feature = "v2")]
583 pub fn to_packed_read_only_account(
584 self,
585 ) -> Result<
586 light_compressed_account::compressed_account::PackedReadOnlyCompressedAccount,
587 ProgramError,
588 > {
589 let account_hash = self
590 .read_only_account_hash
591 .ok_or(LightSdkError::NotReadOnlyAccount)?;
592
593 let input_account = self
594 .account_info
595 .input
596 .ok_or(ProgramError::InvalidAccountData)?;
597
598 use light_compressed_account::compressed_account::PackedReadOnlyCompressedAccount;
599 Ok(PackedReadOnlyCompressedAccount {
600 root_index: input_account.root_index,
601 merkle_context: input_account.merkle_context,
602 account_hash,
603 })
604 }
605 pub fn to_in_account(&self) -> Option<InAccount> {
606 self.account_info
607 .input
608 .as_ref()
609 .map(|input| input.into_in_account(self.account_info.address))
610 }
611
612 pub fn to_output_compressed_account_with_packed_context(
613 &self,
614 owner: Option<solana_pubkey::Pubkey>,
615 ) -> Result<Option<OutputCompressedAccountWithPackedContext>, ProgramError> {
616 let owner = if let Some(owner) = owner {
617 owner.to_bytes().into()
618 } else {
619 self.owner.to_bytes().into()
620 };
621
622 if let Some(mut output) = self.account_info.output.clone() {
623 if self.should_remove_data {
624 if !output.data.is_empty() {
626 return Err(LightSdkError::ExpectedNoData.into());
627 }
628 output.data_hash = DEFAULT_DATA_HASH;
629 output.discriminator = [0u8; 8];
630 } else {
631 output.data = self
632 .account
633 .try_to_vec()
634 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
635 output.data_hash = self
637 .account
638 .hash::<H>()
639 .map_err(LightSdkError::from)
640 .map_err(ProgramError::from)?;
641 output.data = self
642 .account
643 .try_to_vec()
644 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
645 }
646 let result = OutputCompressedAccountWithPackedContext::from_with_owner(
647 &output,
648 owner,
649 self.account_info.address,
650 );
651 Ok(Some(result))
652 } else {
653 Ok(None)
654 }
655 }
656 }
657
658 impl<H: Hasher, A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + Default>
660 LightAccountInner<H, A, true>
661 {
662 pub fn new_mut(
663 owner: &impl crate::PubkeyTrait,
664 input_account_meta: &impl CompressedAccountMetaTrait,
665 input_account: A,
666 ) -> Result<Self, ProgramError> {
667 let input_account_info = {
668 let data = input_account
670 .try_to_vec()
671 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
672 let mut input_data_hash = H::hash(data.as_slice())
673 .map_err(LightSdkError::from)
674 .map_err(ProgramError::from)?;
675 input_data_hash[0] = 0;
676 let tree_info = input_account_meta.get_tree_info();
677 InAccountInfo {
678 data_hash: input_data_hash,
679 lamports: input_account_meta.get_lamports().unwrap_or_default(),
680 merkle_context: PackedMerkleContext {
681 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
682 queue_pubkey_index: tree_info.queue_pubkey_index,
683 leaf_index: tree_info.leaf_index,
684 prove_by_index: tree_info.prove_by_index,
685 },
686 root_index: input_account_meta.get_root_index().unwrap_or_default(),
687 discriminator: A::LIGHT_DISCRIMINATOR,
688 }
689 };
690 let output_account_info = {
691 let output_merkle_tree_index = input_account_meta
692 .get_output_state_tree_index()
693 .ok_or(LightSdkError::OutputStateTreeIndexIsNone)
694 .map_err(ProgramError::from)?;
695 OutAccountInfo {
696 lamports: input_account_meta.get_lamports().unwrap_or_default(),
697 output_merkle_tree_index,
698 discriminator: A::LIGHT_DISCRIMINATOR,
699 ..Default::default()
700 }
701 };
702
703 Ok(Self {
704 owner: owner.to_solana_pubkey(),
705 account: input_account,
706 account_info: CompressedAccountInfo {
707 address: input_account_meta.get_address(),
708 input: Some(input_account_info),
709 output: Some(output_account_info),
710 },
711 should_remove_data: false,
712 read_only_account_hash: None,
713 _hasher: PhantomData,
714 })
715 }
716
717 pub fn new_empty(
758 owner: &impl crate::PubkeyTrait,
759 input_account_meta: &impl CompressedAccountMetaTrait,
760 ) -> Result<Self, ProgramError> {
761 let input_account_info = {
762 let input_data_hash = DEFAULT_DATA_HASH;
763 let tree_info = input_account_meta.get_tree_info();
764 InAccountInfo {
765 data_hash: input_data_hash,
766 lamports: input_account_meta.get_lamports().unwrap_or_default(),
767 merkle_context: PackedMerkleContext {
768 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
769 queue_pubkey_index: tree_info.queue_pubkey_index,
770 leaf_index: tree_info.leaf_index,
771 prove_by_index: tree_info.prove_by_index,
772 },
773 root_index: input_account_meta.get_root_index().unwrap_or_default(),
774 discriminator: [0u8; 8],
775 }
776 };
777 let output_account_info = {
778 let output_merkle_tree_index = input_account_meta
779 .get_output_state_tree_index()
780 .ok_or(LightSdkError::OutputStateTreeIndexIsNone)
781 .map_err(ProgramError::from)?;
782 OutAccountInfo {
783 lamports: input_account_meta.get_lamports().unwrap_or_default(),
784 output_merkle_tree_index,
785 discriminator: A::LIGHT_DISCRIMINATOR,
786 ..Default::default()
787 }
788 };
789
790 Ok(Self {
791 owner: owner.to_solana_pubkey(),
792 account: A::default(),
793 account_info: CompressedAccountInfo {
794 address: input_account_meta.get_address(),
795 input: Some(input_account_info),
796 output: Some(output_account_info),
797 },
798 should_remove_data: false,
799 read_only_account_hash: None,
800 _hasher: PhantomData,
801 })
802 }
803
804 pub fn new_close(
810 owner: &impl crate::PubkeyTrait,
811 input_account_meta: &impl CompressedAccountMetaTrait,
812 input_account: A,
813 ) -> Result<Self, ProgramError> {
814 let mut account = Self::new_mut(owner, input_account_meta, input_account)?;
815 account.should_remove_data = true;
816 Ok(account)
817 }
818
819 pub fn new_burn(
822 owner: &impl crate::PubkeyTrait,
823 input_account_meta: &CompressedAccountMetaBurn,
824 input_account: A,
825 ) -> Result<Self, ProgramError> {
826 let input_account_info = {
827 let data = input_account
829 .try_to_vec()
830 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
831 let mut input_data_hash = H::hash(data.as_slice())
832 .map_err(LightSdkError::from)
833 .map_err(ProgramError::from)?;
834 input_data_hash[0] = 0;
835 let tree_info = input_account_meta.get_tree_info();
836 InAccountInfo {
837 data_hash: input_data_hash,
838 lamports: input_account_meta.get_lamports().unwrap_or_default(),
839 merkle_context: PackedMerkleContext {
840 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
841 queue_pubkey_index: tree_info.queue_pubkey_index,
842 leaf_index: tree_info.leaf_index,
843 prove_by_index: tree_info.prove_by_index,
844 },
845 root_index: input_account_meta.get_root_index().unwrap_or_default(),
846 discriminator: A::LIGHT_DISCRIMINATOR,
847 }
848 };
849
850 Ok(Self {
851 owner: owner.to_solana_pubkey(),
852 account: input_account,
853 account_info: CompressedAccountInfo {
854 address: input_account_meta.get_address(),
855 input: Some(input_account_info),
856 output: None,
857 },
858 should_remove_data: false,
859 read_only_account_hash: None,
860 _hasher: PhantomData,
861 })
862 }
863
864 #[cfg(feature = "v2")]
877 pub fn new_read_only(
878 owner: &impl crate::PubkeyTrait,
879 input_account_meta: &CompressedAccountMetaReadOnly,
880 input_account: A,
881 packed_account_pubkeys: &[Pubkey],
882 ) -> Result<Self, ProgramError> {
883 let data = input_account
885 .try_to_vec()
886 .map_err(|_| LightSdkError::Borsh)
887 .map_err(ProgramError::from)?;
888 let mut input_data_hash = H::hash(data.as_slice())
889 .map_err(LightSdkError::from)
890 .map_err(ProgramError::from)?;
891 input_data_hash[0] = 0;
892
893 let tree_info = input_account_meta.get_tree_info();
894
895 let input_account_info = InAccountInfo {
896 data_hash: input_data_hash,
897 lamports: 0, merkle_context: PackedMerkleContext {
899 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
900 queue_pubkey_index: tree_info.queue_pubkey_index,
901 leaf_index: tree_info.leaf_index,
902 prove_by_index: tree_info.prove_by_index,
903 },
904 root_index: input_account_meta.get_root_index().unwrap_or_default(),
905 discriminator: A::LIGHT_DISCRIMINATOR,
906 };
907
908 let account_hash = {
910 use light_compressed_account::compressed_account::{
911 CompressedAccount, CompressedAccountData,
912 };
913
914 let compressed_account = CompressedAccount {
915 address: Some(input_account_meta.address),
916 owner: owner.to_array().into(),
917 data: Some(CompressedAccountData {
918 data: vec![], data_hash: input_data_hash, discriminator: A::LIGHT_DISCRIMINATOR,
921 }),
922 lamports: 0,
923 };
924
925 let merkle_tree_pubkey = packed_account_pubkeys
927 .get(tree_info.merkle_tree_pubkey_index as usize)
928 .ok_or(LightSdkError::InvalidMerkleTreeIndex)
929 .map_err(ProgramError::from)?
930 .to_bytes()
931 .into();
932
933 compressed_account
934 .hash(&merkle_tree_pubkey, &tree_info.leaf_index, true)
935 .map_err(LightSdkError::from)
936 .map_err(ProgramError::from)?
937 };
938
939 Ok(Self {
940 owner: owner.to_solana_pubkey(),
941 account: input_account,
942 account_info: CompressedAccountInfo {
943 address: Some(input_account_meta.address),
944 input: Some(input_account_info),
945 output: None,
946 },
947 should_remove_data: false,
948 read_only_account_hash: Some(account_hash),
949 _hasher: PhantomData,
950 })
951 }
952
953 pub fn to_account_info(mut self) -> Result<CompressedAccountInfo, ProgramError> {
954 if self.read_only_account_hash.is_some() {
955 return Err(LightSdkError::ReadOnlyAccountCannotUseToAccountInfo.into());
956 }
957
958 if let Some(output) = self.account_info.output.as_mut() {
959 if self.should_remove_data {
960 if !output.data.is_empty() {
962 return Err(LightSdkError::ExpectedNoData.into());
963 }
964 output.data_hash = DEFAULT_DATA_HASH;
965 output.discriminator = [0u8; 8];
966 } else {
967 output.data = self
968 .account
969 .try_to_vec()
970 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
971 output.data_hash = H::hash(output.data.as_slice())
973 .map_err(LightSdkError::from)
974 .map_err(ProgramError::from)?;
975 output.data_hash[0] = 0;
976 }
977 }
978 Ok(self.account_info)
979 }
980
981 #[cfg(feature = "v2")]
982 pub fn to_packed_read_only_account(
983 self,
984 ) -> Result<
985 light_compressed_account::compressed_account::PackedReadOnlyCompressedAccount,
986 ProgramError,
987 > {
988 let account_hash = self
989 .read_only_account_hash
990 .ok_or(LightSdkError::NotReadOnlyAccount)?;
991
992 let input_account = self
993 .account_info
994 .input
995 .ok_or(ProgramError::InvalidAccountData)?;
996
997 use light_compressed_account::compressed_account::PackedReadOnlyCompressedAccount;
998 Ok(PackedReadOnlyCompressedAccount {
999 root_index: input_account.root_index,
1000 merkle_context: input_account.merkle_context,
1001 account_hash,
1002 })
1003 }
1004
1005 pub fn to_in_account(&self) -> Option<InAccount> {
1006 self.account_info
1007 .input
1008 .as_ref()
1009 .map(|input| input.into_in_account(self.account_info.address))
1010 }
1011
1012 pub fn to_output_compressed_account_with_packed_context(
1013 &self,
1014 owner: Option<solana_pubkey::Pubkey>,
1015 ) -> Result<Option<OutputCompressedAccountWithPackedContext>, ProgramError> {
1016 let owner = if let Some(owner) = owner {
1017 owner.to_bytes().into()
1018 } else {
1019 self.owner.to_bytes().into()
1020 };
1021
1022 if let Some(mut output) = self.account_info.output.clone() {
1023 if self.should_remove_data {
1024 if !output.data.is_empty() {
1026 return Err(LightSdkError::ExpectedNoData.into());
1027 }
1028 output.data_hash = DEFAULT_DATA_HASH;
1029 output.discriminator = [0u8; 8];
1030 } else {
1031 output.data = self
1032 .account
1033 .try_to_vec()
1034 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
1035 output.data_hash = H::hash(output.data.as_slice())
1037 .map_err(LightSdkError::from)
1038 .map_err(ProgramError::from)?;
1039 output.data_hash[0] = 0;
1040 output.data = self
1041 .account
1042 .try_to_vec()
1043 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
1044 }
1045
1046 let result = OutputCompressedAccountWithPackedContext::from_with_owner(
1047 &output,
1048 owner,
1049 self.account_info.address,
1050 );
1051 Ok(Some(result))
1052 } else {
1053 Ok(None)
1054 }
1055 }
1056 }
1057}