1pub mod account_root;
2pub mod array_object;
3pub mod current_escrow;
4pub mod escrow;
5pub mod traits;
6
7use crate::core::types::uint::{HASH160_SIZE, HASH192_SIZE, Hash160, Hash192};
8use crate::host::error_codes::{
9 match_result_code_with_expected_bytes, match_result_code_with_expected_bytes_optional,
10};
11use crate::host::{Result, get_current_ledger_obj_field, get_ledger_obj_field};
12
13pub trait LedgerObjectFieldGetter: Sized {
62 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self>;
74
75 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>>;
88
89 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self>;
102
103 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>>;
117}
118
119trait FixedSizeFieldType: Sized {
132 const SIZE: usize;
134}
135
136impl FixedSizeFieldType for u8 {
137 const SIZE: usize = 1;
138}
139
140impl FixedSizeFieldType for u16 {
141 const SIZE: usize = 2;
142}
143
144impl FixedSizeFieldType for u32 {
145 const SIZE: usize = 4;
146}
147
148impl FixedSizeFieldType for u64 {
149 const SIZE: usize = 8;
150}
151
152impl<T: FixedSizeFieldType> LedgerObjectFieldGetter for T {
166 #[inline]
167 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
168 let mut value = core::mem::MaybeUninit::<T>::uninit();
169 let result_code =
170 unsafe { get_current_ledger_obj_field(field_code, value.as_mut_ptr().cast(), T::SIZE) };
171 match_result_code_with_expected_bytes(result_code, T::SIZE, || unsafe {
172 value.assume_init()
173 })
174 }
175
176 #[inline]
177 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
178 let mut value = core::mem::MaybeUninit::<T>::uninit();
179 let result_code =
180 unsafe { get_current_ledger_obj_field(field_code, value.as_mut_ptr().cast(), T::SIZE) };
181 match_result_code_with_expected_bytes_optional(result_code, T::SIZE, || {
182 Some(unsafe { value.assume_init() })
183 })
184 }
185
186 #[inline]
187 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
188 let mut value = core::mem::MaybeUninit::<T>::uninit();
189 let result_code = unsafe {
190 get_ledger_obj_field(register_num, field_code, value.as_mut_ptr().cast(), T::SIZE)
191 };
192 match_result_code_with_expected_bytes(result_code, T::SIZE, || unsafe {
193 value.assume_init()
194 })
195 }
196
197 #[inline]
198 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
199 let mut value = core::mem::MaybeUninit::<T>::uninit();
200 let result_code = unsafe {
201 get_ledger_obj_field(register_num, field_code, value.as_mut_ptr().cast(), T::SIZE)
202 };
203 match_result_code_with_expected_bytes_optional(result_code, T::SIZE, || {
204 Some(unsafe { value.assume_init() })
205 })
206 }
207}
208
209impl LedgerObjectFieldGetter for Hash160 {
219 #[inline]
220 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
221 let mut buffer = core::mem::MaybeUninit::<[u8; HASH160_SIZE]>::uninit();
222 let result_code = unsafe {
223 get_current_ledger_obj_field(field_code, buffer.as_mut_ptr().cast(), HASH160_SIZE)
224 };
225 match_result_code_with_expected_bytes(result_code, HASH160_SIZE, || {
226 Hash160::from(unsafe { buffer.assume_init() })
227 })
228 }
229
230 #[inline]
231 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
232 let mut buffer = core::mem::MaybeUninit::<[u8; HASH160_SIZE]>::uninit();
233 let result_code = unsafe {
234 get_current_ledger_obj_field(field_code, buffer.as_mut_ptr().cast(), HASH160_SIZE)
235 };
236 match_result_code_with_expected_bytes_optional(result_code, HASH160_SIZE, || {
237 Some(Hash160::from(unsafe { buffer.assume_init() }))
238 })
239 }
240
241 #[inline]
242 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
243 let mut buffer = core::mem::MaybeUninit::<[u8; HASH160_SIZE]>::uninit();
244 let result_code = unsafe {
245 get_ledger_obj_field(
246 register_num,
247 field_code,
248 buffer.as_mut_ptr().cast(),
249 HASH160_SIZE,
250 )
251 };
252 match_result_code_with_expected_bytes(result_code, HASH160_SIZE, || {
253 Hash160::from(unsafe { buffer.assume_init() })
254 })
255 }
256
257 #[inline]
258 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
259 let mut buffer = core::mem::MaybeUninit::<[u8; HASH160_SIZE]>::uninit();
260 let result_code = unsafe {
261 get_ledger_obj_field(
262 register_num,
263 field_code,
264 buffer.as_mut_ptr().cast(),
265 HASH160_SIZE,
266 )
267 };
268 match_result_code_with_expected_bytes_optional(result_code, HASH160_SIZE, || {
269 Some(Hash160::from(unsafe { buffer.assume_init() }))
270 })
271 }
272}
273
274impl LedgerObjectFieldGetter for Hash192 {
284 #[inline]
285 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
286 let mut buffer = core::mem::MaybeUninit::<[u8; HASH192_SIZE]>::uninit();
287 let result_code = unsafe {
288 get_current_ledger_obj_field(field_code, buffer.as_mut_ptr().cast(), HASH192_SIZE)
289 };
290 match_result_code_with_expected_bytes(result_code, HASH192_SIZE, || {
291 Hash192::from(unsafe { buffer.assume_init() })
292 })
293 }
294
295 #[inline]
296 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
297 let mut buffer = core::mem::MaybeUninit::<[u8; HASH192_SIZE]>::uninit();
298 let result_code = unsafe {
299 get_current_ledger_obj_field(field_code, buffer.as_mut_ptr().cast(), HASH192_SIZE)
300 };
301 match_result_code_with_expected_bytes_optional(result_code, HASH192_SIZE, || {
302 Some(Hash192::from(unsafe { buffer.assume_init() }))
303 })
304 }
305
306 #[inline]
307 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
308 let mut buffer = core::mem::MaybeUninit::<[u8; HASH192_SIZE]>::uninit();
309 let result_code = unsafe {
310 get_ledger_obj_field(
311 register_num,
312 field_code,
313 buffer.as_mut_ptr().cast(),
314 HASH192_SIZE,
315 )
316 };
317 match_result_code_with_expected_bytes(result_code, HASH192_SIZE, || {
318 Hash192::from(unsafe { buffer.assume_init() })
319 })
320 }
321
322 #[inline]
323 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
324 let mut buffer = core::mem::MaybeUninit::<[u8; HASH192_SIZE]>::uninit();
325 let result_code = unsafe {
326 get_ledger_obj_field(
327 register_num,
328 field_code,
329 buffer.as_mut_ptr().cast(),
330 HASH192_SIZE,
331 )
332 };
333 match_result_code_with_expected_bytes_optional(result_code, HASH192_SIZE, || {
334 Some(Hash192::from(unsafe { buffer.assume_init() }))
335 })
336 }
337}
338
339pub mod current_ledger_object {
340 use super::LedgerObjectFieldGetter;
341 use crate::host::Result;
342 use crate::sfield::SField;
343
344 #[inline]
367 pub fn get_field<T: LedgerObjectFieldGetter, const CODE: i32>(
368 _field: SField<T, CODE>,
369 ) -> Result<T> {
370 T::get_from_current_ledger_obj(CODE)
371 }
372
373 #[inline]
386 pub fn get_field_optional<T: LedgerObjectFieldGetter, const CODE: i32>(
387 _field: SField<T, CODE>,
388 ) -> Result<Option<T>> {
389 T::get_from_current_ledger_obj_optional(CODE)
390 }
391}
392
393pub mod ledger_object {
394 use super::LedgerObjectFieldGetter;
395 use crate::host::Result;
396 use crate::sfield::SField;
397
398 #[inline]
422 pub fn get_field<T: LedgerObjectFieldGetter, const CODE: i32>(
423 register_num: i32,
424 _field: SField<T, CODE>,
425 ) -> Result<T> {
426 T::get_from_ledger_obj(register_num, CODE)
427 }
428
429 #[inline]
443 pub fn get_field_optional<T: LedgerObjectFieldGetter, const CODE: i32>(
444 register_num: i32,
445 _field: SField<T, CODE>,
446 ) -> Result<Option<T>> {
447 T::get_from_ledger_obj_optional(register_num, CODE)
448 }
449
450 #[cfg(test)]
451 mod tests {
452 use super::*;
453 use crate::core::ledger_objects::{current_ledger_object, ledger_object};
454 use crate::core::types::account_id::{ACCOUNT_ID_SIZE, AccountID};
455 use crate::core::types::amount::Amount;
456 use crate::core::types::blob::{Blob, DEFAULT_BLOB_SIZE};
457 use crate::core::types::public_key::PUBLIC_KEY_BUFFER_SIZE;
458 use crate::core::types::uint::{HASH128_SIZE, HASH256_SIZE, Hash128, Hash256};
459 use crate::host::host_bindings_trait::MockHostBindings;
460 use crate::host::setup_mock;
461 use crate::sfield;
462 use mockall::predicate::{always, eq};
463
464 fn expect_current_field(
470 mock: &mut MockHostBindings,
471 field_code: i32,
472 size: usize,
473 times: usize,
474 ) {
475 mock.expect_get_current_ledger_obj_field()
476 .with(eq(field_code), always(), eq(size))
477 .times(times)
478 .returning(move |_, _, _| size as i32);
479 }
480
481 fn expect_ledger_field(
483 mock: &mut MockHostBindings,
484 slot: i32,
485 field_code: i32,
486 size: usize,
487 times: usize,
488 ) {
489 mock.expect_get_ledger_obj_field()
490 .with(eq(slot), eq(field_code), always(), eq(size))
491 .times(times)
492 .returning(move |_, _, _, _| size as i32);
493 }
494
495 #[test]
502 fn test_field_getter_basic_types() {
503 let mut mock = MockHostBindings::new();
504
505 expect_current_field(&mut mock, sfield::LedgerEntryType.into(), 2, 1);
506 expect_current_field(&mut mock, sfield::Flags.into(), 4, 1);
507 expect_current_field(&mut mock, sfield::Balance.into(), 8, 1);
508
509 let _guard = setup_mock(mock);
510
511 assert!(u16::get_from_current_ledger_obj(sfield::LedgerEntryType.into()).is_ok());
513 assert!(u32::get_from_current_ledger_obj(sfield::Flags.into()).is_ok());
514 assert!(u64::get_from_current_ledger_obj(sfield::Balance.into()).is_ok());
515 }
516
517 #[test]
518 fn test_field_getter_xrpl_types() {
519 let mut mock = MockHostBindings::new();
520
521 expect_current_field(&mut mock, sfield::Account.into(), ACCOUNT_ID_SIZE, 1);
522 expect_current_field(&mut mock, sfield::Amount.into(), 48, 1);
523 expect_current_field(&mut mock, sfield::EmailHash.into(), HASH128_SIZE, 1);
524 expect_current_field(&mut mock, sfield::PreviousTxnID.into(), HASH256_SIZE, 1);
525 expect_current_field(&mut mock, sfield::PublicKey.into(), DEFAULT_BLOB_SIZE, 1);
526
527 let _guard = setup_mock(mock);
528
529 assert!(AccountID::get_from_current_ledger_obj(sfield::Account.into()).is_ok());
531 assert!(Amount::get_from_current_ledger_obj(sfield::Amount.into()).is_ok());
532 assert!(Hash128::get_from_current_ledger_obj(sfield::EmailHash.into()).is_ok());
533 assert!(Hash256::get_from_current_ledger_obj(sfield::PreviousTxnID.into()).is_ok());
534
535 let blob: Blob<DEFAULT_BLOB_SIZE> =
536 Blob::get_from_current_ledger_obj(sfield::PublicKey.into()).unwrap();
537 assert_eq!(blob.len, DEFAULT_BLOB_SIZE);
539 }
540
541 #[test]
542 fn test_field_getter_optional_variants() {
543 let mut mock = MockHostBindings::new();
544
545 expect_current_field(&mut mock, sfield::Flags.into(), 4, 1);
546 expect_current_field(&mut mock, sfield::Account.into(), ACCOUNT_ID_SIZE, 1);
547
548 let _guard = setup_mock(mock);
549
550 let result = u32::get_from_current_ledger_obj_optional(sfield::Flags.into());
552 assert!(result.is_ok());
553 assert!(result.unwrap().is_some());
554
555 let result = AccountID::get_from_current_ledger_obj_optional(sfield::Account.into());
556 assert!(result.is_ok());
557 assert!(result.unwrap().is_some());
558 }
559
560 #[test]
561 fn test_field_getter_with_slot() {
562 let mut mock = MockHostBindings::new();
563 let slot = 0;
564
565 expect_ledger_field(&mut mock, slot, sfield::Flags.into(), 4, 1);
566 expect_ledger_field(&mut mock, slot, sfield::Balance.into(), 8, 1);
567 expect_ledger_field(&mut mock, slot, sfield::Account.into(), ACCOUNT_ID_SIZE, 1);
568
569 let _guard = setup_mock(mock);
570
571 assert!(u32::get_from_ledger_obj(slot, sfield::Flags.into()).is_ok());
573 assert!(u64::get_from_ledger_obj(slot, sfield::Balance.into()).is_ok());
574 assert!(AccountID::get_from_ledger_obj(slot, sfield::Account.into()).is_ok());
575 }
576
577 #[test]
578 fn test_field_getter_optional_with_slot() {
579 let mut mock = MockHostBindings::new();
580 let slot = 0;
581
582 expect_ledger_field(&mut mock, slot, sfield::Flags.into(), 4, 1);
583
584 let _guard = setup_mock(mock);
585
586 let result = u32::get_from_ledger_obj_optional(slot, sfield::Flags.into());
588 assert!(result.is_ok());
589 assert!(result.unwrap().is_some());
590 }
591
592 #[test]
597 fn test_current_ledger_object_module() {
598 let mut mock = MockHostBindings::new();
599
600 expect_current_field(&mut mock, sfield::Flags.into(), 4, 2);
601 expect_current_field(&mut mock, sfield::Account.into(), ACCOUNT_ID_SIZE, 1);
602
603 let _guard = setup_mock(mock);
604
605 assert!(current_ledger_object::get_field(sfield::Flags).is_ok());
607 assert!(current_ledger_object::get_field(sfield::Account).is_ok());
608
609 let result = current_ledger_object::get_field_optional(sfield::Flags);
610 assert!(result.is_ok());
611 assert!(result.unwrap().is_some());
612 }
613
614 #[test]
615 fn test_ledger_object_module() {
616 let mut mock = MockHostBindings::new();
617 let slot = 0;
618
619 expect_ledger_field(&mut mock, slot, sfield::LedgerEntryType.into(), 2, 1);
620 expect_ledger_field(&mut mock, slot, sfield::Flags.into(), 4, 2);
621 expect_ledger_field(&mut mock, slot, sfield::Balance.into(), 48, 1);
622 expect_ledger_field(&mut mock, slot, sfield::Account.into(), ACCOUNT_ID_SIZE, 1);
623 expect_ledger_field(&mut mock, slot, sfield::Amount.into(), 48, 1);
624 expect_ledger_field(&mut mock, slot, sfield::EmailHash.into(), HASH128_SIZE, 1);
625 expect_ledger_field(
626 &mut mock,
627 slot,
628 sfield::PreviousTxnID.into(),
629 HASH256_SIZE,
630 1,
631 );
632 expect_ledger_field(
633 &mut mock,
634 slot,
635 sfield::PublicKey.into(),
636 DEFAULT_BLOB_SIZE,
637 1,
638 );
639
640 let _guard = setup_mock(mock);
641
642 assert!(ledger_object::get_field(slot, sfield::LedgerEntryType).is_ok());
644 assert!(ledger_object::get_field(slot, sfield::Flags).is_ok());
645 assert!(ledger_object::get_field(slot, sfield::Balance).is_ok());
646 assert!(ledger_object::get_field(slot, sfield::Account).is_ok());
647 assert!(ledger_object::get_field(slot, sfield::Amount).is_ok());
648 assert!(ledger_object::get_field(slot, sfield::EmailHash).is_ok());
649 assert!(ledger_object::get_field(slot, sfield::PreviousTxnID).is_ok());
650 assert!(ledger_object::get_field(slot, sfield::PublicKey).is_ok());
651
652 let result = ledger_object::get_field_optional(slot, sfield::Flags);
653 assert!(result.is_ok());
654 assert!(result.unwrap().is_some());
655 }
656
657 #[test]
662 fn test_type_inference() {
663 let mut mock = MockHostBindings::new();
664 let slot = 0;
665
666 expect_ledger_field(&mut mock, slot, sfield::Balance.into(), 48, 1);
667 expect_ledger_field(&mut mock, slot, sfield::Account.into(), ACCOUNT_ID_SIZE, 1);
668 expect_ledger_field(&mut mock, slot, sfield::Sequence.into(), 4, 1);
669 expect_ledger_field(&mut mock, slot, sfield::Flags.into(), 4, 1);
670
671 let _guard = setup_mock(mock);
672
673 let _balance = get_field(slot, sfield::Balance);
675 let _account = get_field(slot, sfield::Account);
676
677 let _sequence: Result<u32> = get_field(slot, sfield::Sequence);
679 let _flags: Result<u32> = get_field(slot, sfield::Flags);
680 }
681
682 #[test]
687 fn test_type_sizes() {
688 let mut mock = MockHostBindings::new();
689
690 expect_current_field(&mut mock, sfield::EmailHash.into(), HASH128_SIZE, 1);
691 expect_current_field(&mut mock, sfield::PreviousTxnID.into(), HASH256_SIZE, 1);
692 expect_current_field(&mut mock, sfield::Account.into(), ACCOUNT_ID_SIZE, 1);
693 expect_current_field(
694 &mut mock,
695 sfield::PublicKey.into(),
696 PUBLIC_KEY_BUFFER_SIZE,
697 1,
698 );
699
700 let _guard = setup_mock(mock);
701
702 let hash128 = Hash128::get_from_current_ledger_obj(sfield::EmailHash.into()).unwrap();
704 assert_eq!(hash128.as_bytes().len(), HASH128_SIZE);
705
706 let hash256 =
707 Hash256::get_from_current_ledger_obj(sfield::PreviousTxnID.into()).unwrap();
708 assert_eq!(hash256.as_bytes().len(), HASH256_SIZE);
709
710 let account = AccountID::get_from_current_ledger_obj(sfield::Account.into()).unwrap();
711 assert_eq!(account.0.len(), ACCOUNT_ID_SIZE);
712
713 let blob: Blob<{ PUBLIC_KEY_BUFFER_SIZE }> =
714 Blob::get_from_current_ledger_obj(sfield::PublicKey.into()).unwrap();
715 assert_eq!(blob.len, PUBLIC_KEY_BUFFER_SIZE);
717 assert_eq!(blob.data.len(), PUBLIC_KEY_BUFFER_SIZE);
718 }
719 }
720}