bobcat_entry/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6#[cfg(feature = "alloc")]
7use alloc::vec::Vec;
8
9pub use bobcat_maths::U;
10
11type Address = [u8; 20];
12
13pub use bobcat_cd::read_words;
14
15#[cfg(target_arch = "wasm32")]
16mod impls {
17    #[link(wasm_import_module = "vm_hooks")]
18    unsafe extern "C" {
19        #[allow(unused)]
20        pub(crate) fn pay_for_memory_grow(pages: u16);
21        pub(crate) fn write_result(d: *const u8, l: usize);
22        pub(crate) fn read_args(out: *mut u8);
23        pub(crate) fn msg_sender(addr: *mut u8);
24        pub(crate) fn contract_address(addr: *mut u8);
25        pub(crate) fn msg_value(value: *mut u8);
26        pub fn chain_id() -> u64;
27        pub(crate) fn account_codehash(address: *const u8, dest: *mut u8);
28        pub(crate) fn block_timestamp() -> u64;
29    }
30}
31
32#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
33pub mod entry_host {
34    use super::{Address, U};
35
36    use core::{ptr::copy_nonoverlapping, slice::from_raw_parts};
37
38    use std::cell::RefCell;
39
40    thread_local! {
41        static ARGS: RefCell<Vec<u8>> = RefCell::default();
42        static MSG_SENDER: RefCell<[u8; 20]> = RefCell::default();
43        static CONTRACT_ADDRESS: RefCell<Address> = RefCell::default();
44        static MSG_VALUE: RefCell<U> = RefCell::default();
45        static CHAIN_ID: RefCell<u64> = RefCell::default();
46        static BLOCK_TIMESTAMP: RefCell<u64> = RefCell::default();
47    }
48
49    #[allow(unused)]
50    pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
51
52    pub(crate) unsafe fn write_result(d: *const u8, l: usize) {
53        println!("{}", const_hex::encode(unsafe { from_raw_parts(d, l) }));
54    }
55
56    pub fn set_args(x: Vec<u8>) {
57        ARGS.with(|s| *s.borrow_mut() = x)
58    }
59
60    pub(crate) unsafe fn read_args(out: *mut u8) {
61        ARGS.with(|s| {
62            let b = s.borrow();
63            unsafe {
64                copy_nonoverlapping(b.as_ptr(), out, b.len());
65            }
66        })
67    }
68
69    pub fn set_msg_sender(x: Address) {
70        MSG_SENDER.with(|s| *s.borrow_mut() = x)
71    }
72
73    pub(crate) unsafe fn msg_sender(out: *mut u8) {
74        MSG_SENDER.with(|s| {
75            let b = s.borrow();
76            unsafe {
77                copy_nonoverlapping(b.as_ptr(), out, 20);
78            }
79        })
80    }
81
82    pub fn set_contract_address(x: Address) {
83        CONTRACT_ADDRESS.with(|s| {
84            *s.borrow_mut() = x;
85        })
86    }
87
88    pub(crate) unsafe fn contract_address(out: *mut u8) {
89        CONTRACT_ADDRESS.with(|s| {
90            let b = s.borrow();
91            unsafe {
92                copy_nonoverlapping(b.as_ptr(), out, 20);
93            }
94        })
95    }
96
97    pub(crate) unsafe fn msg_value(out: *mut u8) {
98        MSG_VALUE.with(|s| {
99            let b = s.borrow();
100            unsafe {
101                copy_nonoverlapping(b.as_ptr(), out, 32);
102            }
103        })
104    }
105
106    pub(crate) unsafe fn chain_id() -> u64 {
107        CHAIN_ID.with(|s| s.borrow().clone())
108    }
109
110    pub(crate) unsafe fn account_codehash(_: *const u8, _: *mut u8) {}
111
112    pub fn set_block_timestamp(n: u64) {
113        BLOCK_TIMESTAMP.with(|s| { *s.borrow_mut() = n })
114    }
115
116    pub(crate) unsafe fn block_timestamp() -> u64 {
117        BLOCK_TIMESTAMP.with(|s| *s.borrow())
118    }
119}
120
121#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
122pub use entry_host as impls;
123
124#[cfg(all(not(target_arch = "wasm32"), not(feature = "std")))]
125mod impls {
126    pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
127
128    pub(crate) unsafe fn write_result(_: *const u8, _: usize) {}
129
130    pub(crate) unsafe fn read_args(_out: *mut u8) {}
131
132    pub(crate) unsafe fn msg_sender(_: *mut u8) {}
133
134    pub(crate) unsafe fn contract_address(_: *mut u8) {}
135
136    pub(crate) unsafe fn msg_value(_: *mut u8) {}
137
138    pub(crate) unsafe fn chain_id() -> u64 {
139        0
140    }
141
142    pub(crate) unsafe fn account_codehash(_: *const u8, _: *mut u8) {}
143
144    pub(crate) unsafe fn block_timestamp() -> u64 {
145        0
146    }
147}
148
149#[unsafe(no_mangle)]
150#[cfg(not(feature = "dont-define-symbols"))]
151pub unsafe fn mark_used() {
152    unsafe { impls::pay_for_memory_grow(0) }
153    panic!();
154}
155
156pub fn write_result_slice(s: &[u8]) {
157    unsafe { impls::write_result(s.as_ptr(), s.len()) }
158}
159
160pub fn write_result_word(s: &U) {
161    write_result_slice(&s.0)
162}
163
164pub fn write_result_bool(v: bool) {
165    write_result_slice(&U::from(v).0)
166}
167
168pub use bobcat_cd::leftpad_addr;
169
170/// Like write_result_exit_call, except it only reverts with the
171/// returndata if the underlying call reverted. If it doesn't, then it
172/// just returns the slice.
173#[macro_export]
174macro_rules! revert_if_bad_call_vec {
175    ($e:expr) => {{
176        let (rc, rd) = $e;
177        if !rc {
178            $crate::write_result_slice(&rd);
179            return 1;
180        }
181        rd
182    }};
183}
184
185/// Reverts if the underlying call failed, using the vector that was
186/// returned as the third argument as slice.
187#[macro_export]
188macro_rules! revert_if_bad_call_unit_vec {
189    ($e:expr) => {{
190        let (rc, revertdata) = $e;
191        match (rc, revertdata) {
192            (true, _) => (),
193            (false, Some(v)) => {
194                $crate::write_result_slice(&v);
195                return 1;
196            }
197            (false, _) => return 1,
198        }
199    }};
200}
201
202/// Reverts with a message if the revertdata is Some, and if the rc is false.
203#[macro_export]
204macro_rules! revert_if_bad_call_slice_vec {
205    ($e:expr) => {{
206        let (rc, returndata, revertdata) = $e;
207        match (rc, revertdata) {
208            (true, _) => returndata,
209            (false, Some(v)) => {
210                $crate::write_result_slice(&v);
211                return 1;
212            }
213            (false, _) => return 1,
214        }
215    }};
216}
217
218#[macro_export]
219macro_rules! write_result_exit_res {
220    ($ident:expr) => {{
221        match $ident {
222            Ok(v) => {
223                $crate::write_result_slice(&v);
224                0
225            }
226            Err(v) => {
227                $crate::write_result_slice(&v);
228                1
229            }
230        }
231    }};
232}
233
234#[macro_export]
235macro_rules! write_result_exit_create {
236    ($ident:expr) => {{
237        let (addr, b, i) = $ident;
238        if addr != [0u8; 20] {
239            $crate::write_result_slice(&leftpad_addr(addr));
240            0
241        } else {
242            $crate::write_result_slice(&b[..i]);
243            1
244        }
245    }};
246}
247
248#[macro_export]
249macro_rules! write_result_exit_call {
250    ($ident:expr) => {{
251        let (rc, l, v) = $ident;
252        $crate::write_result_slice(&v[..l]);
253        if rc {
254            0
255        } else {
256            1
257        }
258    }};
259}
260
261pub fn read_args<const CAP: usize>(len: usize) -> ([u8; CAP], usize) {
262    assert!(CAP >= len, "cap not enough");
263    let mut b = [0u8; CAP];
264    unsafe { impls::read_args(b.as_mut_ptr()) };
265    (b, len)
266}
267
268#[macro_export]
269macro_rules! read_args_safe {
270    ($len:expr, $max_len:expr) => {{
271        assert!($max_len >= $len);
272        $crate::read_args::<$max_len>($len).0
273    }};
274}
275
276#[cfg(feature = "alloc")]
277pub fn read_args_vec(len: usize) -> Vec<u8> {
278    let mut b = Vec::with_capacity(len);
279    unsafe {
280        impls::read_args(b.as_mut_ptr());
281        b.set_len(len);
282    };
283    b
284}
285
286pub fn msg_sender() -> Address {
287    let mut b = [0u8; 20];
288    unsafe { impls::msg_sender(b.as_mut_ptr()) }
289    b
290}
291
292pub fn contract_address() -> Address {
293    let mut b = [0u8; 20];
294    unsafe { impls::contract_address(b.as_mut_ptr()) }
295    b
296}
297
298pub fn msg_value() -> U {
299    let mut b = [0u8; 32];
300    unsafe { impls::msg_value(b.as_mut_ptr()) }
301    U(b)
302}
303
304pub fn code_hash(addr: Address) -> [u8; 32] {
305    let mut b = [0u8; 32];
306    unsafe { impls::account_codehash(addr.as_ptr(), b.as_mut_ptr()) };
307    b
308}
309
310pub fn chain_id() -> u64 {
311    unsafe { impls::chain_id() }
312}
313
314pub fn block_timestamp() -> u64 {
315    unsafe { impls::block_timestamp() }
316}