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