wasm_host_simulator/
data_provider.rs

1use crate::decoding::{AccountId, Decodable, decode, decode_amount_json, decode_issue_json};
2use crate::hashing::Hash256;
3use crate::mock_data::{DataSource, Keylet, MockData};
4use std::ffi::c_void;
5
6const LOCATOR_BUFFER_SIZE: usize = 64;
7const NUM_SLOTS: usize = 256;
8pub const XRPL_CONTRACT_DATA_SIZE: usize = 4096;
9
10#[allow(dead_code)]
11pub enum HostError {
12    InternalError = -1,
13    FieldNotFound = -2,
14    BufferTooSmall = -3,
15    NoArray = -4,
16    NotLeafField = -5,
17    LocatorMalformed = -6,
18    SlotOutRange = -7,
19    NoFreeSlots = -8,
20    EmptySlot = -9,
21    LedgerObjNotFound = -10,
22    InvalidDecoding = -11,
23    DataFieldTooLarge = -12,
24    PointerOutOfBound = -13, // WAMR VM checks, so we don't need to
25    NoMemoryExported = -14,  // We don't explicitly call WAMR memory functions.
26    InvalidParams = -15,
27    InvalidAccount = -16,
28    InvalidField = -17,
29    IndexOutOfBounds = -18,
30    InvalidFloatInput = -19,
31    InvalidFloatComputation = -20,
32}
33
34impl From<i64> for HostError {
35    fn from(value: i64) -> Self {
36        match value {
37            -1 => HostError::InternalError,
38            -2 => HostError::FieldNotFound,
39            -3 => HostError::BufferTooSmall,
40            -4 => HostError::NoArray,
41            -5 => HostError::NotLeafField,
42            -6 => HostError::LocatorMalformed,
43            -7 => HostError::SlotOutRange,
44            -8 => HostError::NoFreeSlots,
45            -9 => HostError::EmptySlot,
46            -10 => HostError::LedgerObjNotFound,
47            -11 => HostError::InvalidDecoding,
48            -12 => HostError::DataFieldTooLarge,
49            -13 => HostError::PointerOutOfBound,
50            -14 => HostError::NoMemoryExported,
51            -15 => HostError::InvalidParams,
52            -16 => HostError::InvalidAccount,
53            -17 => HostError::InvalidField,
54            -18 => HostError::IndexOutOfBounds,
55            _ => HostError::InternalError, // Default to InternalError for unknown error codes
56        }
57    }
58}
59
60/// Converts an error code to its string representation.
61///
62/// # Arguments
63///
64/// * `code` - An integer representing the error code
65///
66/// # Returns
67///
68/// Returns a string slice representing the name of the error code constant and its integer value.
69/// Returns "UNKNOWN_ERROR (code)" if the error code is not recognized.
70pub fn error_code_to_string(code: i64) -> &'static str {
71    // Convert the code to a HostError
72    let host_error: HostError = code.into();
73
74    // Match on the HostError
75    match host_error {
76        HostError::InternalError => "INTERNAL_ERROR (-1)",
77        HostError::FieldNotFound => "FIELD_NOT_FOUND (-2)",
78        HostError::BufferTooSmall => "BUFFER_TOO_SMALL (-3)",
79        HostError::NoArray => "NO_ARRAY (-4)",
80        HostError::NotLeafField => "NOT_LEAF_FIELD (-5)",
81        HostError::LocatorMalformed => "LOCATOR_MALFORMED (-6)",
82        HostError::SlotOutRange => "SLOT_OUT_RANGE (-7)",
83        HostError::NoFreeSlots => "SLOTS_FULL (-8)",
84        HostError::EmptySlot => "EMPTY_SLOT (-9)",
85        HostError::LedgerObjNotFound => "LEDGER_OBJ_NOT_FOUND (-10)",
86        HostError::InvalidDecoding => "DECODING_ERROR (-11)",
87        HostError::DataFieldTooLarge => "DATA_FIELD_TOO_LARGE (-12)",
88        HostError::PointerOutOfBound => "POINTER_OUT_OF_BOUND (-13)",
89        HostError::NoMemoryExported => "NO_MEMORY_EXPORTED (-14)",
90        HostError::InvalidParams => "INVALID_PARAMS (-15)",
91        HostError::InvalidAccount => "INVALID_ACCOUNT (-16)",
92        HostError::InvalidField => "INVALID_FIELD (-17)",
93        HostError::IndexOutOfBounds => "INDEX_OUT_OF_BOUNDS (-18)",
94        HostError::InvalidFloatInput => "INVALID_FLOAT_INPUT (-19)",
95        HostError::InvalidFloatComputation => "INVALID_FLOAT_COMPUTATION (-20)",
96    }
97}
98
99pub struct LocatorUnpacker {
100    buffer: Vec<u8>,
101    cur_buffer_index: usize,
102}
103
104impl LocatorUnpacker {
105    pub fn from_bytes(buffer: Vec<u8>) -> Option<LocatorUnpacker> {
106        let packed_bytes: usize = buffer.len();
107        if packed_bytes > LOCATOR_BUFFER_SIZE
108            || packed_bytes == 0
109            || !packed_bytes.is_multiple_of(4)
110        {
111            None
112        } else {
113            Some(LocatorUnpacker {
114                buffer,
115                cur_buffer_index: 0,
116            })
117        }
118    }
119
120    pub fn unpack(&mut self) -> Option<i32> {
121        if self.cur_buffer_index + 4 > self.buffer.len() {
122            return None;
123        }
124        let mut bytes: [u8; 4] = [0u8; 4];
125        bytes.copy_from_slice(&self.buffer[self.cur_buffer_index..self.cur_buffer_index + 4]);
126        self.cur_buffer_index += 4;
127        Some(i32::from_le_bytes(bytes))
128    }
129}
130
131pub fn unpack_locator(buffer: Vec<u8>) -> Result<Vec<i32>, HostError> {
132    let mut unpacker = LocatorUnpacker::from_bytes(buffer).ok_or(HostError::LocatorMalformed)?;
133
134    let mut result = vec![];
135    while let Some(slot) = unpacker.unpack() {
136        result.push(slot);
137    }
138    Ok(result)
139}
140
141use num_derive::FromPrimitive;
142#[derive(FromPrimitive, Debug)]
143pub enum RippledRoundingMode {
144    ToNearest = 0,
145    TowardsZero = 1,
146    Downward = 2,
147    Upward = 3,
148}
149
150pub struct DataProvider {
151    data_source: MockData,
152    next_slot: usize,
153    slots: [Keylet; NUM_SLOTS],
154    pub _rounding_mode: RippledRoundingMode,
155}
156
157impl DataProvider {
158    pub fn new(data_source: MockData) -> Self {
159        let slots: [Hash256; 256] = core::array::from_fn(|_| Hash256::default());
160        Self {
161            data_source,
162            next_slot: 1,
163            slots,
164            _rounding_mode: RippledRoundingMode::ToNearest,
165        }
166    }
167
168    pub fn slot_set(&mut self, keylet: Keylet, mut slot: usize) -> i32 {
169        if slot == 0 {
170            if self.next_slot >= NUM_SLOTS {
171                return HostError::NoFreeSlots as i32;
172            }
173            slot = self.next_slot;
174            self.next_slot += 1;
175        } else if slot >= NUM_SLOTS {
176            return HostError::SlotOutRange as i32;
177        }
178
179        if self.data_source.obj_exist(&keylet) {
180            self.slots[slot] = keylet;
181            slot as i32
182        } else {
183            HostError::LedgerObjNotFound as i32
184        }
185    }
186
187    pub fn slot_get(&self, slot: usize) -> Option<&Keylet> {
188        if slot == 0 || slot >= self.next_slot {
189            None
190        } else {
191            Some(&self.slots[slot])
192        }
193    }
194
195    pub fn get_field_value(
196        &self,
197        source: DataSource,
198        idx_fields: Vec<i32>,
199        buf_cap: usize,
200    ) -> (i32, Vec<u8>) {
201        assert!(!idx_fields.is_empty());
202        let (last_sfield, field_result) = match self.data_source.get_field_value(source, idx_fields)
203        {
204            Ok(v) => v,
205            Err(e) => return (e as i32, vec![]),
206        };
207
208        Self::fill_buf(
209            Some(field_result),
210            buf_cap,
211            Decodable::from_sfield(last_sfield),
212        )
213    }
214
215    pub fn get_array_len(&self, source: DataSource, idx_fields: Vec<i32>) -> i32 {
216        let (_, value) = match self.data_source.get_field_value(source, idx_fields) {
217            Ok(v) => v,
218            Err(e) => return e as i32,
219        };
220        if value.is_array() {
221            value.as_array().unwrap().len() as i32
222        } else {
223            HostError::NoArray as i32
224        }
225    }
226
227    pub fn get_ledger_sqn(&self) -> i32 {
228        match self.data_source.get_ledger_sqn() {
229            Some(value) => {
230                if let Some(num) = value.as_i64() {
231                    num as i32
232                } else {
233                    HostError::InvalidDecoding as i32
234                }
235            }
236            None => HostError::InternalError as i32,
237        }
238    }
239
240    pub fn get_parent_ledger_time(&self) -> i32 {
241        match self.data_source.get_parent_ledger_time() {
242            Some(value) => {
243                if let Some(num) = value.as_i64() {
244                    num as i32
245                } else {
246                    HostError::InvalidDecoding as i32
247                }
248            }
249            None => HostError::InternalError as i32,
250        }
251    }
252
253    pub fn get_parent_ledger_hash(&self, buf_cap: usize) -> (i32, Vec<u8>) {
254        let field_result = self.data_source.get_parent_ledger_hash();
255        Self::fill_buf(field_result, buf_cap, Decodable::UINT256)
256    }
257
258    pub fn get_nft_uri(
259        &self,
260        nft_id: &Hash256,
261        account_id: &AccountId,
262        buf_cap: usize,
263    ) -> (i32, Vec<u8>) {
264        let field_result = self.data_source.get_nft_uri(nft_id, account_id);
265        Self::fill_buf(field_result, buf_cap, Decodable::AS_IS)
266    }
267
268    pub fn set_current_ledger_obj_data(&mut self, data: Vec<u8>) {
269        self.data_source.set_current_ledger_obj_data(data);
270    }
271
272    fn fill_buf(
273        field_result: Option<&serde_json::Value>,
274        buf_cap: usize,
275        decodable: Decodable,
276    ) -> (i32, Vec<u8>) {
277        let mut buf = vec![0u8; buf_cap];
278        match field_result {
279            Some(value) => {
280                if decodable == Decodable::AMOUNT {
281                    match decode_amount_json(value.clone()) {
282                        None => (HostError::InvalidDecoding as i32, buf),
283                        Some(bytes) => {
284                            if bytes.len() > buf_cap {
285                                return (HostError::BufferTooSmall as i32, buf);
286                            }
287                            buf[..bytes.len()].copy_from_slice(&bytes);
288                            (bytes.len() as i32, buf)
289                        }
290                    }
291                } else if decodable == Decodable::ISSUE {
292                    match decode_issue_json(value.clone()) {
293                        None => (HostError::InvalidDecoding as i32, buf),
294                        Some(bytes) => {
295                            if bytes.len() > buf_cap {
296                                return (HostError::BufferTooSmall as i32, buf);
297                            }
298                            buf[..bytes.len()].copy_from_slice(&bytes);
299                            (bytes.len() as i32, buf)
300                        }
301                    }
302                } else {
303                    match value {
304                        serde_json::Value::Number(n) => {
305                            if n.is_i64() {
306                                let num = n.as_i64().unwrap();
307                                if buf_cap == 4 {
308                                    // Safe cast to i32
309                                    if num > u32::MAX as i64 || num < u32::MIN as i64 {
310                                        return (HostError::BufferTooSmall as i32, buf);
311                                    }
312                                    let bytes = (num as u32).to_le_bytes();
313                                    buf[..4].copy_from_slice(&bytes);
314                                    (4, buf)
315                                } else {
316                                    let bytes = num.to_le_bytes();
317                                    if bytes.len() > buf_cap {
318                                        return (HostError::BufferTooSmall as i32, buf);
319                                    }
320                                    buf[..bytes.len()].copy_from_slice(&bytes);
321                                    (bytes.len() as i32, buf)
322                                }
323                            } else if n.is_u64() {
324                                let num = n.as_u64().unwrap();
325                                if buf_cap == 4 {
326                                    // Safe cast to u32
327                                    if num > u32::MAX as u64 {
328                                        return (HostError::BufferTooSmall as i32, buf);
329                                    }
330                                    let bytes = (num as u32).to_le_bytes();
331                                    buf[..4].copy_from_slice(&bytes);
332                                    (4, buf)
333                                } else {
334                                    let bytes = num.to_le_bytes();
335                                    if bytes.len() > buf_cap {
336                                        return (HostError::BufferTooSmall as i32, buf);
337                                    }
338                                    buf[..bytes.len()].copy_from_slice(&bytes);
339                                    (bytes.len() as i32, buf)
340                                }
341                            } else if n.is_f64() {
342                                let s = n.as_f64().unwrap().to_string();
343                                let bytes = s.as_bytes();
344                                if bytes.len() > buf_cap {
345                                    return (HostError::BufferTooSmall as i32, buf);
346                                }
347                                buf[..bytes.len()].copy_from_slice(bytes);
348                                (bytes.len() as i32, buf)
349                            } else {
350                                (HostError::InternalError as i32, buf)
351                            }
352                        }
353                        serde_json::Value::String(s) => match decode(s, decodable) {
354                            None => (HostError::InvalidDecoding as i32, buf),
355                            Some(bytes) => {
356                                if bytes.len() > buf_cap {
357                                    return (HostError::BufferTooSmall as i32, buf);
358                                }
359                                buf[..bytes.len()].copy_from_slice(&bytes);
360                                (bytes.len() as i32, buf)
361                            }
362                        },
363                        serde_json::Value::Bool(b) => {
364                            if buf_cap == 0 {
365                                return (HostError::BufferTooSmall as i32, buf);
366                            }
367                            buf[0] = if *b { 1 } else { 0 };
368                            (1, buf)
369                        }
370                        // be explicit about the cases we don't support
371                        serde_json::Value::Null => (HostError::NotLeafField as i32, buf),
372                        serde_json::Value::Array(_) => (HostError::NotLeafField as i32, buf),
373                        serde_json::Value::Object(_) => (HostError::NotLeafField as i32, buf),
374                    }
375                }
376            }
377            None => (HostError::FieldNotFound as i32, buf),
378        }
379    }
380    #[allow(unused)]
381    pub fn as_ptr(&mut self) -> *mut c_void {
382        self as *mut _ as *mut c_void
383    }
384}