Skip to main content

rootchain_std/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5pub mod error;
6pub mod rrc721;
7pub mod traits;
8pub mod types;
9
10pub use rootchain_core::types::{Address, Hash};
11pub use rootchain_macros::rootchain_contract;
12pub use traits::{Ownable, RRC20, RRC721};
13
14// Host function declarations
15#[cfg(not(feature = "test-utils"))]
16extern "C" {
17    pub fn state_get(
18        key_ptr: *const u8,
19        key_len: usize,
20        value_ptr: *mut u8,
21        value_len: usize,
22    ) -> i32;
23    pub fn state_set(
24        key_ptr: *const u8,
25        key_len: usize,
26        value_ptr: *const u8,
27        value_len: usize,
28    ) -> i32;
29    pub fn get_caller(addr_ptr: *mut u8) -> i32;
30    pub fn host_input_len() -> u32;
31    pub fn host_read_input(ptr: *mut u8) -> u32;
32    pub fn host_write_output(ptr: *const u8, len: usize) -> i32;
33    pub fn host_log(ptr: *const u8, len: usize, level: u32) -> i32;
34    pub fn host_log_event(
35        topics_ptr: *const u8,
36        topics_count: usize,
37        data_ptr: *const u8,
38        data_len: usize,
39    ) -> i32;
40    pub fn host_set_metadata(ptr: *const u8, len: usize) -> i32;
41    pub fn host_hash(ptr: *const u8, len: usize, out_ptr: *mut u8) -> i32;
42}
43
44#[cfg(feature = "test-utils")]
45pub use mock::*;
46
47#[cfg(feature = "test-utils")]
48mod mock {
49    extern crate std;
50    use core::cell::RefCell;
51    use std::collections::HashMap;
52    use std::vec::Vec;
53
54    std::thread_local! {
55        static STATE: RefCell<HashMap<Vec<u8>, Vec<u8>>> = RefCell::new(HashMap::new());
56        static CALLER: RefCell<[u8; 32]> = const { RefCell::new([0u8; 32]) };
57    }
58
59    /// # Safety
60    /// This function dereferences raw pointers. The caller must ensure that `key_ptr` and `value_ptr`
61    /// are valid pointers to memory of at least `key_len` and `value_len` bytes respectively.
62    pub unsafe fn state_get(
63        key_ptr: *const u8,
64        key_len: usize,
65        value_ptr: *mut u8,
66        value_len: usize,
67    ) -> i32 {
68        let key = core::slice::from_raw_parts(key_ptr, key_len).to_vec();
69        STATE.with(|s| {
70            if let Some(val) = s.borrow().get(&key) {
71                let len = core::cmp::min(val.len(), value_len);
72                core::ptr::copy_nonoverlapping(val.as_ptr(), value_ptr, len);
73                0
74            } else {
75                -1
76            }
77        })
78    }
79
80    /// # Safety
81    /// This function dereferences raw pointers. The caller must ensure that `key_ptr` and `value_ptr`
82    /// are valid pointers to memory of at least `key_len` and `value_len` bytes respectively.
83    pub unsafe fn state_set(
84        key_ptr: *const u8,
85        key_len: usize,
86        value_ptr: *const u8,
87        value_len: usize,
88    ) -> i32 {
89        let key = core::slice::from_raw_parts(key_ptr, key_len).to_vec();
90        let val = core::slice::from_raw_parts(value_ptr, value_len).to_vec();
91        STATE.with(|s| {
92            s.borrow_mut().insert(key, val);
93            0
94        })
95    }
96
97    /// # Safety
98    /// This function dereferences raw pointers. The caller must ensure that `addr_ptr`
99    /// is a valid pointer to memory of at least 32 bytes.
100    pub unsafe fn get_caller(addr_ptr: *mut u8) -> i32 {
101        CALLER.with(|c| {
102            core::ptr::copy_nonoverlapping(c.borrow().as_ptr(), addr_ptr, 32);
103            0
104        })
105    }
106
107    /// # Safety
108    /// Caller must ensure `_ptr` points to a buffer of sufficient size to hold the input data.
109    pub unsafe fn host_input_len() -> u32 {
110        0
111    }
112
113    /// # Safety
114    /// Caller must ensure `_ptr` points to a buffer of sufficient size to hold the input data.
115    pub unsafe fn host_read_input(_ptr: *mut u8) -> u32 {
116        0
117    }
118
119    /// # Safety
120    /// Caller must ensure `_ptr` points to valid memory of at least `_len` bytes.
121    pub unsafe fn host_write_output(_ptr: *const u8, _len: usize) -> i32 {
122        0
123    }
124
125    /// # Safety
126    /// Caller must ensure `_ptr` points to valid UTF-8 memory of at least `_len` bytes.
127    pub unsafe fn host_log(_ptr: *const u8, _len: usize, _level: u32) -> i32 {
128        0
129    }
130
131    /// # Safety
132    /// This function is a mock implementation for testing.
133    pub unsafe fn host_log_event(
134        _topics_ptr: *const u8,
135        _topics_count: usize,
136        _data_ptr: *const u8,
137        _data_len: usize,
138    ) -> i32 {
139        0
140    }
141
142    /// # Safety
143    /// This function is a mock implementation for testing.
144    pub unsafe fn host_set_metadata(_ptr: *const u8, _len: usize) -> i32 {
145        0
146    }
147
148    /// # Safety
149    /// This function is a mock implementation for testing.
150    pub unsafe fn host_hash(_ptr: *const u8, _len: usize, _out_ptr: *mut u8) -> i32 {
151        0
152    }
153
154    pub fn set_mock_caller(addr: [u8; 32]) {
155        CALLER.with(|c| *c.borrow_mut() = addr);
156    }
157}
158
159#[cfg(all(not(feature = "std"), target_arch = "wasm32"))]
160#[global_allocator]
161static ALLOC: lol_alloc::AssumeSingleThreaded<lol_alloc::LeakingPageAllocator> =
162    unsafe { lol_alloc::AssumeSingleThreaded::new(lol_alloc::LeakingPageAllocator) };
163
164#[cfg(all(not(feature = "std"), target_arch = "wasm32"))]
165#[panic_handler]
166fn panic(_info: &core::panic::PanicInfo) -> ! {
167    loop {}
168}
169
170pub fn read_input() -> alloc::vec::Vec<u8> {
171    #[cfg(not(feature = "test-utils"))]
172    {
173        let len = unsafe { host_input_len() } as usize;
174        let mut buf = alloc::vec::Vec::with_capacity(len);
175        buf.resize(len, 0);
176        unsafe { host_read_input(buf.as_mut_ptr()) };
177        buf
178    }
179    #[cfg(feature = "test-utils")]
180    {
181        alloc::vec::Vec::new()
182    }
183}
184
185pub fn hash_bytes(data: &[u8]) -> Hash {
186    let mut hash = [0u8; 32];
187    unsafe { host_hash(data.as_ptr(), data.len(), hash.as_mut_ptr()) };
188    Hash(hash)
189}
190
191pub fn write_output(data: &[u8]) {
192    unsafe { host_write_output(data.as_ptr(), data.len()) };
193}
194
195pub fn log(msg: &str, level: u32) {
196    unsafe { host_log(msg.as_ptr(), msg.len(), level) };
197}
198
199pub fn log_event(topics: &[Hash], data: &[u8]) {
200    unsafe {
201        host_log_event(
202            topics.as_ptr() as *const u8,
203            topics.len(),
204            data.as_ptr(),
205            data.len(),
206        )
207    };
208}
209
210pub fn set_metadata(metadata: &[u8]) {
211    unsafe { host_set_metadata(metadata.as_ptr(), metadata.len()) };
212}
213
214#[macro_export]
215macro_rules! log_event {
216    ($topic:expr, $data:expr) => {
217        $crate::log_event(&[$topic], &$data);
218    };
219    ($topics:expr, $data:expr) => {
220        $crate::log_event(&$topics, &$data);
221    };
222}