1use crate::host::error_codes::match_result_code;
2
3use crate::core::types::account_id::AccountID;
4use crate::core::types::amount::Amount;
5use crate::host;
6use crate::host::Result;
7
8#[derive(Clone, Copy)]
10pub enum DataRepr {
11 AsUTF8 = 0,
13 AsHex = 1,
15}
16
17#[inline(always)] pub fn trace(msg: &str) -> Result<i32> {
29 let empty_data: &[u8] = &[];
32
33 let result_code = unsafe {
34 host::trace(
35 msg.as_ptr(),
36 msg.len(),
37 empty_data.as_ptr(),
38 0usize,
39 DataRepr::AsUTF8 as _,
40 )
41 };
42
43 match_result_code(result_code, || result_code)
44}
45
46#[inline(always)] pub fn trace_data(msg: &str, data: &[u8], data_repr: DataRepr) -> Result<i32> {
58 let result_code = unsafe {
59 let data_ptr = data.as_ptr();
60 let data_len = data.len();
61 host::trace(msg.as_ptr(), msg.len(), data_ptr, data_len, data_repr as _)
62 };
63
64 match_result_code(result_code, || result_code)
65}
66
67#[inline(always)]
79pub fn trace_num(msg: &str, number: i64) -> Result<i32> {
80 let result_code = unsafe { host::trace_num(msg.as_ptr(), msg.len(), number) };
81 match_result_code(result_code, || result_code)
82}
83
84#[inline(always)]
85pub fn trace_account_buf(msg: &str, account_id: &[u8; 20]) -> Result<i32> {
86 let result_code = unsafe {
87 host::trace_account(
88 msg.as_ptr(),
89 msg.len(),
90 account_id.as_ptr(),
91 account_id.len(),
92 )
93 };
94 match_result_code(result_code, || result_code)
95}
96
97#[inline(always)]
98pub fn trace_account(msg: &str, account_id: &AccountID) -> Result<i32> {
99 let result_code = unsafe {
100 host::trace_account(
101 msg.as_ptr(),
102 msg.len(),
103 account_id.0.as_ptr(),
104 account_id.0.len(),
105 )
106 };
107 match_result_code(result_code, || result_code)
108}
109
110#[inline(always)]
111pub fn trace_amount(msg: &str, amount: &Amount) -> Result<i32> {
112 let (amount_bytes, len) = amount.to_stamount_bytes();
114
115 let result_code =
116 unsafe { host::trace_amount(msg.as_ptr(), msg.len(), amount_bytes.as_ptr(), len) };
117
118 match_result_code(result_code, || result_code)
119}
120
121#[inline(always)]
123pub fn trace_float(msg: &str, f: &[u8; 8]) -> Result<i32> {
124 let result_code = unsafe { host::trace_opaque_float(msg.as_ptr(), msg.len(), f.as_ptr(), 8) };
125 match_result_code(result_code, || result_code)
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use crate::core::types::amount::Amount;
132 use crate::host::host_bindings_trait::MockHostBindings;
133 use crate::host::setup_mock;
134 use mockall::predicate::always;
135
136 #[test]
137 fn test_trace_amount_xrp() {
138 let mut mock = MockHostBindings::new();
139
140 let message = "Test XRP amount";
141
142 mock.expect_trace_amount()
144 .with(always(), always(), always(), always())
145 .returning(move |_, msg_len, _, _| msg_len as i32);
146
147 let _guard = setup_mock(mock);
148
149 let amount = Amount::XRP {
151 num_drops: 1_000_000,
152 };
153
154 let result = trace_amount(message, &amount);
156
157 assert!(result.is_ok());
159 assert_eq!(result.unwrap(), message.len() as i32);
160 }
161
162 #[test]
163 fn test_trace_amount_mpt() {
164 let mut mock = MockHostBindings::new();
165
166 let message = "Test MPT amount";
167
168 mock.expect_trace_amount()
170 .with(always(), always(), always(), always())
171 .returning(move |_, msg_len, _, _| msg_len as i32);
172
173 let _guard = setup_mock(mock);
174
175 use crate::core::types::account_id::AccountID;
177 use crate::core::types::mpt_id::MptId;
178
179 const VALUE: u64 = 500_000;
180 const SEQUENCE_NUM: u32 = 12345;
181 const ISSUER_BYTES: [u8; 20] = [1u8; 20];
182
183 let issuer = AccountID::from(ISSUER_BYTES);
184 let mpt_id = MptId::new(SEQUENCE_NUM, issuer);
185 let amount = Amount::MPT {
186 num_units: VALUE,
187 is_positive: true,
188 mpt_id,
189 };
190
191 let result = trace_amount(message, &amount);
193
194 assert!(result.is_ok());
196 assert_eq!(result.unwrap(), message.len() as i32);
197 }
198
199 #[test]
200 fn test_trace_amount_iou() {
201 let mut mock = MockHostBindings::new();
202
203 let message = "Test IOU amount";
204
205 mock.expect_trace_amount()
207 .with(always(), always(), always(), always())
208 .returning(move |_, msg_len, _, _| msg_len as i32);
209
210 let _guard = setup_mock(mock);
211
212 use crate::core::types::account_id::AccountID;
214 use crate::core::types::currency::Currency;
215 use crate::core::types::opaque_float::OpaqueFloat;
216
217 let currency_bytes = [2u8; 20];
218 let issuer_bytes = [3u8; 20];
219 let amount_bytes = [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39]; let currency = Currency::from(currency_bytes);
222 let issuer = AccountID::from(issuer_bytes);
223 let amount = OpaqueFloat(amount_bytes);
224
225 let amount = Amount::IOU {
226 amount,
227 issuer,
228 currency,
229 };
230
231 let result = trace_amount(message, &amount);
233
234 assert!(result.is_ok());
236 assert_eq!(result.unwrap(), message.len() as i32);
237 }
238
239 #[test]
240 fn test_trace_amount_negative_xrp() {
241 let mut mock = MockHostBindings::new();
242
243 let message = "Test negative XRP amount";
244
245 mock.expect_trace_amount()
247 .with(always(), always(), always(), always())
248 .returning(move |_, msg_len, _, _| msg_len as i32);
249
250 let _guard = setup_mock(mock);
251
252 let amount = Amount::XRP {
254 num_drops: -1_000_000,
255 };
256
257 let result = trace_amount(message, &amount);
259
260 assert!(result.is_ok());
262 assert_eq!(result.unwrap(), message.len() as i32);
263 }
264
265 #[test]
266 fn test_trace_bytes_format() {
267 let xrp_amount = Amount::XRP {
269 num_drops: 1_000_000,
270 };
271 let (_bytes, len) = xrp_amount.to_stamount_bytes();
272 assert_eq!(len, 48); let fee_amount = Amount::XRP { num_drops: 10 };
276 let (bytes, len) = fee_amount.to_stamount_bytes();
277 assert_eq!(len, 48); let expected_bytes = [64, 0, 0, 0, 0, 0, 0, 10];
282 assert_eq!(&bytes[0..8], &expected_bytes);
283
284 use crate::core::types::account_id::AccountID;
286 use crate::core::types::currency::Currency;
287 use crate::core::types::opaque_float::OpaqueFloat;
288
289 let currency_bytes = [2u8; 20];
290 let issuer_bytes = [3u8; 20];
291 let amount_bytes = [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39];
292
293 let iou_amount = Amount::IOU {
294 amount: OpaqueFloat(amount_bytes),
295 issuer: AccountID::from(issuer_bytes),
296 currency: Currency::from(currency_bytes),
297 };
298 let (bytes, len) = iou_amount.to_stamount_bytes();
299 assert_eq!(len, 48); assert_eq!(&bytes[0..8], &amount_bytes); use crate::core::types::mpt_id::MptId;
304
305 const VALUE: u64 = 500_000;
306 const SEQUENCE_NUM: u32 = 12345;
307 const ISSUER_BYTES: [u8; 20] = [1u8; 20];
308
309 let issuer = AccountID::from(ISSUER_BYTES);
310 let mpt_id = MptId::new(SEQUENCE_NUM, issuer);
311 let mpt_amount = Amount::MPT {
312 num_units: VALUE,
313 is_positive: true,
314 mpt_id,
315 };
316 let (bytes, len) = mpt_amount.to_stamount_bytes();
317 assert_eq!(len, 48); assert_eq!(bytes[0], 0b_0110_0000); assert_eq!(&bytes[1..9], &VALUE.to_be_bytes()); }
321}