1use crate::core::ledger_objects::{current_ledger_object, ledger_object};
6use crate::core::types::account_id::AccountID;
7use crate::core::types::amount::Amount;
8use crate::core::types::blob::{
9 CONDITION_BLOB_SIZE, ConditionBlob, PublicKeyBlob, UriBlob, WasmBlob,
10};
11use crate::core::types::contract_data::{ContractData, XRPL_CONTRACT_DATA_SIZE};
12use crate::core::types::uint::{Hash128, Hash256};
13use crate::host::error_codes::{match_result_code, match_result_code_optional};
14use crate::host::{Error, Result, Result::Err, Result::Ok, get_ledger_obj_field};
15use crate::sfield;
16
17pub trait LedgerObjectCommonFields {
22 fn get_slot_num(&self) -> i32;
35
36 fn get_flags(&self) -> Result<u32> {
46 ledger_object::get_field(self.get_slot_num(), sfield::Flags)
47 }
48
49 fn get_ledger_entry_type(&self) -> Result<u16> {
57 ledger_object::get_field(self.get_slot_num(), sfield::LedgerEntryType)
58 }
59}
60
61pub trait CurrentLedgerObjectCommonFields {
67 fn get_flags(&self) -> Result<u32> {
77 current_ledger_object::get_field(sfield::Flags)
78 }
79
80 fn get_ledger_entry_type(&self) -> Result<u16> {
88 current_ledger_object::get_field(sfield::LedgerEntryType)
89 }
90}
91
92pub trait EscrowFields: LedgerObjectCommonFields {
98 fn get_account(&self) -> Result<AccountID> {
101 ledger_object::get_field(self.get_slot_num(), sfield::Account)
102 }
103
104 fn get_amount(&self) -> Result<Amount> {
106 const BUFFER_SIZE: usize = 48usize;
108 let mut buffer = [0u8; BUFFER_SIZE];
109
110 let result_code = unsafe {
111 get_ledger_obj_field(
112 self.get_slot_num(),
113 sfield::Amount.into(),
114 buffer.as_mut_ptr(),
115 buffer.len(),
116 )
117 };
118
119 match_result_code(result_code, || Amount::from(buffer))
120 }
121
122 fn get_cancel_after(&self) -> Result<Option<u32>> {
126 ledger_object::get_field_optional(self.get_slot_num(), sfield::CancelAfter)
127 }
128
129 fn get_condition(&self) -> Result<Option<ConditionBlob>> {
132 let mut buffer = [0u8; CONDITION_BLOB_SIZE];
133
134 let result_code = unsafe {
135 get_ledger_obj_field(
136 self.get_slot_num(),
137 sfield::Condition.into(),
138 buffer.as_mut_ptr(),
139 buffer.len(),
140 )
141 };
142
143 match_result_code_optional(result_code, || {
144 if result_code > 0 {
145 let blob = ConditionBlob {
146 data: buffer,
147 len: result_code as usize,
148 };
149 Some(blob)
150 } else {
151 None
152 }
153 })
154 }
155
156 fn get_destination(&self) -> Result<AccountID> {
158 ledger_object::get_field(self.get_slot_num(), sfield::Destination)
159 }
160
161 fn get_destination_node(&self) -> Result<Option<u64>> {
164 ledger_object::get_field_optional(self.get_slot_num(), sfield::DestinationNode)
165 }
166
167 fn get_destination_tag(&self) -> Result<Option<u32>> {
170 ledger_object::get_field_optional(self.get_slot_num(), sfield::DestinationTag)
171 }
172
173 fn get_finish_after(&self) -> Result<Option<u32>> {
177 ledger_object::get_field_optional(self.get_slot_num(), sfield::FinishAfter)
178 }
179
180 fn get_owner_node(&self) -> Result<u64> {
183 ledger_object::get_field(self.get_slot_num(), sfield::OwnerNode)
184 }
185
186 fn get_previous_txn_id(&self) -> Result<Hash256> {
188 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnID)
189 }
190
191 fn get_previous_txn_lgr_seq(&self) -> Result<u32> {
194 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnLgrSeq)
195 }
196
197 fn get_source_tag(&self) -> Result<Option<u32>> {
200 ledger_object::get_field_optional(self.get_slot_num(), sfield::SourceTag)
201 }
202
203 fn get_finish_function(&self) -> Result<Option<WasmBlob>> {
205 ledger_object::get_field_optional(self.get_slot_num(), sfield::FinishFunction)
206 }
207
208 fn get_data(&self) -> Result<ContractData> {
224 let mut data: [u8; XRPL_CONTRACT_DATA_SIZE] = [0; XRPL_CONTRACT_DATA_SIZE];
225
226 let result_code = unsafe {
227 get_ledger_obj_field(
228 self.get_slot_num(),
229 sfield::Data.into(),
230 data.as_mut_ptr(),
231 data.len(),
232 )
233 };
234
235 match result_code {
236 code if code >= 0 => Ok(ContractData {
237 data,
238 len: code as usize,
239 }),
240 code => Err(Error::from_code(code)),
241 }
242 }
243}
244
245pub trait AccountFields: LedgerObjectCommonFields {
251 fn get_account(&self) -> Result<AccountID> {
253 ledger_object::get_field(self.get_slot_num(), sfield::Account)
254 }
255
256 fn account_txn_id(&self) -> Result<Option<Hash256>> {
258 ledger_object::get_field_optional(self.get_slot_num(), sfield::AccountTxnID)
259 }
260
261 fn amm_id(&self) -> Result<Option<Hash256>> {
265 ledger_object::get_field_optional(self.get_slot_num(), sfield::AMMID)
266 }
267
268 fn balance(&self) -> Result<Option<Amount>> {
270 ledger_object::get_field_optional(self.get_slot_num(), sfield::Balance)
271 }
272
273 fn burned_nf_tokens(&self) -> Result<Option<u32>> {
276 ledger_object::get_field_optional(self.get_slot_num(), sfield::BurnedNFTokens)
277 }
278
279 fn domain(&self) -> Result<Option<UriBlob>> {
282 ledger_object::get_field_optional(self.get_slot_num(), sfield::Domain)
283 }
284
285 fn email_hash(&self) -> Result<Option<Hash128>> {
287 ledger_object::get_field_optional(self.get_slot_num(), sfield::EmailHash)
288 }
289
290 fn first_nf_token_sequence(&self) -> Result<Option<u32>> {
293 ledger_object::get_field_optional(self.get_slot_num(), sfield::FirstNFTokenSequence)
294 }
295
296 fn ledger_entry_type(&self) -> Result<u16> {
298 ledger_object::get_field(self.get_slot_num(), sfield::LedgerEntryType)
299 }
300
301 fn message_key(&self) -> Result<Option<PublicKeyBlob>> {
306 ledger_object::get_field_optional(self.get_slot_num(), sfield::MessageKey)
307 }
308
309 fn minted_nf_tokens(&self) -> Result<Option<u32>> {
312 ledger_object::get_field_optional(self.get_slot_num(), sfield::MintedNFTokens)
313 }
314
315 fn nf_token_minter(&self) -> Result<Option<AccountID>> {
318 ledger_object::get_field_optional(self.get_slot_num(), sfield::NFTokenMinter)
319 }
320
321 fn owner_count(&self) -> Result<u32> {
323 ledger_object::get_field(self.get_slot_num(), sfield::OwnerCount)
324 }
325
326 fn previous_txn_id(&self) -> Result<Hash256> {
328 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnID)
329 }
330
331 fn previous_txn_lgr_seq(&self) -> Result<u32> {
333 ledger_object::get_field(self.get_slot_num(), sfield::PreviousTxnLgrSeq)
334 }
335
336 fn regular_key(&self) -> Result<Option<AccountID>> {
339 ledger_object::get_field_optional(self.get_slot_num(), sfield::RegularKey)
340 }
341
342 fn sequence(&self) -> Result<u32> {
344 ledger_object::get_field(self.get_slot_num(), sfield::Sequence)
345 }
346
347 fn ticket_count(&self) -> Result<Option<u32>> {
351 ledger_object::get_field_optional(self.get_slot_num(), sfield::TicketCount)
352 }
353
354 fn tick_size(&self) -> Result<Option<u8>> {
357 ledger_object::get_field_optional(self.get_slot_num(), sfield::TickSize)
358 }
359
360 fn transfer_rate(&self) -> Result<Option<u32>> {
362 ledger_object::get_field_optional(self.get_slot_num(), sfield::TransferRate)
363 }
364
365 fn wallet_locator(&self) -> Result<Option<Hash256>> {
367 ledger_object::get_field_optional(self.get_slot_num(), sfield::WalletLocator)
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374 use crate::core::ledger_objects::LedgerObjectFieldGetter;
375 use crate::core::ledger_objects::account_root::AccountRoot;
376 use crate::host::error_codes::{FIELD_NOT_FOUND, INTERNAL_ERROR, INVALID_FIELD};
377 use crate::host::host_bindings_trait::MockHostBindings;
378 use crate::sfield::SField;
379 use mockall::predicate::{always, eq};
380
381 fn expect_current_field<
394 T: LedgerObjectFieldGetter + Send + std::fmt::Debug + PartialEq + 'static,
395 const CODE: i32,
396 >(
397 mock: &mut MockHostBindings,
398 _field: SField<T, CODE>,
399 size: usize,
400 times: usize,
401 ) {
402 mock.expect_get_current_ledger_obj_field()
403 .with(eq(CODE), always(), eq(size))
404 .times(times)
405 .returning(move |_, _, _| size as i32);
406 }
407
408 fn expect_ledger_field<
418 T: LedgerObjectFieldGetter + Send + std::fmt::Debug + PartialEq + 'static,
419 const CODE: i32,
420 >(
421 mock: &mut MockHostBindings,
422 slot: i32,
423 _field: SField<T, CODE>,
424 size: usize,
425 times: usize,
426 ) {
427 mock.expect_get_ledger_obj_field()
428 .with(eq(slot), eq(CODE), always(), eq(size))
429 .times(times)
430 .returning(move |_, _, _, _| size as i32);
431 }
432
433 mod ledger_object_common_fields {
434 use super::*;
435 use crate::host::setup_mock;
436
437 #[test]
438 fn test_mandatory_fields_return_ok() {
439 let mut mock = MockHostBindings::new();
440
441 expect_ledger_field(&mut mock, 1, sfield::Flags, 4, 1);
443 expect_ledger_field(&mut mock, 1, sfield::LedgerEntryType, 2, 1);
445
446 let _guard = setup_mock(mock);
447
448 let account = AccountRoot { slot_num: 1 };
449
450 assert!(account.get_flags().is_ok());
452 assert!(account.get_ledger_entry_type().is_ok());
453 }
454
455 #[test]
456 fn test_mandatory_fields_return_error_on_internal_error() {
457 let mut mock = MockHostBindings::new();
458
459 mock.expect_get_ledger_obj_field()
461 .with(eq(1), eq(sfield::Flags), always(), eq(4))
462 .times(1)
463 .returning(|_, _, _, _| INTERNAL_ERROR);
464
465 let _guard = setup_mock(mock);
466
467 let account = AccountRoot { slot_num: 1 };
468 let result = account.get_flags();
469
470 assert!(result.is_err());
471 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
472 }
473
474 #[test]
475 fn test_get_ledger_entry_type_returns_error_on_internal_error() {
476 let mut mock = MockHostBindings::new();
477
478 mock.expect_get_ledger_obj_field()
479 .with(eq(1), eq(sfield::LedgerEntryType), always(), eq(2))
480 .times(1)
481 .returning(|_, _, _, _| INTERNAL_ERROR);
482
483 let _guard = setup_mock(mock);
484
485 let account = AccountRoot { slot_num: 1 };
486 let result = account.get_ledger_entry_type();
487
488 assert!(result.is_err());
489 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
490 }
491
492 #[test]
493 fn test_mandatory_fields_return_error_on_invalid_field() {
494 let mut mock = MockHostBindings::new();
495
496 mock.expect_get_ledger_obj_field()
498 .with(eq(1), eq(sfield::Flags), always(), eq(4))
499 .times(1)
500 .returning(|_, _, _, _| INVALID_FIELD);
501
502 let _guard = setup_mock(mock);
503
504 let account = AccountRoot { slot_num: 1 };
505 let result = account.get_flags();
506
507 assert!(result.is_err());
508 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
509 }
510 }
511
512 mod escrow_fields {
513 use super::*;
514 use crate::core::types::blob::WASM_BLOB_SIZE;
515 use crate::host::setup_mock;
516
517 struct TestLedgerObject {
518 slot_num: i32,
519 }
520 impl LedgerObjectCommonFields for TestLedgerObject {
521 fn get_slot_num(&self) -> i32 {
522 self.slot_num
523 }
524 }
525 impl EscrowFields for TestLedgerObject {}
526
527 #[test]
528 fn test_mandatory_fields_return_ok() {
529 let mut mock = MockHostBindings::new();
530
531 expect_ledger_field(&mut mock, 1, sfield::Account, 20, 1);
533 expect_ledger_field(&mut mock, 1, sfield::Amount, 48, 1);
535 expect_ledger_field(&mut mock, 1, sfield::Destination, 20, 1);
537 expect_ledger_field(&mut mock, 1, sfield::OwnerNode, 8, 1);
539 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnID, 32, 1);
541 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnLgrSeq, 4, 1);
543 expect_ledger_field(&mut mock, 1, sfield::Data, 4096, 1);
545
546 let _guard = setup_mock(mock);
547
548 let obj = TestLedgerObject { slot_num: 1 };
549
550 assert!(obj.get_account().is_ok());
552 assert!(obj.get_amount().is_ok());
553 assert!(obj.get_destination().is_ok());
554 assert!(obj.get_owner_node().is_ok());
555 assert!(obj.get_previous_txn_id().is_ok());
556 assert!(obj.get_previous_txn_lgr_seq().is_ok());
557 assert!(obj.get_data().is_ok());
558 }
559
560 #[test]
561 fn test_optional_fields_return_some() {
562 let mut mock = MockHostBindings::new();
563
564 expect_ledger_field(&mut mock, 1, sfield::CancelAfter, 4, 1);
566 expect_ledger_field(&mut mock, 1, sfield::Condition, CONDITION_BLOB_SIZE, 1);
568 expect_ledger_field(&mut mock, 1, sfield::DestinationNode, 8, 1);
570 expect_ledger_field(&mut mock, 1, sfield::DestinationTag, 4, 1);
572 expect_ledger_field(&mut mock, 1, sfield::FinishAfter, 4, 1);
574 expect_ledger_field(&mut mock, 1, sfield::SourceTag, 4, 1);
576 expect_ledger_field(&mut mock, 1, sfield::FinishFunction, WASM_BLOB_SIZE, 1);
578
579 let _guard = setup_mock(mock);
580
581 let obj = TestLedgerObject { slot_num: 1 };
582
583 assert!(obj.get_cancel_after().unwrap().is_some());
585 assert!(obj.get_condition().unwrap().is_some());
586 assert!(obj.get_destination_node().unwrap().is_some());
587 assert!(obj.get_destination_tag().unwrap().is_some());
588 assert!(obj.get_finish_after().unwrap().is_some());
589 assert!(obj.get_source_tag().unwrap().is_some());
590 assert!(obj.get_finish_function().unwrap().is_some());
591 }
592
593 #[test]
594 fn test_optional_fields_return_none_when_field_not_found() {
595 let mut mock = MockHostBindings::new();
596
597 mock.expect_get_ledger_obj_field()
599 .with(eq(1), eq(sfield::CancelAfter), always(), eq(4))
600 .times(1)
601 .returning(|_, _, _, _| FIELD_NOT_FOUND);
602 mock.expect_get_ledger_obj_field()
604 .with(
605 eq(1),
606 eq(sfield::Condition),
607 always(),
608 eq(CONDITION_BLOB_SIZE),
609 )
610 .times(1)
611 .returning(|_, _, _, _| 0);
612 mock.expect_get_ledger_obj_field()
614 .with(eq(1), eq(sfield::DestinationNode), always(), eq(8))
615 .times(1)
616 .returning(|_, _, _, _| FIELD_NOT_FOUND);
617 mock.expect_get_ledger_obj_field()
619 .with(eq(1), eq(sfield::DestinationTag), always(), eq(4))
620 .times(1)
621 .returning(|_, _, _, _| FIELD_NOT_FOUND);
622 mock.expect_get_ledger_obj_field()
624 .with(eq(1), eq(sfield::FinishAfter), always(), eq(4))
625 .times(1)
626 .returning(|_, _, _, _| FIELD_NOT_FOUND);
627 mock.expect_get_ledger_obj_field()
629 .with(eq(1), eq(sfield::SourceTag), always(), eq(4))
630 .times(1)
631 .returning(|_, _, _, _| FIELD_NOT_FOUND);
632 mock.expect_get_ledger_obj_field()
634 .with(
635 eq(1),
636 eq(sfield::FinishFunction),
637 always(),
638 eq(WASM_BLOB_SIZE),
639 )
640 .times(1)
641 .returning(|_, _, _, _| 0);
642
643 let _guard = setup_mock(mock);
644
645 let obj = TestLedgerObject { slot_num: 1 };
646
647 assert!(obj.get_cancel_after().unwrap().is_none());
649 assert!(obj.get_condition().unwrap().is_none());
650 assert!(obj.get_destination_node().unwrap().is_none());
651 assert!(obj.get_destination_tag().unwrap().is_none());
652 assert!(obj.get_finish_after().unwrap().is_none());
653 assert!(obj.get_source_tag().unwrap().is_none());
654
655 let finish_function = obj.get_finish_function().unwrap();
657 assert!(finish_function.is_some());
658 assert_eq!(finish_function.unwrap().len, 0);
659 }
660
661 #[test]
662 fn test_mandatory_fields_return_error_on_internal_error() {
663 let mut mock = MockHostBindings::new();
664
665 mock.expect_get_ledger_obj_field()
667 .with(eq(1), eq(sfield::Account), always(), eq(20))
668 .times(1)
669 .returning(|_, _, _, _| INTERNAL_ERROR);
670
671 let _guard = setup_mock(mock);
672
673 let obj = TestLedgerObject { slot_num: 1 };
674 let result = obj.get_account();
675
676 assert!(result.is_err());
677 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
678 }
679
680 #[test]
681 fn test_get_data_returns_error_on_internal_error() {
682 let mut mock = MockHostBindings::new();
683
684 mock.expect_get_ledger_obj_field()
685 .with(eq(1), eq(sfield::Data), always(), eq(4096))
686 .times(1)
687 .returning(|_, _, _, _| INTERNAL_ERROR);
688
689 let _guard = setup_mock(mock);
690
691 let obj = TestLedgerObject { slot_num: 1 };
692 let result = obj.get_data();
693
694 assert!(result.is_err());
695 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
696 }
697
698 #[test]
699 fn test_mandatory_fields_return_error_on_invalid_field() {
700 let mut mock = MockHostBindings::new();
701
702 mock.expect_get_ledger_obj_field()
704 .with(eq(1), eq(sfield::Account), always(), eq(20))
705 .times(1)
706 .returning(|_, _, _, _| INVALID_FIELD);
707
708 let _guard = setup_mock(mock);
709
710 let obj = TestLedgerObject { slot_num: 1 };
711 let result = obj.get_account();
712
713 assert!(result.is_err());
714 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
715 }
716 }
717
718 mod account_fields {
719 use super::*;
720 use crate::core::types::account_id::ACCOUNT_ID_SIZE;
721 use crate::core::types::blob::{DOMAIN_BLOB_SIZE, PUBLIC_KEY_BLOB_SIZE};
722 use crate::host::setup_mock;
723
724 #[test]
725 fn test_mandatory_fields_return_ok() {
726 let mut mock = MockHostBindings::new();
727
728 expect_ledger_field(&mut mock, 1, sfield::Account, 20, 1);
730 expect_ledger_field(&mut mock, 1, sfield::OwnerCount, 4, 1);
732 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnID, 32, 1);
734 expect_ledger_field(&mut mock, 1, sfield::PreviousTxnLgrSeq, 4, 1);
736 expect_ledger_field(&mut mock, 1, sfield::Sequence, 4, 1);
738 expect_ledger_field(&mut mock, 1, sfield::LedgerEntryType, 2, 1);
740
741 let _guard = setup_mock(mock);
742
743 let account = AccountRoot { slot_num: 1 };
744
745 assert!(account.get_account().is_ok());
747 assert!(account.owner_count().is_ok());
748 assert!(account.previous_txn_id().is_ok());
749 assert!(account.previous_txn_lgr_seq().is_ok());
750 assert!(account.sequence().is_ok());
751 assert!(account.ledger_entry_type().is_ok());
752 }
753
754 #[test]
755 fn test_optional_fields_return_some() {
756 let mut mock = MockHostBindings::new();
757
758 expect_ledger_field(&mut mock, 1, sfield::AccountTxnID, 32, 1);
760 expect_ledger_field(&mut mock, 1, sfield::AMMID, 32, 1);
762 expect_ledger_field(&mut mock, 1, sfield::Balance, 48, 1);
764 expect_ledger_field(&mut mock, 1, sfield::BurnedNFTokens, 4, 1);
766 expect_ledger_field(&mut mock, 1, sfield::Domain, DOMAIN_BLOB_SIZE, 1);
768 expect_ledger_field(&mut mock, 1, sfield::EmailHash, 16, 1);
770 expect_ledger_field(&mut mock, 1, sfield::FirstNFTokenSequence, 4, 1);
772 expect_ledger_field(&mut mock, 1, sfield::MessageKey, PUBLIC_KEY_BLOB_SIZE, 1);
774 expect_ledger_field(&mut mock, 1, sfield::MintedNFTokens, 4, 1);
776 expect_ledger_field(&mut mock, 1, sfield::NFTokenMinter, 20, 1);
778 expect_ledger_field(&mut mock, 1, sfield::RegularKey, ACCOUNT_ID_SIZE, 1);
780 expect_ledger_field(&mut mock, 1, sfield::TicketCount, 4, 1);
782 expect_ledger_field(&mut mock, 1, sfield::TickSize, 1, 1);
784 expect_ledger_field(&mut mock, 1, sfield::TransferRate, 4, 1);
786 expect_ledger_field(&mut mock, 1, sfield::WalletLocator, 32, 1);
788
789 let _guard = setup_mock(mock);
790
791 let account = AccountRoot { slot_num: 1 };
792
793 assert!(account.account_txn_id().unwrap().is_some());
795 assert!(account.amm_id().unwrap().is_some());
796 assert!(account.balance().unwrap().is_some());
797 assert!(account.burned_nf_tokens().unwrap().is_some());
798 assert!(account.domain().unwrap().is_some());
799 assert!(account.email_hash().unwrap().is_some());
800 assert!(account.first_nf_token_sequence().unwrap().is_some());
801 assert!(account.message_key().unwrap().is_some());
802 assert!(account.minted_nf_tokens().unwrap().is_some());
803 assert!(account.nf_token_minter().unwrap().is_some());
804 assert!(account.regular_key().unwrap().is_some());
805 assert!(account.ticket_count().unwrap().is_some());
806 assert!(account.tick_size().unwrap().is_some());
807 assert!(account.transfer_rate().unwrap().is_some());
808 assert!(account.wallet_locator().unwrap().is_some());
809 }
810
811 #[test]
812 fn test_optional_fields_return_none_when_field_not_found() {
813 let mut mock = MockHostBindings::new();
814
815 mock.expect_get_ledger_obj_field()
817 .with(eq(1), eq(sfield::AccountTxnID), always(), eq(32))
818 .times(1)
819 .returning(|_, _, _, _| FIELD_NOT_FOUND);
820 mock.expect_get_ledger_obj_field()
822 .with(eq(1), eq(sfield::AMMID), always(), eq(32))
823 .times(1)
824 .returning(|_, _, _, _| FIELD_NOT_FOUND);
825 mock.expect_get_ledger_obj_field()
827 .with(eq(1), eq(sfield::Balance), always(), eq(48))
828 .times(1)
829 .returning(|_, _, _, _| 0);
830 mock.expect_get_ledger_obj_field()
832 .with(eq(1), eq(sfield::BurnedNFTokens), always(), eq(4))
833 .times(1)
834 .returning(|_, _, _, _| FIELD_NOT_FOUND);
835 mock.expect_get_ledger_obj_field()
837 .with(eq(1), eq(sfield::Domain), always(), eq(DOMAIN_BLOB_SIZE))
838 .times(1)
839 .returning(|_, _, _, _| 0);
840 mock.expect_get_ledger_obj_field()
842 .with(eq(1), eq(sfield::EmailHash), always(), eq(16))
843 .times(1)
844 .returning(|_, _, _, _| FIELD_NOT_FOUND);
845 mock.expect_get_ledger_obj_field()
847 .with(eq(1), eq(sfield::FirstNFTokenSequence), always(), eq(4))
848 .times(1)
849 .returning(|_, _, _, _| FIELD_NOT_FOUND);
850 mock.expect_get_ledger_obj_field()
852 .with(
853 eq(1),
854 eq(sfield::MessageKey),
855 always(),
856 eq(PUBLIC_KEY_BLOB_SIZE),
857 )
858 .times(1)
859 .returning(|_, _, _, _| 0);
860 mock.expect_get_ledger_obj_field()
862 .with(eq(1), eq(sfield::MintedNFTokens), always(), eq(4))
863 .times(1)
864 .returning(|_, _, _, _| FIELD_NOT_FOUND);
865 mock.expect_get_ledger_obj_field()
867 .with(eq(1), eq(sfield::NFTokenMinter), always(), eq(20))
868 .times(1)
869 .returning(|_, _, _, _| FIELD_NOT_FOUND);
870 mock.expect_get_ledger_obj_field()
872 .with(eq(1), eq(sfield::RegularKey), always(), eq(ACCOUNT_ID_SIZE))
873 .times(1)
874 .returning(|_, _, _, _| FIELD_NOT_FOUND);
875 mock.expect_get_ledger_obj_field()
877 .with(eq(1), eq(sfield::TicketCount), always(), eq(4))
878 .times(1)
879 .returning(|_, _, _, _| FIELD_NOT_FOUND);
880 mock.expect_get_ledger_obj_field()
882 .with(eq(1), eq(sfield::TickSize), always(), eq(1))
883 .times(1)
884 .returning(|_, _, _, _| FIELD_NOT_FOUND);
885 mock.expect_get_ledger_obj_field()
887 .with(eq(1), eq(sfield::TransferRate), always(), eq(4))
888 .times(1)
889 .returning(|_, _, _, _| FIELD_NOT_FOUND);
890 mock.expect_get_ledger_obj_field()
892 .with(eq(1), eq(sfield::WalletLocator), always(), eq(32))
893 .times(1)
894 .returning(|_, _, _, _| FIELD_NOT_FOUND);
895
896 let _guard = setup_mock(mock);
897
898 let account = AccountRoot { slot_num: 1 };
899
900 assert!(account.account_txn_id().unwrap().is_none());
902 assert!(account.amm_id().unwrap().is_none());
903 assert!(account.burned_nf_tokens().unwrap().is_none());
904 assert!(account.email_hash().unwrap().is_none());
905 assert!(account.first_nf_token_sequence().unwrap().is_none());
906 assert!(account.minted_nf_tokens().unwrap().is_none());
907 assert!(account.nf_token_minter().unwrap().is_none());
908 assert!(account.regular_key().unwrap().is_none());
909 assert!(account.ticket_count().unwrap().is_none());
910 assert!(account.tick_size().unwrap().is_none());
911 assert!(account.transfer_rate().unwrap().is_none());
912 assert!(account.wallet_locator().unwrap().is_none());
913
914 let balance = account.balance().unwrap();
917 assert!(balance.is_some());
918 let domain = account.domain().unwrap();
919 assert!(domain.is_some());
920 assert_eq!(domain.unwrap().len, 0);
921 let message_key = account.message_key().unwrap();
922 assert!(message_key.is_some());
923 assert_eq!(message_key.unwrap().len, 0);
924 }
925
926 #[test]
927 fn test_mandatory_fields_return_error_on_internal_error() {
928 let mut mock = MockHostBindings::new();
929
930 mock.expect_get_ledger_obj_field()
932 .with(eq(1), eq(sfield::Account), always(), eq(20))
933 .times(1)
934 .returning(|_, _, _, _| INTERNAL_ERROR);
935
936 let _guard = setup_mock(mock);
937
938 let account = AccountRoot { slot_num: 1 };
939 let result = account.get_account();
940
941 assert!(result.is_err());
942 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
943 }
944
945 #[test]
946 fn test_mandatory_fields_return_error_on_invalid_field() {
947 let mut mock = MockHostBindings::new();
948
949 mock.expect_get_ledger_obj_field()
951 .with(eq(1), eq(sfield::Account), always(), eq(20))
952 .times(1)
953 .returning(|_, _, _, _| INVALID_FIELD);
954
955 let _guard = setup_mock(mock);
956
957 let account = AccountRoot { slot_num: 1 };
958 let result = account.get_account();
959
960 assert!(result.is_err());
961 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
962 }
963 }
964
965 mod current_ledger_object_common_fields {
966 use super::*;
967 use crate::host::setup_mock;
968
969 struct TestCurrentLedgerObject;
970 impl CurrentLedgerObjectCommonFields for TestCurrentLedgerObject {}
971
972 #[test]
973 fn test_mandatory_fields_return_ok() {
974 let mut mock = MockHostBindings::new();
975
976 expect_current_field(&mut mock, sfield::Flags, 4, 1);
978 expect_current_field(&mut mock, sfield::LedgerEntryType, 2, 1);
980
981 let _guard = setup_mock(mock);
982
983 let obj = TestCurrentLedgerObject;
984
985 assert!(obj.get_flags().is_ok());
987 assert!(obj.get_ledger_entry_type().is_ok());
988 }
989
990 #[test]
991 fn test_mandatory_fields_return_error_on_internal_error() {
992 let mut mock = MockHostBindings::new();
993
994 mock.expect_get_current_ledger_obj_field()
996 .with(eq(sfield::Flags), always(), eq(4))
997 .times(1)
998 .returning(|_, _, _| INTERNAL_ERROR);
999
1000 let _guard = setup_mock(mock);
1001
1002 let obj = TestCurrentLedgerObject;
1003 let result = obj.get_flags();
1004
1005 assert!(result.is_err());
1006 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
1007 }
1008
1009 #[test]
1010 fn test_get_ledger_entry_type_returns_error_on_internal_error() {
1011 let mut mock = MockHostBindings::new();
1012
1013 mock.expect_get_current_ledger_obj_field()
1014 .with(eq(sfield::LedgerEntryType), always(), eq(2))
1015 .times(1)
1016 .returning(|_, _, _| INTERNAL_ERROR);
1017
1018 let _guard = setup_mock(mock);
1019
1020 let obj = TestCurrentLedgerObject;
1021 let result = obj.get_ledger_entry_type();
1022
1023 assert!(result.is_err());
1024 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
1025 }
1026
1027 #[test]
1028 fn test_mandatory_fields_return_error_on_invalid_field() {
1029 let mut mock = MockHostBindings::new();
1030
1031 mock.expect_get_current_ledger_obj_field()
1033 .with(eq(sfield::Flags), always(), eq(4))
1034 .times(1)
1035 .returning(|_, _, _| INVALID_FIELD);
1036
1037 let _guard = setup_mock(mock);
1038
1039 let obj = TestCurrentLedgerObject;
1040 let result = obj.get_flags();
1041
1042 assert!(result.is_err());
1043 assert_eq!(result.err().unwrap().code(), INVALID_FIELD);
1044 }
1045 }
1046}