Skip to main content

vrs_core_sdk/
storage.rs

1//! Storage module provides a set of functions to interact with the kv storage.
2//! Any data stored in the kv storage will be synchronized across all nodes in the subnet.
3//! The nucleus will automatically update the state root after each modification and then
4//! submit to Verisense chain.
5//!
6//! The `put` and `del` can only be called in the post functions. Otherwise, it will case panic.
7
8use crate::{error::RuntimeError, CallResult};
9use codec::Decode;
10
11#[link(wasm_import_module = "env")]
12extern "C" {
13    fn storage_put(
14        key_ptr: *const u8,
15        key_len: i32,
16        value_ptr: *const u8,
17        value_len: i32,
18        return_ptr: *mut u8,
19    ) -> i32;
20
21    fn storage_del(key_ptr: *const u8, key_len: i32, return_ptr: *mut u8) -> i32;
22
23    fn storage_get(k_ptr: *const u8, k_len: i32, return_ptr: *mut u8, v_offset: i32) -> i32;
24
25    fn storage_get_prefix(
26        k_ptr: *const u8,
27        k_len: i32,
28        direction: i32,
29        return_ptr: *mut u8,
30        v_offset: i32,
31    ) -> i32;
32
33    fn storage_get_range(
34        k_ptr: *const u8,
35        k_len: i32,
36        direction: i32,
37        limit: i32,
38        return_ptr: *mut u8,
39        v_offset: i32,
40    ) -> i32;
41
42    fn storage_del_range(
43        s0_ptr: *const u8,
44        s0_len: i32,
45        s1_ptr: *const u8,
46        s1_len: i32,
47        return_ptr: *mut u8,
48    ) -> i32;
49}
50
51/// Put a key-value pair into the kvdb.
52pub fn put(key: impl AsRef<[u8]>, value: impl AsRef<[u8]>) -> CallResult<()> {
53    let key = key.as_ref();
54    let value = value.as_ref();
55    assert!(key.len() <= i32::MAX as usize);
56    assert!(value.len() <= i32::MAX as usize);
57    let mut buf = crate::allocate_buffer();
58    let status = unsafe {
59        storage_put(
60            key.as_ptr(),
61            key.len() as i32,
62            value.as_ptr(),
63            value.len() as i32,
64            buf.as_mut_ptr(),
65        )
66    };
67    assert!(status == crate::NO_MORE_DATA);
68    CallResult::<()>::decode(&mut &buf[..]).map_err(|_| RuntimeError::DecodeReturnValueError)?
69}
70
71/// Delete a key-value pair from the kvdb.
72pub fn del(key: impl AsRef<[u8]>) -> CallResult<()> {
73    let key = key.as_ref();
74    assert!(key.len() <= i32::MAX as usize);
75    let mut buf = crate::allocate_buffer();
76    let status = unsafe { storage_del(key.as_ptr(), key.len() as i32, buf.as_mut_ptr()) };
77    assert!(status == crate::NO_MORE_DATA);
78    CallResult::<()>::decode(&mut &buf[..]).map_err(|_| RuntimeError::DecodeReturnValueError)?
79}
80
81/// Get a value from the kvdb with the key.
82pub fn get(key: impl AsRef<[u8]>) -> CallResult<Option<Vec<u8>>> {
83    let key = key.as_ref();
84    assert!(key.len() <= i32::MAX as usize);
85    let mut buf = crate::allocate_buffer();
86    let mut val = vec![];
87    loop {
88        let status = unsafe {
89            storage_get(
90                key.as_ptr(),
91                key.len() as i32,
92                buf.as_mut_ptr(),
93                val.len() as i32,
94            )
95        };
96        val.extend_from_slice(&buf);
97        if status == crate::NO_MORE_DATA {
98            break;
99        }
100    }
101    CallResult::<Option<Vec<u8>>>::decode(&mut &val[..])
102        .map_err(|_| RuntimeError::DecodeReturnValueError)?
103}
104
105/// The direction of the search
106#[derive(Clone, Copy, Debug, Eq, PartialEq)]
107pub enum Direction {
108    Forward,
109    Reverse,
110}
111
112impl Into<i32> for Direction {
113    fn into(self) -> i32 {
114        match self {
115            Direction::Forward => 0,
116            Direction::Reverse => 1,
117        }
118    }
119}
120
121impl From<i32> for Direction {
122    fn from(v: i32) -> Self {
123        match v {
124            0 => Direction::Forward,
125            1 => Direction::Reverse,
126            _ => unreachable!(),
127        }
128    }
129}
130
131/// Get a batch of entries from the databass with "start_key" and direction , the limit maximum is 1000
132pub fn get_range(
133    start_key: impl AsRef<[u8]>,
134    direction: Direction,
135    limit: usize,
136) -> CallResult<Vec<(Vec<u8>, Vec<u8>)>> {
137    let start = start_key.as_ref();
138    assert!(start.len() <= i32::MAX as usize);
139    assert!(limit <= 1000);
140    let mut buf = crate::allocate_buffer();
141    let mut val = vec![];
142    loop {
143        let status = unsafe {
144            storage_get_range(
145                start.as_ptr(),
146                start.len() as i32,
147                direction.into(),
148                limit as i32,
149                buf.as_mut_ptr(),
150                val.len() as i32,
151            )
152        };
153        val.extend_from_slice(&buf);
154        if status == crate::NO_MORE_DATA {
155            break;
156        }
157    }
158    CallResult::<Vec<(Vec<u8>, Vec<u8>)>>::decode(&mut &val[..])
159        .map_err(|_| RuntimeError::DecodeReturnValueError)?
160}
161
162/// Search a key-value with a prefix and direction
163///
164/// # Examples
165///
166///  ```
167///  use vrs_core_sdk::storage::{search, Direction};
168///
169///  pub fn search_blog_id() {
170///     let key = [&b"blog:"[..], &0u64.to_be_bytes()[..]].concat();
171///     let first_blog = search(&key, Direction::Forward).unwrap();
172///     let key = [&b"blog:"[..], &u64::MAX.to_be_bytes()[..]].concat();
173///     let last_blog = search(&key, Direction::Reverse).unwrap();
174///     assert!(first_blog.is_some());
175///     assert!(last_blog.is_some());
176///  }
177///  ```
178pub fn search(
179    key_prefix: impl AsRef<[u8]>,
180    direction: Direction,
181) -> CallResult<Option<(Vec<u8>, Vec<u8>)>> {
182    let key = key_prefix.as_ref();
183    assert!(key.len() <= i32::MAX as usize);
184    let mut buf = crate::allocate_buffer();
185    let mut val = vec![];
186    loop {
187        let status = unsafe {
188            storage_get_prefix(
189                key.as_ptr(),
190                key.len() as i32,
191                direction.into(),
192                buf.as_mut_ptr(),
193                val.len() as i32,
194            )
195        };
196        val.extend_from_slice(&buf);
197        if status == crate::NO_MORE_DATA {
198            break;
199        }
200    }
201    CallResult::<Option<(Vec<u8>, Vec<u8>)>>::decode(&mut &val[..])
202        .map_err(|_| RuntimeError::DecodeReturnValueError)?
203}
204
205/// Removes the database entries in the range [start_key, end_key)
206pub fn delete_range(start_key: impl AsRef<[u8]>, end_key: impl AsRef<[u8]>) -> CallResult<()> {
207    let start = start_key.as_ref();
208    let end = end_key.as_ref();
209    assert!(start.len() <= i32::MAX as usize);
210    assert!(end.len() <= i32::MAX as usize);
211    let mut buf = crate::allocate_buffer();
212    let status = unsafe {
213        storage_del_range(
214            start.as_ptr(),
215            start.len() as i32,
216            end.as_ptr(),
217            end.len() as i32,
218            buf.as_mut_ptr(),
219        )
220    };
221    assert!(status == crate::NO_MORE_DATA);
222    CallResult::<()>::decode(&mut &buf[..]).map_err(|_| RuntimeError::DecodeReturnValueError)?
223}