1pub mod account_root;
2pub mod current_escrow;
3pub mod escrow;
4pub mod traits;
5
6use crate::host::error_codes::{
7 match_result_code_with_expected_bytes, match_result_code_with_expected_bytes_optional,
8};
9use crate::host::{Result, get_current_ledger_obj_field, get_ledger_obj_field};
10
11pub trait LedgerObjectFieldGetter: Sized {
59 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self>;
71
72 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>>;
85
86 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self>;
99
100 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>>;
114}
115
116trait FixedSizeFieldType: Sized {
129 const SIZE: usize;
131}
132
133impl FixedSizeFieldType for u8 {
134 const SIZE: usize = 1;
135}
136
137impl FixedSizeFieldType for u16 {
138 const SIZE: usize = 2;
139}
140
141impl FixedSizeFieldType for u32 {
142 const SIZE: usize = 4;
143}
144
145impl FixedSizeFieldType for u64 {
146 const SIZE: usize = 8;
147}
148
149impl<T: FixedSizeFieldType> LedgerObjectFieldGetter for T {
163 #[inline]
164 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
165 let mut value = core::mem::MaybeUninit::<T>::uninit();
166 let result_code =
167 unsafe { get_current_ledger_obj_field(field_code, value.as_mut_ptr().cast(), T::SIZE) };
168 match_result_code_with_expected_bytes(result_code, T::SIZE, || unsafe {
169 value.assume_init()
170 })
171 }
172
173 #[inline]
174 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
175 let mut value = core::mem::MaybeUninit::<T>::uninit();
176 let result_code =
177 unsafe { get_current_ledger_obj_field(field_code, value.as_mut_ptr().cast(), T::SIZE) };
178 match_result_code_with_expected_bytes_optional(result_code, T::SIZE, || {
179 Some(unsafe { value.assume_init() })
180 })
181 }
182
183 #[inline]
184 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
185 let mut value = core::mem::MaybeUninit::<T>::uninit();
186 let result_code = unsafe {
187 get_ledger_obj_field(register_num, field_code, value.as_mut_ptr().cast(), T::SIZE)
188 };
189 match_result_code_with_expected_bytes(result_code, T::SIZE, || unsafe {
190 value.assume_init()
191 })
192 }
193
194 #[inline]
195 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
196 let mut value = core::mem::MaybeUninit::<T>::uninit();
197 let result_code = unsafe {
198 get_ledger_obj_field(register_num, field_code, value.as_mut_ptr().cast(), T::SIZE)
199 };
200 match_result_code_with_expected_bytes_optional(result_code, T::SIZE, || {
201 Some(unsafe { value.assume_init() })
202 })
203 }
204}
205
206pub mod current_ledger_object {
207 use super::LedgerObjectFieldGetter;
208 use crate::host::Result;
209
210 #[inline]
222 pub fn get_field<T: LedgerObjectFieldGetter>(field_code: i32) -> Result<T> {
223 T::get_from_current_ledger_obj(field_code)
224 }
225
226 #[inline]
239 pub fn get_field_optional<T: LedgerObjectFieldGetter>(field_code: i32) -> Result<Option<T>> {
240 T::get_from_current_ledger_obj_optional(field_code)
241 }
242}
243
244pub mod ledger_object {
245 use super::LedgerObjectFieldGetter;
246 use crate::host::Result;
247
248 #[inline]
261 pub fn get_field<T: LedgerObjectFieldGetter>(register_num: i32, field_code: i32) -> Result<T> {
262 T::get_from_ledger_obj(register_num, field_code)
263 }
264
265 #[inline]
279 pub fn get_field_optional<T: LedgerObjectFieldGetter>(
280 register_num: i32,
281 field_code: i32,
282 ) -> Result<Option<T>> {
283 T::get_from_ledger_obj_optional(register_num, field_code)
284 }
285
286 #[cfg(test)]
287 mod tests {
288 use super::*;
289 use crate::core::ledger_objects::{current_ledger_object, ledger_object};
290 use crate::core::types::account_id::{ACCOUNT_ID_SIZE, AccountID};
291 use crate::core::types::amount::Amount;
292 use crate::core::types::blob::{Blob, DEFAULT_BLOB_SIZE};
293 use crate::core::types::public_key::PUBLIC_KEY_BUFFER_SIZE;
294 use crate::core::types::uint::{HASH128_SIZE, HASH256_SIZE, Hash128, Hash256};
295 use crate::host::host_bindings_trait::MockHostBindings;
296 use crate::host::setup_mock;
297 use crate::sfield;
298 use mockall::predicate::{always, eq};
299
300 fn expect_current_field(
306 mock: &mut MockHostBindings,
307 field_code: i32,
308 size: usize,
309 times: usize,
310 ) {
311 mock.expect_get_current_ledger_obj_field()
312 .with(eq(field_code), always(), eq(size))
313 .times(times)
314 .returning(move |_, _, _| size as i32);
315 }
316
317 fn expect_ledger_field(
319 mock: &mut MockHostBindings,
320 slot: i32,
321 field_code: i32,
322 size: usize,
323 times: usize,
324 ) {
325 mock.expect_get_ledger_obj_field()
326 .with(eq(slot), eq(field_code), always(), eq(size))
327 .times(times)
328 .returning(move |_, _, _, _| size as i32);
329 }
330
331 #[test]
338 fn test_field_getter_basic_types() {
339 let mut mock = MockHostBindings::new();
340
341 expect_current_field(&mut mock, sfield::LedgerEntryType, 2, 1);
342 expect_current_field(&mut mock, sfield::Flags, 4, 1);
343 expect_current_field(&mut mock, sfield::Balance, 8, 1);
344
345 let _guard = setup_mock(mock);
346
347 assert!(u16::get_from_current_ledger_obj(sfield::LedgerEntryType).is_ok());
349 assert!(u32::get_from_current_ledger_obj(sfield::Flags).is_ok());
350 assert!(u64::get_from_current_ledger_obj(sfield::Balance).is_ok());
351 }
352
353 #[test]
354 fn test_field_getter_xrpl_types() {
355 let mut mock = MockHostBindings::new();
356
357 expect_current_field(&mut mock, sfield::Account, ACCOUNT_ID_SIZE, 1);
358 expect_current_field(&mut mock, sfield::Amount, 48, 1);
359 expect_current_field(&mut mock, sfield::EmailHash, HASH128_SIZE, 1);
360 expect_current_field(&mut mock, sfield::PreviousTxnID, HASH256_SIZE, 1);
361 expect_current_field(&mut mock, sfield::PublicKey, DEFAULT_BLOB_SIZE, 1);
362
363 let _guard = setup_mock(mock);
364
365 assert!(AccountID::get_from_current_ledger_obj(sfield::Account).is_ok());
367 assert!(Amount::get_from_current_ledger_obj(sfield::Amount).is_ok());
368 assert!(Hash128::get_from_current_ledger_obj(sfield::EmailHash).is_ok());
369 assert!(Hash256::get_from_current_ledger_obj(sfield::PreviousTxnID).is_ok());
370
371 let blob: Blob<DEFAULT_BLOB_SIZE> =
372 Blob::get_from_current_ledger_obj(sfield::PublicKey).unwrap();
373 assert_eq!(blob.len, DEFAULT_BLOB_SIZE);
375 }
376
377 #[test]
378 fn test_field_getter_optional_variants() {
379 let mut mock = MockHostBindings::new();
380
381 expect_current_field(&mut mock, sfield::Flags, 4, 1);
382 expect_current_field(&mut mock, sfield::Account, ACCOUNT_ID_SIZE, 1);
383
384 let _guard = setup_mock(mock);
385
386 let result = u32::get_from_current_ledger_obj_optional(sfield::Flags);
388 assert!(result.is_ok());
389 assert!(result.unwrap().is_some());
390
391 let result = AccountID::get_from_current_ledger_obj_optional(sfield::Account);
392 assert!(result.is_ok());
393 assert!(result.unwrap().is_some());
394 }
395
396 #[test]
397 fn test_field_getter_with_slot() {
398 let mut mock = MockHostBindings::new();
399 let slot = 0;
400
401 expect_ledger_field(&mut mock, slot, sfield::Flags, 4, 1);
402 expect_ledger_field(&mut mock, slot, sfield::Balance, 8, 1);
403 expect_ledger_field(&mut mock, slot, sfield::Account, ACCOUNT_ID_SIZE, 1);
404
405 let _guard = setup_mock(mock);
406
407 assert!(u32::get_from_ledger_obj(slot, sfield::Flags).is_ok());
409 assert!(u64::get_from_ledger_obj(slot, sfield::Balance).is_ok());
410 assert!(AccountID::get_from_ledger_obj(slot, sfield::Account).is_ok());
411 }
412
413 #[test]
414 fn test_field_getter_optional_with_slot() {
415 let mut mock = MockHostBindings::new();
416 let slot = 0;
417
418 expect_ledger_field(&mut mock, slot, sfield::Flags, 4, 1);
419
420 let _guard = setup_mock(mock);
421
422 let result = u32::get_from_ledger_obj_optional(slot, sfield::Flags);
424 assert!(result.is_ok());
425 assert!(result.unwrap().is_some());
426 }
427
428 #[test]
433 fn test_current_ledger_object_module() {
434 let mut mock = MockHostBindings::new();
435
436 expect_current_field(&mut mock, sfield::Flags, 4, 2);
437 expect_current_field(&mut mock, sfield::Account, ACCOUNT_ID_SIZE, 1);
438
439 let _guard = setup_mock(mock);
440
441 assert!(current_ledger_object::get_field::<u32>(sfield::Flags).is_ok());
443 assert!(current_ledger_object::get_field::<AccountID>(sfield::Account).is_ok());
444
445 let result = current_ledger_object::get_field_optional::<u32>(sfield::Flags);
446 assert!(result.is_ok());
447 assert!(result.unwrap().is_some());
448 }
449
450 #[test]
451 fn test_ledger_object_module() {
452 let mut mock = MockHostBindings::new();
453 let slot = 0;
454
455 expect_ledger_field(&mut mock, slot, sfield::LedgerEntryType, 2, 1);
456 expect_ledger_field(&mut mock, slot, sfield::Flags, 4, 2);
457 expect_ledger_field(&mut mock, slot, sfield::Balance, 8, 1);
458 expect_ledger_field(&mut mock, slot, sfield::Account, ACCOUNT_ID_SIZE, 1);
459 expect_ledger_field(&mut mock, slot, sfield::Amount, 48, 1);
460 expect_ledger_field(&mut mock, slot, sfield::EmailHash, HASH128_SIZE, 1);
461 expect_ledger_field(&mut mock, slot, sfield::PreviousTxnID, HASH256_SIZE, 1);
462 expect_ledger_field(&mut mock, slot, sfield::PublicKey, 33, 1);
463
464 let _guard = setup_mock(mock);
465
466 assert!(ledger_object::get_field::<u16>(slot, sfield::LedgerEntryType).is_ok());
468 assert!(ledger_object::get_field::<u32>(slot, sfield::Flags).is_ok());
469 assert!(ledger_object::get_field::<u64>(slot, sfield::Balance).is_ok());
470 assert!(ledger_object::get_field::<AccountID>(slot, sfield::Account).is_ok());
471 assert!(ledger_object::get_field::<Amount>(slot, sfield::Amount).is_ok());
472 assert!(ledger_object::get_field::<Hash128>(slot, sfield::EmailHash).is_ok());
473 assert!(ledger_object::get_field::<Hash256>(slot, sfield::PreviousTxnID).is_ok());
474 assert!(ledger_object::get_field::<Blob<33>>(slot, sfield::PublicKey).is_ok());
475
476 let result = ledger_object::get_field_optional::<u32>(slot, sfield::Flags);
477 assert!(result.is_ok());
478 assert!(result.unwrap().is_some());
479 }
480
481 #[test]
486 fn test_type_inference() {
487 let mut mock = MockHostBindings::new();
488 let slot = 0;
489
490 expect_ledger_field(&mut mock, slot, sfield::Balance, 8, 1);
491 expect_ledger_field(&mut mock, slot, sfield::Account, ACCOUNT_ID_SIZE, 1);
492 expect_ledger_field(&mut mock, slot, sfield::Sequence, 4, 1);
493 expect_ledger_field(&mut mock, slot, sfield::Flags, 4, 1);
494
495 let _guard = setup_mock(mock);
496
497 let _balance = get_field::<u64>(slot, sfield::Balance);
499 let _account = get_field::<AccountID>(slot, sfield::Account);
500
501 let _sequence: Result<u32> = get_field(slot, sfield::Sequence);
503 let _flags: Result<u32> = get_field(slot, sfield::Flags);
504 }
505
506 #[test]
511 fn test_type_sizes() {
512 let mut mock = MockHostBindings::new();
513
514 expect_current_field(&mut mock, sfield::EmailHash, HASH128_SIZE, 1);
515 expect_current_field(&mut mock, sfield::PreviousTxnID, HASH256_SIZE, 1);
516 expect_current_field(&mut mock, sfield::Account, ACCOUNT_ID_SIZE, 1);
517 expect_current_field(&mut mock, sfield::PublicKey, PUBLIC_KEY_BUFFER_SIZE, 1);
518
519 let _guard = setup_mock(mock);
520
521 let hash128 = Hash128::get_from_current_ledger_obj(sfield::EmailHash).unwrap();
523 assert_eq!(hash128.as_bytes().len(), HASH128_SIZE);
524
525 let hash256 = Hash256::get_from_current_ledger_obj(sfield::PreviousTxnID).unwrap();
526 assert_eq!(hash256.as_bytes().len(), HASH256_SIZE);
527
528 let account = AccountID::get_from_current_ledger_obj(sfield::Account).unwrap();
529 assert_eq!(account.0.len(), ACCOUNT_ID_SIZE);
530
531 let blob: Blob<{ PUBLIC_KEY_BUFFER_SIZE }> =
532 Blob::get_from_current_ledger_obj(sfield::PublicKey).unwrap();
533 assert_eq!(blob.len, PUBLIC_KEY_BUFFER_SIZE);
535 assert_eq!(blob.data.len(), PUBLIC_KEY_BUFFER_SIZE);
536 }
537 }
538}