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"))]
16use bobcat_host as impls;
17
18#[cfg(all(
19 not(all(target_family = "wasm", target_os = "unknown")),
20 feature = "std"
21))]
22pub mod entry_host {
23 use super::{Address, U};
24
25 use core::{ptr::copy_nonoverlapping, slice::from_raw_parts};
26
27 use std::{cell::RefCell, cmp::min, collections::HashMap};
28
29 use bobcat_storage::keccak256;
30
31 thread_local! {
32 static ACCOUNT_BALANCE: RefCell<HashMap<Address, U>> = RefCell::default();
33 static ARGS: RefCell<Vec<u8>> = RefCell::default();
34 static MSG_SENDER: RefCell<[u8; 20]> = RefCell::default();
35 static CONTRACT_ADDRESS: RefCell<Address> = RefCell::default();
36 static MSG_VALUE: RefCell<U> = RefCell::default();
37 static CHAIN_ID: RefCell<u64> = RefCell::default();
38 static BLOCK_TIMESTAMP: RefCell<u64> = RefCell::default();
39 static ACCOUNT_CODE: RefCell<HashMap<Address, Vec<u8>>> = RefCell::default();
40 }
41
42 const EMPTY_HASH: U = U([
43 0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03,
44 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85,
45 0xa4, 0x70,
46 ]);
47
48 pub(crate) unsafe fn account_balance(addr_: *const u8, out: *mut u8) {
49 ACCOUNT_BALANCE.with(|s| {
50 let mut addr = [0u8; 20];
51 unsafe {
52 copy_nonoverlapping(addr_, addr.as_mut_ptr(), 32);
53 }
54 let h = s.borrow();
55 let amt = h.get(&addr).unwrap_or(&U::ZERO);
56 unsafe {
57 copy_nonoverlapping(amt.as_ptr(), out, 32);
58 }
59 })
60 }
61
62 #[allow(unused)]
63 pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
64
65 pub(crate) unsafe fn write_result(d: *const u8, l: usize) {
66 println!("{}", const_hex::encode(unsafe { from_raw_parts(d, l) }));
67 }
68
69 pub(crate) unsafe fn return_data_size() -> usize {
70 0
71 }
72
73 pub fn set_args(x: Vec<u8>) {
74 ARGS.with(|s| *s.borrow_mut() = x)
75 }
76
77 pub fn args_len() -> usize {
78 ARGS.with(|s| s.borrow().len())
79 }
80
81 pub(crate) unsafe fn read_args(out: *mut u8) {
82 ARGS.with(|s| {
83 let b = s.borrow();
84 unsafe {
85 copy_nonoverlapping(b.as_ptr(), out, b.len());
86 }
87 })
88 }
89
90 pub fn set_msg_sender(x: Address) {
91 MSG_SENDER.with(|s| *s.borrow_mut() = x)
92 }
93
94 pub(crate) unsafe fn msg_sender(out: *mut u8) {
95 MSG_SENDER.with(|s| {
96 let b = s.borrow();
97 unsafe {
98 copy_nonoverlapping(b.as_ptr(), out, 20);
99 }
100 })
101 }
102
103 pub fn set_contract_address(x: Address) {
104 CONTRACT_ADDRESS.with(|s| {
105 *s.borrow_mut() = x;
106 })
107 }
108
109 pub fn set_account_code(x: Address, code: Vec<u8>) {
110 ACCOUNT_CODE.with(|s| s.borrow_mut().insert(x, code));
111 }
112
113 pub(crate) unsafe fn contract_address(out: *mut u8) {
114 CONTRACT_ADDRESS.with(|s| {
115 let b = s.borrow();
116 unsafe {
117 copy_nonoverlapping(b.as_ptr(), out, 20);
118 }
119 })
120 }
121
122 pub(crate) unsafe fn msg_value(out: *mut u8) {
123 MSG_VALUE.with(|s| {
124 let b = s.borrow();
125 unsafe {
126 copy_nonoverlapping(b.as_ptr(), out, 32);
127 }
128 })
129 }
130
131 pub(crate) unsafe fn chainid() -> u64 {
132 CHAIN_ID.with(|s| s.borrow().clone())
133 }
134
135 pub(crate) unsafe fn account_code_size(addr_: *const u8) -> usize {
136 ACCOUNT_CODE.with(|s| {
137 let mut addr = [0u8; 20];
138 unsafe {
139 copy_nonoverlapping(addr_, addr.as_mut_ptr(), 20);
140 }
141 s.borrow().get(&addr).map(|s| s.len()).unwrap_or(0)
142 })
143 }
144
145 pub(crate) unsafe fn account_code(
146 addr_: *const u8,
147 offset: usize,
148 size: usize,
149 out: *mut u8,
150 ) -> usize {
151 ACCOUNT_CODE.with(|s| {
152 let mut addr = [0u8; 20];
153 unsafe {
154 copy_nonoverlapping(addr_, addr.as_mut_ptr(), 20);
155 }
156 let b = s.borrow();
157 match b.get(&addr) {
158 Some(b) => {
159 if offset >= b.len() {
160 return 0;
161 }
162 let src = &b[offset..];
163 let len = min(size, src.len());
164 unsafe {
165 copy_nonoverlapping(src.as_ptr(), out, len);
166 }
167 len
168 }
169 None => 0,
170 }
171 })
172 }
173
174 pub unsafe fn account_codehash(addr_: *const u8, out: *mut u8) {
175 ACCOUNT_CODE.with(|s| {
176 let mut addr = [0u8; 20];
177 unsafe {
178 copy_nonoverlapping(addr_, addr.as_mut_ptr(), 20);
179 }
180 let b = s.borrow();
181 let h = match b.get(&addr) {
182 None => EMPTY_HASH,
183 Some(b) if b.len() == 0 => EMPTY_HASH,
184 Some(b) => keccak256(&b),
185 };
186 unsafe {
187 copy_nonoverlapping(h.as_ptr(), out, 32);
188 }
189 })
190 }
191
192 pub fn set_block_timestamp(n: u64) {
193 BLOCK_TIMESTAMP.with(|s| *s.borrow_mut() = n)
194 }
195
196 pub(crate) unsafe fn block_timestamp() -> u64 {
197 BLOCK_TIMESTAMP.with(|s| *s.borrow())
198 }
199
200 pub(crate) unsafe fn block_basefee(_: *mut u8) {}
201
202 pub(crate) unsafe fn evm_gas_left() -> u64 {
203 0
204 }
205
206 pub(crate) unsafe fn evm_ink_left() -> u64 {
207 0
208 }
209}
210
211#[cfg(all(
212 not(all(target_family = "wasm", target_os = "unknown")),
213 feature = "std"
214))]
215pub use entry_host as impls;
216
217#[cfg(all(
218 not(all(target_family = "wasm", target_os = "unknown")),
219 not(feature = "std")
220))]
221mod impls {
222 pub(crate) unsafe fn account_balance(_: *const u8, _: *mut u8) {}
223
224 #[allow(unused)]
225 pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
226
227 pub(crate) unsafe fn write_result(_: *const u8, _: usize) {}
228
229 pub(crate) unsafe fn return_data_size() -> usize {
230 0
231 }
232
233 pub(crate) unsafe fn read_args(_out: *mut u8) {}
234
235 pub(crate) unsafe fn msg_sender(_: *mut u8) {}
236
237 pub(crate) unsafe fn contract_address(_: *mut u8) {}
238
239 pub(crate) unsafe fn msg_value(_: *mut u8) {}
240
241 pub(crate) unsafe fn chainid() -> u64 {
242 0
243 }
244
245 pub unsafe fn account_code_size(_: *const u8) -> usize {
246 0
247 }
248
249 pub(crate) unsafe fn account_code(_: *const u8, _: usize, _: usize, _: *mut u8) -> usize {
250 0
251 }
252
253 pub(crate) unsafe fn account_codehash(_: *const u8, _: *mut u8) {}
254
255 pub(crate) unsafe fn block_timestamp() -> u64 {
256 0
257 }
258
259 pub(crate) unsafe fn block_basefee(_: *mut u8) {}
260
261 pub(crate) unsafe fn evm_gas_left() -> u64 {
262 0
263 }
264 pub(crate) unsafe fn evm_ink_left() -> u64 {
265 0
266 }
267}
268
269pub fn balance(addr: Address) -> U {
270 let mut out = U::ZERO;
271 unsafe { impls::account_balance(addr.as_ptr(), out.as_mut_ptr()) }
272 out
273}
274
275#[unsafe(no_mangle)]
276#[cfg(all(
277 target_family = "wasm",
278 target_os = "unknown",
279 not(feature = "dont-define-symbols")
280))]
281pub unsafe fn mark_used() {
282 unsafe { impls::pay_for_memory_grow(0) }
283 panic!();
284}
285
286pub fn write_result_slice(s: &[u8]) {
287 unsafe { impls::write_result(s.as_ptr(), s.len()) }
288}
289
290pub fn write_result_word(s: &U) {
291 write_result_slice(&s.0)
292}
293
294pub fn write_result_bool(v: bool) {
295 write_result_slice(&U::from(v).0)
296}
297
298pub fn return_data_size() -> usize {
299 unsafe { impls::return_data_size() }
300}
301
302pub use bobcat_cd::leftpad_addr;
303
304#[macro_export]
308macro_rules! revert_if_bad_call_vec {
309 ($e:expr) => {{
310 let (rc, rd) = $e;
311 if !rc {
312 $crate::write_result_slice(&rd);
313 return 1;
314 }
315 rd
316 }};
317}
318
319#[macro_export]
322macro_rules! revert_if_bad_call_unit_vec {
323 ($e:expr) => {{
324 let (rc, revertdata) = $e;
325 match (rc, revertdata) {
326 (true, _) => (),
327 (false, Some(v)) => {
328 $crate::write_result_slice(&v);
329 return 1;
330 }
331 (false, _) => return 1,
332 }
333 }};
334}
335
336#[macro_export]
338macro_rules! revert_if_bad_call_slice_vec {
339 ($e:expr) => {{
340 let (rc, returndata, revertdata) = $e;
341 match (rc, revertdata) {
342 (true, _) => returndata,
343 (false, Some(v)) => {
344 $crate::write_result_slice(&v);
345 return 1;
346 }
347 (false, _) => return 1,
348 }
349 }};
350}
351
352#[macro_export]
353macro_rules! write_result_exit_res {
354 ($ident:expr) => {{
355 match $ident {
356 Ok(v) => {
357 $crate::write_result_slice(&v);
358 0
359 }
360 Err(v) => {
361 $crate::write_result_slice(&v);
362 1
363 }
364 }
365 }};
366}
367
368#[macro_export]
369macro_rules! write_result_exit_create {
370 ($ident:expr) => {{
371 let (addr, b, i) = $ident;
372 if addr != [0u8; 20] {
373 $crate::write_result_slice(&leftpad_addr(addr));
374 0
375 } else {
376 $crate::write_result_slice(&b[..i]);
377 1
378 }
379 }};
380}
381
382#[macro_export]
383macro_rules! write_result_exit_call {
384 ($ident:expr) => {{
385 let (rc, l, v) = $ident;
386 $crate::write_result_slice(&v[..l]);
387 if rc { 0 } else { 1 }
388 }};
389}
390
391pub fn read_args<const CAP: usize>(len: usize) -> ([u8; CAP], usize) {
392 assert!(CAP >= len, "cap not enough");
393 let mut b = [0u8; CAP];
394 unsafe { impls::read_args(b.as_mut_ptr()) };
395 (b, len)
396}
397
398#[macro_export]
399macro_rules! read_args_safe {
400 ($len:expr, $max_len:expr) => {{
401 assert!($max_len >= $len, "{} < {}", $max_len, $len);
402 $crate::read_args::<$max_len>($len).0
403 }};
404}
405
406#[cfg(feature = "alloc")]
407pub fn read_args_vec(len: usize) -> Vec<u8> {
408 let mut b = Vec::with_capacity(len);
409 unsafe {
410 impls::read_args(b.as_mut_ptr());
411 b.set_len(len);
412 };
413 b
414}
415
416pub fn msg_sender() -> Address {
417 let mut b = [0u8; 20];
418 unsafe { impls::msg_sender(b.as_mut_ptr()) }
419 b
420}
421
422pub fn contract_address() -> Address {
423 let mut b = [0u8; 20];
424 unsafe { impls::contract_address(b.as_mut_ptr()) }
425 b
426}
427
428pub fn msg_value() -> U {
429 let mut b = [0u8; 32];
430 unsafe { impls::msg_value(b.as_mut_ptr()) }
431 U(b)
432}
433
434pub fn code_size(addr: Address) -> usize {
435 unsafe { impls::account_code_size(addr.as_ptr()) }
436}
437
438pub fn code_slice<const CAP: usize>(
439 addr: Address,
440 size: usize,
441 offset: usize,
442) -> ([u8; CAP], usize) {
443 let mut b = [0u8; CAP];
444 assert!(CAP >= size, "not enough size: {size}, capacity: {CAP}");
445 let rd = unsafe { impls::account_code(addr.as_ptr(), offset, size, b.as_mut_ptr()) };
446 (b, rd)
447}
448
449#[cfg(feature = "alloc")]
450pub fn code_vec_size(addr: Address, offset: usize, size: usize) -> Vec<u8> {
451 let mut b = Vec::with_capacity(size);
452 let rd = unsafe { impls::account_code(addr.as_ptr(), offset, size, b.as_mut_ptr()) };
453 unsafe { b.set_len(rd) };
454 b
455}
456
457#[cfg(feature = "alloc")]
458pub fn code_vec(addr: Address, offset: usize) -> Vec<u8> {
459 code_vec_size(addr, offset, code_size(addr))
460}
461
462pub fn code_hash(addr: Address) -> U {
463 let mut b = U::ZERO;
464 unsafe { impls::account_codehash(addr.as_ptr(), b.as_mut_ptr()) };
465 b
466}
467
468pub fn chain_id() -> u64 {
469 unsafe { impls::chainid() }
470}
471
472pub fn block_timestamp() -> u64 {
473 unsafe { impls::block_timestamp() }
474}
475
476pub fn block_basefee() -> U {
477 let mut out = U::ZERO;
478 unsafe { impls::block_basefee(out.as_mut_ptr()) }
479 out
480}
481
482pub fn evm_gas_left() -> u64 {
483 unsafe { impls::evm_gas_left() }
484}
485
486pub fn evm_ink_left() -> u64 {
487 unsafe { impls::evm_ink_left() }
488}