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