1use crate::core::ledger_objects::{current_ledger_object, ledger_object};
2use crate::core::types::account_id::AccountID;
3use crate::core::types::amount::Amount;
4use crate::core::types::blob::{
5 CONDITION_BLOB_SIZE, ConditionBlob, PublicKeyBlob, UriBlob, WasmBlob,
6};
7use crate::core::types::contract_data::{ContractData, XRPL_CONTRACT_DATA_SIZE};
8use crate::core::types::uint::{Hash128, Hash256};
9
10use crate::host::error_codes::{match_result_code, match_result_code_optional};
16use crate::host::{Error, get_current_ledger_obj_field, get_ledger_obj_field, update_data};
17use crate::host::{Result, Result::Err, Result::Ok};
18use crate::sfield;
19
20pub trait LedgerObjectCommonFields {
25 fn get_slot_num(&self) -> i32;
38
39 fn get_flags(&self) -> Result<u32> {
49 ledger_object::get_field(self.get_slot_num(), sfield::Flags)
50 }
51
52 fn get_ledger_entry_type(&self) -> Result<u16> {
60 ledger_object::get_field(self.get_slot_num(), sfield::LedgerEntryType)
61 }
62}
63
64pub trait CurrentLedgerObjectCommonFields {
70 fn get_flags(&self) -> Result<u32> {
80 current_ledger_object::get_field(sfield::Flags)
81 }
82
83 fn get_ledger_entry_type(&self) -> Result<u16> {
91 current_ledger_object::get_field(sfield::LedgerEntryType)
92 }
93}
94
95pub trait CurrentEscrowFields: CurrentLedgerObjectCommonFields {
100 fn get_account(&self) -> Result<AccountID> {
103 current_ledger_object::get_field(sfield::Account)
104 }
105
106 fn get_amount(&self) -> Result<Amount> {
108 current_ledger_object::get_field(sfield::Amount)
109 }
110
111 fn get_cancel_after(&self) -> Result<Option<u32>> {
115 current_ledger_object::get_field_optional(sfield::CancelAfter)
116 }
117
118 fn get_condition(&self) -> Result<Option<ConditionBlob>> {
121 let mut buffer = ConditionBlob::new();
122
123 let result_code = unsafe {
124 get_current_ledger_obj_field(
125 sfield::Condition.into(),
126 buffer.data.as_mut_ptr(),
127 buffer.capacity(),
128 )
129 };
130
131 match_result_code_optional(result_code, || {
132 buffer.len = result_code as usize;
133 (result_code > 0).then_some(buffer)
134 })
135 }
136
137 fn get_destination(&self) -> Result<AccountID> {
139 current_ledger_object::get_field(sfield::Destination)
140 }
141
142 fn get_destination_node(&self) -> Result<Option<u64>> {
145 current_ledger_object::get_field_optional(sfield::DestinationNode)
146 }
147
148 fn get_destination_tag(&self) -> Result<Option<u32>> {
151 current_ledger_object::get_field_optional(sfield::DestinationTag)
152 }
153
154 fn get_finish_after(&self) -> Result<Option<u32>> {
158 current_ledger_object::get_field_optional(sfield::FinishAfter)
159 }
160
161 fn get_owner_node(&self) -> Result<u64> {
164 current_ledger_object::get_field(sfield::OwnerNode)
165 }
166
167 fn get_previous_txn_id(&self) -> Result<Hash256> {
169 current_ledger_object::get_field(sfield::PreviousTxnID)
170 }
171
172 fn get_previous_txn_lgr_seq(&self) -> Result<u32> {
175 current_ledger_object::get_field(sfield::PreviousTxnLgrSeq)
176 }
177
178 fn get_source_tag(&self) -> Result<Option<u32>> {
181 current_ledger_object::get_field_optional(sfield::SourceTag)
182 }
183
184 fn get_finish_function(&self) -> Result<Option<WasmBlob>> {
186 current_ledger_object::get_field_optional(sfield::FinishFunction)
187 }
188
189 fn get_data(&self) -> Result<ContractData> {
200 let mut data: [u8; XRPL_CONTRACT_DATA_SIZE] = [0; XRPL_CONTRACT_DATA_SIZE];
201
202 let result_code = unsafe {
203 get_current_ledger_obj_field(sfield::Data.into(), data.as_mut_ptr(), data.len())
204 };
205
206 match result_code {
207 code if code >= 0 => Ok(ContractData {
208 data,
209 len: code as usize,
210 }),
211 code => Err(Error::from_code(code)),
212 }
213 }
214
215 fn update_current_escrow_data(data: ContractData) -> Result<()> {
227 let result_code = unsafe { update_data(data.data.as_ptr(), data.len) };
231 match_result_code(result_code, || ())
232 }
233}
234
235pub trait EscrowFields: LedgerObjectCommonFields {
241 fn get_account(&self) -> Result<AccountID> {
244 ledger_object::get_field(self.get_slot_num(), sfield::Account)
245 }
246
247 fn get_amount(&self) -> Result<Amount> {
249 const BUFFER_SIZE: usize = 48usize;
251 let mut buffer = [0u8; BUFFER_SIZE];
252
253 let result_code = unsafe {
254 get_ledger_obj_field(
255 self.get_slot_num(),
256 sfield::Amount.into(),
257 buffer.as_mut_ptr(),
258 buffer.len(),
259 )
260 };
261
262 match_result_code(result_code, || Amount::from(buffer))
263 }
264
265 fn get_cancel_after(&self) -> Result<Option<u32>> {
269 ledger_object::get_field_optional(self.get_slot_num(), sfield::CancelAfter)
270 }
271
272 fn get_condition(&self) -> Result<Option<ConditionBlob>> {
275 let mut buffer = [0u8; CONDITION_BLOB_SIZE];
276
277 let result_code = unsafe {
278 get_ledger_obj_field(
279 self.get_slot_num(),
280 sfield::Condition.into(),
281 buffer.as_mut_ptr(),
282 buffer.len(),
283 )
284 };
285
286 match_result_code_optional(result_code, || {
287 if result_code > 0 {
288 let blob = ConditionBlob {
289 data: buffer,
290 len: result_code as usize,
291 };
292 Some(blob)
293 } else {
294 None
295 }
296 })
297 }
298
299 fn get_destination(&self) -> Result<AccountID> {
301 ledger_object::get_field(self.get_slot_num(), sfield::Destination)
302 }
303
304 fn get_destination_node(&self) -> Result<Option<u64>> {
307 ledger_object::get_field_optional(self.get_slot_num(), sfield::DestinationNode)
308 }
309
310 fn get_destination_tag(&self) -> Result<Option<u32>> {
313 ledger_object::get_field_optional(self.get_slot_num(), sfield::DestinationTag)
314 }
315
316 fn get_finish_after(&self) -> Result<Option<u32>> {
320 ledger_object::get_field_optional(self.get_slot_num(), sfield::FinishAfter)
321 }
322
323 fn get_owner_node(&self) -> Result<u64> {
326 ledger_object::get_field(self.get_slot_num(), sfield::OwnerNode)
327 }
328
329 fn get_previous_txn_id(&self) -> Result<Hash256> {
331 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnID)
332 }
333
334 fn get_previous_txn_lgr_seq(&self) -> Result<u32> {
337 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnLgrSeq)
338 }
339
340 fn get_source_tag(&self) -> Result<Option<u32>> {
343 ledger_object::get_field_optional(self.get_slot_num(), sfield::SourceTag)
344 }
345
346 fn get_finish_function(&self) -> Result<Option<WasmBlob>> {
348 ledger_object::get_field_optional(self.get_slot_num(), sfield::FinishFunction)
349 }
350
351 fn get_data(&self) -> Result<ContractData> {
367 let mut data: [u8; XRPL_CONTRACT_DATA_SIZE] = [0; XRPL_CONTRACT_DATA_SIZE];
368
369 let result_code = unsafe {
370 get_ledger_obj_field(
371 self.get_slot_num(),
372 sfield::Data.into(),
373 data.as_mut_ptr(),
374 data.len(),
375 )
376 };
377
378 match result_code {
379 code if code >= 0 => Ok(ContractData {
380 data,
381 len: code as usize,
382 }),
383 code => Err(Error::from_code(code)),
384 }
385 }
386}
387
388pub trait AccountFields: LedgerObjectCommonFields {
394 fn get_account(&self) -> Result<AccountID> {
396 ledger_object::get_field(self.get_slot_num(), sfield::Account)
397 }
398
399 fn account_txn_id(&self) -> Result<Option<Hash256>> {
401 ledger_object::get_field_optional(self.get_slot_num(), sfield::AccountTxnID)
402 }
403
404 fn amm_id(&self) -> Result<Option<Hash256>> {
408 ledger_object::get_field_optional(self.get_slot_num(), sfield::AMMID)
409 }
410
411 fn balance(&self) -> Result<Option<Amount>> {
413 ledger_object::get_field_optional(self.get_slot_num(), sfield::Balance)
414 }
415
416 fn burned_nf_tokens(&self) -> Result<Option<u32>> {
419 ledger_object::get_field_optional(self.get_slot_num(), sfield::BurnedNFTokens)
420 }
421
422 fn domain(&self) -> Result<Option<UriBlob>> {
425 ledger_object::get_field_optional(self.get_slot_num(), sfield::Domain)
426 }
427
428 fn email_hash(&self) -> Result<Option<Hash128>> {
430 ledger_object::get_field_optional(self.get_slot_num(), sfield::EmailHash)
431 }
432
433 fn first_nf_token_sequence(&self) -> Result<Option<u32>> {
436 ledger_object::get_field_optional(self.get_slot_num(), sfield::FirstNFTokenSequence)
437 }
438
439 fn ledger_entry_type(&self) -> Result<u16> {
441 ledger_object::get_field(self.get_slot_num(), sfield::LedgerEntryType)
442 }
443
444 fn message_key(&self) -> Result<Option<PublicKeyBlob>> {
449 ledger_object::get_field_optional(self.get_slot_num(), sfield::MessageKey)
450 }
451
452 fn minted_nf_tokens(&self) -> Result<Option<u32>> {
455 ledger_object::get_field_optional(self.get_slot_num(), sfield::MintedNFTokens)
456 }
457
458 fn nf_token_minter(&self) -> Result<Option<AccountID>> {
461 ledger_object::get_field_optional(self.get_slot_num(), sfield::NFTokenMinter)
462 }
463
464 fn owner_count(&self) -> Result<u32> {
466 ledger_object::get_field(self.get_slot_num(), sfield::OwnerCount)
467 }
468
469 fn previous_txn_id(&self) -> Result<Hash256> {
471 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnID)
472 }
473
474 fn previous_txn_lgr_seq(&self) -> Result<u32> {
476 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnLgrSeq)
477 }
478
479 fn regular_key(&self) -> Result<Option<AccountID>> {
482 ledger_object::get_field_optional(self.get_slot_num(), sfield::RegularKey)
483 }
484
485 fn sequence(&self) -> Result<u32> {
487 ledger_object::get_field(self.get_slot_num(), sfield::Sequence)
488 }
489
490 fn ticket_count(&self) -> Result<Option<u32>> {
494 ledger_object::get_field_optional(self.get_slot_num(), sfield::TicketCount)
495 }
496
497 fn tick_size(&self) -> Result<Option<u8>> {
500 ledger_object::get_field_optional(self.get_slot_num(), sfield::TickSize)
501 }
502
503 fn transfer_rate(&self) -> Result<Option<u32>> {
505 ledger_object::get_field_optional(self.get_slot_num(), sfield::TransferRate)
506 }
507
508 fn wallet_locator(&self) -> Result<Option<Hash256>> {
510 ledger_object::get_field_optional(self.get_slot_num(), sfield::WalletLocator)
511 }
512}
513
514#[cfg(test)]
515mod tests {
516 use super::*;
517 use crate::core::ledger_objects::LedgerObjectFieldGetter;
518 use crate::core::ledger_objects::account_root::AccountRoot;
519 use crate::host::error_codes::{FIELD_NOT_FOUND, INTERNAL_ERROR, INVALID_FIELD};
520 use crate::host::host_bindings_trait::MockHostBindings;
521 use crate::sfield::SField;
522 use mockall::predicate::{always, eq};
523
524 fn expect_current_field<
537 T: LedgerObjectFieldGetter + Send + std::fmt::Debug + PartialEq + 'static,
538 const CODE: i32,
539 >(
540 mock: &mut MockHostBindings,
541 _field: SField<T, CODE>,
542 size: usize,
543 times: usize,
544 ) {
545 mock.expect_get_current_ledger_obj_field()
546 .with(eq(CODE), always(), eq(size))
547 .times(times)
548 .returning(move |_, _, _| size as i32);
549 }
550
551 fn expect_ledger_field<
561 T: LedgerObjectFieldGetter + Send + std::fmt::Debug + PartialEq + 'static,
562 const CODE: i32,
563 >(
564 mock: &mut MockHostBindings,
565 slot: i32,
566 _field: SField<T, CODE>,
567 size: usize,
568 times: usize,
569 ) {
570 mock.expect_get_ledger_obj_field()
571 .with(eq(slot), eq(CODE), always(), eq(size))
572 .times(times)
573 .returning(move |_, _, _, _| size as i32);
574 }
575
576 mod ledger_object_common_fields {
577 use super::*;
578 use crate::host::setup_mock;
579
580 #[test]
581 fn test_mandatory_fields_return_ok() {
582 let mut mock = MockHostBindings::new();
583
584 expect_ledger_field(&mut mock, 1, sfield::Flags, 4, 1);
586 expect_ledger_field(&mut mock, 1, sfield::LedgerEntryType, 2, 1);
588
589 let _guard = setup_mock(mock);
590
591 let account = AccountRoot { slot_num: 1 };
592
593 assert!(account.get_flags().is_ok());
595 assert!(account.get_ledger_entry_type().is_ok());
596 }
597
598 #[test]
599 fn test_mandatory_fields_return_error_on_internal_error() {
600 let mut mock = MockHostBindings::new();
601
602 mock.expect_get_ledger_obj_field()
604 .with(eq(1), eq(sfield::Flags), always(), eq(4))
605 .times(1)
606 .returning(|_, _, _, _| INTERNAL_ERROR);
607
608 let _guard = setup_mock(mock);
609
610 let account = AccountRoot { slot_num: 1 };
611 let result = account.get_flags();
612
613 assert!(result.is_err());
614 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
615 }
616
617 #[test]
618 fn test_get_ledger_entry_type_returns_error_on_internal_error() {
619 let mut mock = MockHostBindings::new();
620
621 mock.expect_get_ledger_obj_field()
622 .with(eq(1), eq(sfield::LedgerEntryType), always(), eq(2))
623 .times(1)
624 .returning(|_, _, _, _| INTERNAL_ERROR);
625
626 let _guard = setup_mock(mock);
627
628 let account = AccountRoot { slot_num: 1 };
629 let result = account.get_ledger_entry_type();
630
631 assert!(result.is_err());
632 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
633 }
634
635 #[test]
636 fn test_mandatory_fields_return_error_on_invalid_field() {
637 let mut mock = MockHostBindings::new();
638
639 mock.expect_get_ledger_obj_field()
641 .with(eq(1), eq(sfield::Flags), always(), eq(4))
642 .times(1)
643 .returning(|_, _, _, _| INVALID_FIELD);
644
645 let _guard = setup_mock(mock);
646
647 let account = AccountRoot { slot_num: 1 };
648 let result = account.get_flags();
649
650 assert!(result.is_err());
651 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
652 }
653 }
654
655 mod account_fields {
656 use super::*;
657 use crate::core::types::account_id::ACCOUNT_ID_SIZE;
658 use crate::core::types::blob::{DOMAIN_BLOB_SIZE, PUBLIC_KEY_BLOB_SIZE};
659 use crate::host::setup_mock;
660
661 #[test]
662 fn test_mandatory_fields_return_ok() {
663 let mut mock = MockHostBindings::new();
664
665 expect_ledger_field(&mut mock, 1, sfield::Account, 20, 1);
667 expect_ledger_field(&mut mock, 1, sfield::OwnerCount, 4, 1);
669 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnID, 32, 1);
671 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnLgrSeq, 4, 1);
673 expect_ledger_field(&mut mock, 1, sfield::Sequence, 4, 1);
675 expect_ledger_field(&mut mock, 1, sfield::LedgerEntryType, 2, 1);
677
678 let _guard = setup_mock(mock);
679
680 let account = AccountRoot { slot_num: 1 };
681
682 assert!(account.get_account().is_ok());
684 assert!(account.owner_count().is_ok());
685 assert!(account.previous_txn_id().is_ok());
686 assert!(account.previous_txn_lgr_seq().is_ok());
687 assert!(account.sequence().is_ok());
688 assert!(account.ledger_entry_type().is_ok());
689 }
690
691 #[test]
692 fn test_optional_fields_return_some() {
693 let mut mock = MockHostBindings::new();
694
695 expect_ledger_field(&mut mock, 1, sfield::AccountTxnID, 32, 1);
697 expect_ledger_field(&mut mock, 1, sfield::AMMID, 32, 1);
699 expect_ledger_field(&mut mock, 1, sfield::Balance, 48, 1);
701 expect_ledger_field(&mut mock, 1, sfield::BurnedNFTokens, 4, 1);
703 expect_ledger_field(&mut mock, 1, sfield::Domain, DOMAIN_BLOB_SIZE, 1);
705 expect_ledger_field(&mut mock, 1, sfield::EmailHash, 16, 1);
707 expect_ledger_field(&mut mock, 1, sfield::FirstNFTokenSequence, 4, 1);
709 expect_ledger_field(&mut mock, 1, sfield::MessageKey, PUBLIC_KEY_BLOB_SIZE, 1);
711 expect_ledger_field(&mut mock, 1, sfield::MintedNFTokens, 4, 1);
713 expect_ledger_field(&mut mock, 1, sfield::NFTokenMinter, 20, 1);
715 expect_ledger_field(&mut mock, 1, sfield::RegularKey, ACCOUNT_ID_SIZE, 1);
717 expect_ledger_field(&mut mock, 1, sfield::TicketCount, 4, 1);
719 expect_ledger_field(&mut mock, 1, sfield::TickSize, 1, 1);
721 expect_ledger_field(&mut mock, 1, sfield::TransferRate, 4, 1);
723 expect_ledger_field(&mut mock, 1, sfield::WalletLocator, 32, 1);
725
726 let _guard = setup_mock(mock);
727
728 let account = AccountRoot { slot_num: 1 };
729
730 assert!(account.account_txn_id().unwrap().is_some());
732 assert!(account.amm_id().unwrap().is_some());
733 assert!(account.balance().unwrap().is_some());
734 assert!(account.burned_nf_tokens().unwrap().is_some());
735 assert!(account.domain().unwrap().is_some());
736 assert!(account.email_hash().unwrap().is_some());
737 assert!(account.first_nf_token_sequence().unwrap().is_some());
738 assert!(account.message_key().unwrap().is_some());
739 assert!(account.minted_nf_tokens().unwrap().is_some());
740 assert!(account.nf_token_minter().unwrap().is_some());
741 assert!(account.regular_key().unwrap().is_some());
742 assert!(account.ticket_count().unwrap().is_some());
743 assert!(account.tick_size().unwrap().is_some());
744 assert!(account.transfer_rate().unwrap().is_some());
745 assert!(account.wallet_locator().unwrap().is_some());
746 }
747
748 #[test]
749 fn test_optional_fields_return_none_when_field_not_found() {
750 let mut mock = MockHostBindings::new();
751
752 mock.expect_get_ledger_obj_field()
754 .with(eq(1), eq(sfield::AccountTxnID), always(), eq(32))
755 .times(1)
756 .returning(|_, _, _, _| FIELD_NOT_FOUND);
757 mock.expect_get_ledger_obj_field()
759 .with(eq(1), eq(sfield::AMMID), always(), eq(32))
760 .times(1)
761 .returning(|_, _, _, _| FIELD_NOT_FOUND);
762 mock.expect_get_ledger_obj_field()
764 .with(eq(1), eq(sfield::Balance), always(), eq(48))
765 .times(1)
766 .returning(|_, _, _, _| 0);
767 mock.expect_get_ledger_obj_field()
769 .with(eq(1), eq(sfield::BurnedNFTokens), always(), eq(4))
770 .times(1)
771 .returning(|_, _, _, _| FIELD_NOT_FOUND);
772 mock.expect_get_ledger_obj_field()
774 .with(eq(1), eq(sfield::Domain), always(), eq(DOMAIN_BLOB_SIZE))
775 .times(1)
776 .returning(|_, _, _, _| 0);
777 mock.expect_get_ledger_obj_field()
779 .with(eq(1), eq(sfield::EmailHash), always(), eq(16))
780 .times(1)
781 .returning(|_, _, _, _| FIELD_NOT_FOUND);
782 mock.expect_get_ledger_obj_field()
784 .with(eq(1), eq(sfield::FirstNFTokenSequence), always(), eq(4))
785 .times(1)
786 .returning(|_, _, _, _| FIELD_NOT_FOUND);
787 mock.expect_get_ledger_obj_field()
789 .with(
790 eq(1),
791 eq(sfield::MessageKey),
792 always(),
793 eq(PUBLIC_KEY_BLOB_SIZE),
794 )
795 .times(1)
796 .returning(|_, _, _, _| 0);
797 mock.expect_get_ledger_obj_field()
799 .with(eq(1), eq(sfield::MintedNFTokens), always(), eq(4))
800 .times(1)
801 .returning(|_, _, _, _| FIELD_NOT_FOUND);
802 mock.expect_get_ledger_obj_field()
804 .with(eq(1), eq(sfield::NFTokenMinter), always(), eq(20))
805 .times(1)
806 .returning(|_, _, _, _| FIELD_NOT_FOUND);
807 mock.expect_get_ledger_obj_field()
809 .with(eq(1), eq(sfield::RegularKey), always(), eq(ACCOUNT_ID_SIZE))
810 .times(1)
811 .returning(|_, _, _, _| FIELD_NOT_FOUND);
812 mock.expect_get_ledger_obj_field()
814 .with(eq(1), eq(sfield::TicketCount), always(), eq(4))
815 .times(1)
816 .returning(|_, _, _, _| FIELD_NOT_FOUND);
817 mock.expect_get_ledger_obj_field()
819 .with(eq(1), eq(sfield::TickSize), always(), eq(1))
820 .times(1)
821 .returning(|_, _, _, _| FIELD_NOT_FOUND);
822 mock.expect_get_ledger_obj_field()
824 .with(eq(1), eq(sfield::TransferRate), always(), eq(4))
825 .times(1)
826 .returning(|_, _, _, _| FIELD_NOT_FOUND);
827 mock.expect_get_ledger_obj_field()
829 .with(eq(1), eq(sfield::WalletLocator), always(), eq(32))
830 .times(1)
831 .returning(|_, _, _, _| FIELD_NOT_FOUND);
832
833 let _guard = setup_mock(mock);
834
835 let account = AccountRoot { slot_num: 1 };
836
837 assert!(account.account_txn_id().unwrap().is_none());
839 assert!(account.amm_id().unwrap().is_none());
840 assert!(account.burned_nf_tokens().unwrap().is_none());
841 assert!(account.email_hash().unwrap().is_none());
842 assert!(account.first_nf_token_sequence().unwrap().is_none());
843 assert!(account.minted_nf_tokens().unwrap().is_none());
844 assert!(account.nf_token_minter().unwrap().is_none());
845 assert!(account.regular_key().unwrap().is_none());
846 assert!(account.ticket_count().unwrap().is_none());
847 assert!(account.tick_size().unwrap().is_none());
848 assert!(account.transfer_rate().unwrap().is_none());
849 assert!(account.wallet_locator().unwrap().is_none());
850
851 let balance = account.balance().unwrap();
854 assert!(balance.is_some());
855 let domain = account.domain().unwrap();
856 assert!(domain.is_some());
857 assert_eq!(domain.unwrap().len, 0);
858 let message_key = account.message_key().unwrap();
859 assert!(message_key.is_some());
860 assert_eq!(message_key.unwrap().len, 0);
861 }
862
863 #[test]
864 fn test_mandatory_fields_return_error_on_internal_error() {
865 let mut mock = MockHostBindings::new();
866
867 mock.expect_get_ledger_obj_field()
869 .with(eq(1), eq(sfield::Account), always(), eq(20))
870 .times(1)
871 .returning(|_, _, _, _| INTERNAL_ERROR);
872
873 let _guard = setup_mock(mock);
874
875 let account = AccountRoot { slot_num: 1 };
876 let result = account.get_account();
877
878 assert!(result.is_err());
879 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
880 }
881
882 #[test]
883 fn test_mandatory_fields_return_error_on_invalid_field() {
884 let mut mock = MockHostBindings::new();
885
886 mock.expect_get_ledger_obj_field()
888 .with(eq(1), eq(sfield::Account), always(), eq(20))
889 .times(1)
890 .returning(|_, _, _, _| INVALID_FIELD);
891
892 let _guard = setup_mock(mock);
893
894 let account = AccountRoot { slot_num: 1 };
895 let result = account.get_account();
896
897 assert!(result.is_err());
898 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
899 }
900 }
901
902 mod current_ledger_object_common_fields {
903 use super::*;
904 use crate::core::ledger_objects::current_escrow::CurrentEscrow;
905 use crate::host::setup_mock;
906
907 #[test]
908 fn test_mandatory_fields_return_ok() {
909 let mut mock = MockHostBindings::new();
910
911 expect_current_field(&mut mock, sfield::Flags, 4, 1);
913 expect_current_field(&mut mock, sfield::LedgerEntryType, 2, 1);
915
916 let _guard = setup_mock(mock);
917
918 let escrow = CurrentEscrow;
919
920 assert!(escrow.get_flags().is_ok());
922 assert!(escrow.get_ledger_entry_type().is_ok());
923 }
924
925 #[test]
926 fn test_mandatory_fields_return_error_on_internal_error() {
927 let mut mock = MockHostBindings::new();
928
929 mock.expect_get_current_ledger_obj_field()
931 .with(eq(sfield::Flags), always(), eq(4))
932 .times(1)
933 .returning(|_, _, _| INTERNAL_ERROR);
934
935 let _guard = setup_mock(mock);
936
937 let escrow = CurrentEscrow;
938 let result = escrow.get_flags();
939
940 assert!(result.is_err());
941 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
942 }
943
944 #[test]
945 fn test_get_ledger_entry_type_returns_error_on_internal_error() {
946 let mut mock = MockHostBindings::new();
947
948 mock.expect_get_current_ledger_obj_field()
949 .with(eq(sfield::LedgerEntryType), always(), eq(2))
950 .times(1)
951 .returning(|_, _, _| INTERNAL_ERROR);
952
953 let _guard = setup_mock(mock);
954
955 let escrow = CurrentEscrow;
956 let result = escrow.get_ledger_entry_type();
957
958 assert!(result.is_err());
959 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
960 }
961
962 #[test]
963 fn test_mandatory_fields_return_error_on_invalid_field() {
964 let mut mock = MockHostBindings::new();
965
966 mock.expect_get_current_ledger_obj_field()
968 .with(eq(sfield::Flags), always(), eq(4))
969 .times(1)
970 .returning(|_, _, _| INVALID_FIELD);
971
972 let _guard = setup_mock(mock);
973
974 let escrow = CurrentEscrow;
975 let result = escrow.get_flags();
976
977 assert!(result.is_err());
978 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
979 }
980 }
981
982 mod current_escrow_fields {
983 use super::*;
984 use crate::core::ledger_objects::current_escrow::CurrentEscrow;
985 use crate::core::types::blob::WASM_BLOB_SIZE;
986 use crate::host::setup_mock;
987
988 #[test]
989 fn test_mandatory_fields_return_ok() {
990 let mut mock = MockHostBindings::new();
991
992 expect_current_field(&mut mock, sfield::Account, 20, 1);
994 expect_current_field(&mut mock, sfield::Amount, 48, 1);
996 expect_current_field(&mut mock, sfield::Destination, 20, 1);
998 expect_current_field(&mut mock, sfield::OwnerNode, 8, 1);
1000 expect_current_field(&mut mock, sfield::PreviousTxnID, 32, 1);
1002 expect_current_field(&mut mock, sfield::PreviousTxnLgrSeq, 4, 1);
1004 expect_current_field(&mut mock, sfield::Data, 4096, 1);
1006
1007 let _guard = setup_mock(mock);
1008
1009 let escrow = CurrentEscrow;
1010
1011 assert!(escrow.get_account().is_ok());
1013 assert!(escrow.get_amount().is_ok());
1014 assert!(escrow.get_destination().is_ok());
1015 assert!(escrow.get_owner_node().is_ok());
1016 assert!(escrow.get_previous_txn_id().is_ok());
1017 assert!(escrow.get_previous_txn_lgr_seq().is_ok());
1018 assert!(escrow.get_data().is_ok());
1019 }
1020
1021 #[test]
1022 fn test_optional_fields_return_some() {
1023 let mut mock = MockHostBindings::new();
1024
1025 expect_current_field(&mut mock, sfield::CancelAfter, 4, 1);
1027 expect_current_field(&mut mock, sfield::Condition, CONDITION_BLOB_SIZE, 1);
1029 expect_current_field(&mut mock, sfield::DestinationNode, 8, 1);
1031 expect_current_field(&mut mock, sfield::DestinationTag, 4, 1);
1033 expect_current_field(&mut mock, sfield::FinishAfter, 4, 1);
1035 expect_current_field(&mut mock, sfield::SourceTag, 4, 1);
1037 expect_current_field(&mut mock, sfield::FinishFunction, WASM_BLOB_SIZE, 1);
1039
1040 let _guard = setup_mock(mock);
1041
1042 let escrow = CurrentEscrow;
1043
1044 assert!(escrow.get_cancel_after().unwrap().is_some());
1046 assert!(escrow.get_condition().unwrap().is_some());
1047 assert!(escrow.get_destination_node().unwrap().is_some());
1048 assert!(escrow.get_destination_tag().unwrap().is_some());
1049 assert!(escrow.get_finish_after().unwrap().is_some());
1050 assert!(escrow.get_source_tag().unwrap().is_some());
1051 assert!(escrow.get_finish_function().unwrap().is_some());
1052 }
1053
1054 #[test]
1055 fn test_optional_fields_return_none_when_field_not_found() {
1056 let mut mock = MockHostBindings::new();
1057
1058 mock.expect_get_current_ledger_obj_field()
1060 .with(eq(sfield::CancelAfter), always(), eq(4))
1061 .times(1)
1062 .returning(|_, _, _| FIELD_NOT_FOUND);
1063 mock.expect_get_current_ledger_obj_field()
1065 .with(eq(sfield::Condition), always(), eq(CONDITION_BLOB_SIZE))
1066 .times(1)
1067 .returning(|_, _, _| 0);
1068 mock.expect_get_current_ledger_obj_field()
1070 .with(eq(sfield::DestinationNode), always(), eq(8))
1071 .times(1)
1072 .returning(|_, _, _| FIELD_NOT_FOUND);
1073 mock.expect_get_current_ledger_obj_field()
1075 .with(eq(sfield::DestinationTag), always(), eq(4))
1076 .times(1)
1077 .returning(|_, _, _| FIELD_NOT_FOUND);
1078 mock.expect_get_current_ledger_obj_field()
1080 .with(eq(sfield::FinishAfter), always(), eq(4))
1081 .times(1)
1082 .returning(|_, _, _| FIELD_NOT_FOUND);
1083 mock.expect_get_current_ledger_obj_field()
1085 .with(eq(sfield::SourceTag), always(), eq(4))
1086 .times(1)
1087 .returning(|_, _, _| FIELD_NOT_FOUND);
1088 mock.expect_get_current_ledger_obj_field()
1090 .with(eq(sfield::FinishFunction), always(), eq(WASM_BLOB_SIZE))
1091 .times(1)
1092 .returning(|_, _, _| 0);
1093
1094 let _guard = setup_mock(mock);
1095
1096 let escrow = CurrentEscrow;
1097
1098 assert!(escrow.get_cancel_after().unwrap().is_none());
1100 assert!(escrow.get_condition().unwrap().is_none());
1101 assert!(escrow.get_destination_node().unwrap().is_none());
1102 assert!(escrow.get_destination_tag().unwrap().is_none());
1103 assert!(escrow.get_finish_after().unwrap().is_none());
1104 assert!(escrow.get_source_tag().unwrap().is_none());
1105
1106 let finish_function = escrow.get_finish_function().unwrap();
1108 assert!(finish_function.is_some());
1109 assert_eq!(finish_function.unwrap().len, 0);
1110 }
1111
1112 #[test]
1113 fn test_mandatory_fields_return_error_on_internal_error() {
1114 let mut mock = MockHostBindings::new();
1115
1116 mock.expect_get_current_ledger_obj_field()
1118 .with(eq(sfield::Account), always(), eq(20))
1119 .times(1)
1120 .returning(|_, _, _| INTERNAL_ERROR);
1121
1122 let _guard = setup_mock(mock);
1123
1124 let escrow = CurrentEscrow;
1125 let result = escrow.get_account();
1126
1127 assert!(result.is_err());
1128 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
1129 }
1130
1131 #[test]
1132 fn test_get_data_returns_error_on_internal_error() {
1133 let mut mock = MockHostBindings::new();
1134
1135 mock.expect_get_current_ledger_obj_field()
1136 .with(eq(sfield::Data), always(), eq(4096))
1137 .times(1)
1138 .returning(|_, _, _| INTERNAL_ERROR);
1139
1140 let _guard = setup_mock(mock);
1141
1142 let escrow = CurrentEscrow;
1143 let result = escrow.get_data();
1144
1145 assert!(result.is_err());
1146 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
1147 }
1148
1149 #[test]
1150 fn test_mandatory_fields_return_error_on_invalid_field() {
1151 let mut mock = MockHostBindings::new();
1152
1153 mock.expect_get_current_ledger_obj_field()
1155 .with(eq(sfield::Account), always(), eq(20))
1156 .times(1)
1157 .returning(|_, _, _| INVALID_FIELD);
1158
1159 let _guard = setup_mock(mock);
1160
1161 let escrow = CurrentEscrow;
1162 let result = escrow.get_account();
1163
1164 assert!(result.is_err());
1165 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
1166 }
1167 }
1168
1169 mod escrow_fields {
1170 use super::*;
1171 use crate::core::ledger_objects::escrow::Escrow;
1172 use crate::core::types::blob::WASM_BLOB_SIZE;
1173 use crate::host::setup_mock;
1174
1175 #[test]
1176 fn test_mandatory_fields_return_ok() {
1177 let mut mock = MockHostBindings::new();
1178
1179 expect_ledger_field(&mut mock, 1, sfield::Account, 20, 1);
1181 expect_ledger_field(&mut mock, 1, sfield::Amount, 48, 1);
1183 expect_ledger_field(&mut mock, 1, sfield::Destination, 20, 1);
1185 expect_ledger_field(&mut mock, 1, sfield::OwnerNode, 8, 1);
1187 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnID, 32, 1);
1189 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnLgrSeq, 4, 1);
1191 expect_ledger_field(&mut mock, 1, sfield::Data, 4096, 1);
1193
1194 let _guard = setup_mock(mock);
1195
1196 let escrow = Escrow { slot_num: 1 };
1197
1198 assert!(escrow.get_account().is_ok());
1200 assert!(escrow.get_amount().is_ok());
1201 assert!(escrow.get_destination().is_ok());
1202 assert!(escrow.get_owner_node().is_ok());
1203 assert!(escrow.get_previous_txn_id().is_ok());
1204 assert!(escrow.get_previous_txn_lgr_seq().is_ok());
1205 assert!(escrow.get_data().is_ok());
1206 }
1207
1208 #[test]
1209 fn test_optional_fields_return_some() {
1210 let mut mock = MockHostBindings::new();
1211
1212 expect_ledger_field(&mut mock, 1, sfield::CancelAfter, 4, 1);
1214 expect_ledger_field(&mut mock, 1, sfield::Condition, CONDITION_BLOB_SIZE, 1);
1216 expect_ledger_field(&mut mock, 1, sfield::DestinationNode, 8, 1);
1218 expect_ledger_field(&mut mock, 1, sfield::DestinationTag, 4, 1);
1220 expect_ledger_field(&mut mock, 1, sfield::FinishAfter, 4, 1);
1222 expect_ledger_field(&mut mock, 1, sfield::SourceTag, 4, 1);
1224 expect_ledger_field(&mut mock, 1, sfield::FinishFunction, WASM_BLOB_SIZE, 1);
1226
1227 let _guard = setup_mock(mock);
1228
1229 let escrow = Escrow { slot_num: 1 };
1230
1231 assert!(escrow.get_cancel_after().unwrap().is_some());
1233 assert!(escrow.get_condition().unwrap().is_some());
1234 assert!(escrow.get_destination_node().unwrap().is_some());
1235 assert!(escrow.get_destination_tag().unwrap().is_some());
1236 assert!(escrow.get_finish_after().unwrap().is_some());
1237 assert!(escrow.get_source_tag().unwrap().is_some());
1238 assert!(escrow.get_finish_function().unwrap().is_some());
1239 }
1240
1241 #[test]
1242 fn test_optional_fields_return_none_when_field_not_found() {
1243 let mut mock = MockHostBindings::new();
1244
1245 mock.expect_get_ledger_obj_field()
1247 .with(eq(1), eq(sfield::CancelAfter), always(), eq(4))
1248 .times(1)
1249 .returning(|_, _, _, _| FIELD_NOT_FOUND);
1250 mock.expect_get_ledger_obj_field()
1252 .with(
1253 eq(1),
1254 eq(sfield::Condition),
1255 always(),
1256 eq(CONDITION_BLOB_SIZE),
1257 )
1258 .times(1)
1259 .returning(|_, _, _, _| 0);
1260 mock.expect_get_ledger_obj_field()
1262 .with(eq(1), eq(sfield::DestinationNode), always(), eq(8))
1263 .times(1)
1264 .returning(|_, _, _, _| FIELD_NOT_FOUND);
1265 mock.expect_get_ledger_obj_field()
1267 .with(eq(1), eq(sfield::DestinationTag), always(), eq(4))
1268 .times(1)
1269 .returning(|_, _, _, _| FIELD_NOT_FOUND);
1270 mock.expect_get_ledger_obj_field()
1272 .with(eq(1), eq(sfield::FinishAfter), always(), eq(4))
1273 .times(1)
1274 .returning(|_, _, _, _| FIELD_NOT_FOUND);
1275 mock.expect_get_ledger_obj_field()
1277 .with(eq(1), eq(sfield::SourceTag), always(), eq(4))
1278 .times(1)
1279 .returning(|_, _, _, _| FIELD_NOT_FOUND);
1280 mock.expect_get_ledger_obj_field()
1282 .with(
1283 eq(1),
1284 eq(sfield::FinishFunction),
1285 always(),
1286 eq(WASM_BLOB_SIZE),
1287 )
1288 .times(1)
1289 .returning(|_, _, _, _| 0);
1290
1291 let _guard = setup_mock(mock);
1292
1293 let escrow = Escrow { slot_num: 1 };
1294
1295 assert!(escrow.get_cancel_after().unwrap().is_none());
1297 assert!(escrow.get_condition().unwrap().is_none());
1298 assert!(escrow.get_destination_node().unwrap().is_none());
1299 assert!(escrow.get_destination_tag().unwrap().is_none());
1300 assert!(escrow.get_finish_after().unwrap().is_none());
1301 assert!(escrow.get_source_tag().unwrap().is_none());
1302
1303 let finish_function = escrow.get_finish_function().unwrap();
1305 assert!(finish_function.is_some());
1306 assert_eq!(finish_function.unwrap().len, 0);
1307 }
1308
1309 #[test]
1310 fn test_mandatory_fields_return_error_on_internal_error() {
1311 let mut mock = MockHostBindings::new();
1312
1313 mock.expect_get_ledger_obj_field()
1315 .with(eq(1), eq(sfield::Account), always(), eq(20))
1316 .times(1)
1317 .returning(|_, _, _, _| INTERNAL_ERROR);
1318
1319 let _guard = setup_mock(mock);
1320
1321 let escrow = Escrow { slot_num: 1 };
1322 let result = escrow.get_account();
1323
1324 assert!(result.is_err());
1325 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
1326 }
1327
1328 #[test]
1329 fn test_get_data_returns_error_on_internal_error() {
1330 let mut mock = MockHostBindings::new();
1331
1332 mock.expect_get_ledger_obj_field()
1333 .with(eq(1), eq(sfield::Data), always(), eq(4096))
1334 .times(1)
1335 .returning(|_, _, _, _| INTERNAL_ERROR);
1336
1337 let _guard = setup_mock(mock);
1338
1339 let escrow = Escrow { slot_num: 1 };
1340 let result = escrow.get_data();
1341
1342 assert!(result.is_err());
1343 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
1344 }
1345
1346 #[test]
1347 fn test_mandatory_fields_return_error_on_invalid_field() {
1348 let mut mock = MockHostBindings::new();
1349
1350 mock.expect_get_ledger_obj_field()
1352 .with(eq(1), eq(sfield::Account), always(), eq(20))
1353 .times(1)
1354 .returning(|_, _, _, _| INVALID_FIELD);
1355
1356 let _guard = setup_mock(mock);
1357
1358 let escrow = Escrow { slot_num: 1 };
1359 let result = escrow.get_account();
1360
1361 assert!(result.is_err());
1362 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
1363 }
1364 }
1365}