xrpl_wasm_stdlib/core/ledger_objects/
account_root.rs1use crate::core::keylets::account_keylet;
2use crate::core::ledger_objects::traits::{AccountFields, LedgerObjectCommonFields};
3use crate::core::types::account_id::AccountID;
4use crate::core::types::amount::Amount;
5use crate::host;
6use host::Error;
7
8#[derive(Debug, Clone, Copy, Eq, PartialEq)]
9pub struct AccountRoot {
10 pub slot_num: i32,
11}
12
13impl LedgerObjectCommonFields for AccountRoot {
14 fn get_slot_num(&self) -> i32 {
15 self.slot_num
16 }
17}
18
19impl AccountFields for AccountRoot {}
20
21pub fn get_account_balance(account_id: &AccountID) -> host::Result<Option<Amount>> {
22 let account_keylet = match account_keylet(account_id) {
24 host::Result::Ok(keylet) => keylet,
25 host::Result::Err(e) => return host::Result::Err(e),
26 };
27
28 let slot = unsafe { host::cache_ledger_obj(account_keylet.as_ptr(), account_keylet.len(), 0) };
30 if slot < 0 {
31 return host::Result::Err(Error::from_code(slot));
32 }
33
34 let account = AccountRoot { slot_num: slot };
37 account.balance()
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::core::keylets::XRPL_KEYLET_SIZE;
44 use crate::core::types::amount::AMOUNT_SIZE;
45 use crate::host::error_codes::INTERNAL_ERROR;
46 use crate::host::host_bindings_trait::MockHostBindings;
47 use crate::host::setup_mock;
48 use crate::sfield;
49 use mockall::predicate::{always, eq};
50
51 fn mock_account_keylet_success(mock: &mut MockHostBindings) {
56 mock.expect_account_keylet()
57 .times(1)
58 .returning(|_, _, out_buff_ptr, out_buff_len| {
59 assert_eq!(out_buff_len, XRPL_KEYLET_SIZE);
60 unsafe {
61 for i in 0..XRPL_KEYLET_SIZE {
62 *out_buff_ptr.add(i) = 0xCC;
63 }
64 }
65 XRPL_KEYLET_SIZE as i32
66 });
67 }
68
69 #[test]
70 fn test_get_account_balance_success() {
71 let mut mock = MockHostBindings::new();
72 let slot = 5;
73 let balance_field_code: i32 = sfield::Balance.into();
74
75 mock_account_keylet_success(&mut mock);
76
77 mock.expect_cache_ledger_obj()
79 .times(1)
80 .returning(move |_, _, _| slot);
81
82 mock.expect_get_ledger_obj_field()
87 .with(eq(slot), eq(balance_field_code), always(), eq(AMOUNT_SIZE))
88 .times(1)
89 .returning(move |_, _, buf, buf_size| {
90 unsafe { core::ptr::write_bytes(buf, 0, buf_size) };
91 AMOUNT_SIZE as i32
92 });
93
94 let _guard = setup_mock(mock);
95
96 let account_id = AccountID::from([0xBB; 20]);
97 let result = get_account_balance(&account_id);
98 assert!(result.is_ok());
99 assert!(result.unwrap().is_some());
100 }
101
102 #[test]
103 fn test_get_account_balance_keylet_error() {
104 let mut mock = MockHostBindings::new();
105
106 mock.expect_account_keylet()
108 .times(1)
109 .returning(|_, _, _, _| INTERNAL_ERROR);
110
111 let _guard = setup_mock(mock);
112
113 let account_id = AccountID::from([0xBB; 20]);
114 let result = get_account_balance(&account_id);
115 assert!(result.is_err());
116 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
117 }
118
119 #[test]
120 fn test_get_account_balance_cache_error() {
121 let mut mock = MockHostBindings::new();
122
123 mock_account_keylet_success(&mut mock);
124
125 mock.expect_cache_ledger_obj()
127 .times(1)
128 .returning(|_, _, _| INTERNAL_ERROR);
129
130 let _guard = setup_mock(mock);
131
132 let account_id = AccountID::from([0xBB; 20]);
133 let result = get_account_balance(&account_id);
134 assert!(result.is_err());
135 assert_eq!(result.err().unwrap().code(), INTERNAL_ERROR);
136 }
137}