Skip to main content

bobcat_events/
lib.rs

1#![no_std]
2
3pub use bobcat_maths::U;
4
5#[cfg(not(feature = "shadow"))]
6use array_concat::concat_arrays;
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11#[cfg(feature = "alloc")]
12use alloc::vec::Vec;
13
14#[cfg(all(target_family = "wasm", target_os = "unknown"))]
15use bobcat_host as impls;
16
17#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
18#[allow(unused)]
19mod impls {
20    pub(crate) unsafe fn emit_log(_: *const u8, _: usize, _: usize) {}
21    pub(crate) unsafe fn write_result(_: *const u8, _: usize) {}
22}
23
24pub fn emit_log(data: &[u8], topics: usize) {
25    unsafe { impls::emit_log(data.as_ptr(), data.len(), topics) }
26}
27
28// ShadowTable that's intended for the 32 wasm machine to do shadow event
29// logging with custom Nitro instances with a whitelisted pool of nodes
30// to log from.
31#[derive(Debug, Clone, PartialEq)]
32#[repr(C)]
33struct ShadowTable<const DATA: usize> {
34    magic: u8,
35    topics_len: usize,
36    data_len: usize,
37    topics: [U; 4],
38    data: [u8; DATA],
39}
40
41#[cfg(feature = "alloc")]
42#[derive(Debug, Clone, PartialEq)]
43#[repr(C)]
44struct ShadowTableVec {
45    magic: u8,
46    topics_len: usize,
47    data_len: usize,
48    topics: [U; 4],
49    data: Vec<u8>,
50}
51
52const SHADOW_MAGIC_BYTE: u8 = 0xee;
53
54impl<const DATA: usize> Default for ShadowTable<DATA> {
55    fn default() -> Self {
56        Self {
57            magic: SHADOW_MAGIC_BYTE,
58            topics_len: 0,
59            data_len: 0,
60            topics: [U::ZERO; 4],
61            data: [0u8; DATA],
62        }
63    }
64}
65
66#[cfg(feature = "alloc")]
67impl Default for ShadowTableVec {
68    fn default() -> Self {
69        Self {
70            magic: SHADOW_MAGIC_BYTE,
71            topics_len: 0,
72            data_len: 0,
73            topics: [U::ZERO; 4],
74            data: Vec::new(),
75        }
76    }
77}
78
79pub fn shadow_log_0_slice<const D: usize, const ALL: usize>(t0: &U, d: [u8; D]) {
80    let mut t = ShadowTable {
81        data_len: D,
82        data: d,
83        ..ShadowTable::<D>::default()
84    };
85    t.topics[0] = *t0;
86    unsafe {
87        impls::write_result(&t as *const _ as *const u8, 0);
88    }
89}
90
91pub fn shadow_log_1_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, d: [u8; D]) {
92    let mut t = ShadowTable {
93        topics_len: 1,
94        data_len: D,
95        data: d,
96        ..ShadowTable::<D>::default()
97    };
98    t.topics[0] = *t0;
99    t.topics[1] = *t1;
100    unsafe {
101        impls::write_result(&t as *const _ as *const u8, 0);
102    }
103}
104
105pub fn shadow_log_2_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, t2: &U, d: [u8; D]) {
106    let mut t = ShadowTable {
107        topics_len: 2,
108        data_len: D,
109        data: d,
110        ..ShadowTable::<D>::default()
111    };
112    t.topics[0] = *t0;
113    t.topics[1] = *t1;
114    t.topics[2] = *t2;
115    unsafe {
116        impls::write_result(&t as *const _ as *const u8, 0);
117    }
118}
119
120pub fn shadow_log_3_slice<const D: usize, const ALL: usize>(
121    t0: &U,
122    t1: &U,
123    t2: &U,
124    t3: &U,
125    d: [u8; D],
126) {
127    let mut t = ShadowTable {
128        topics_len: 3,
129        data_len: D,
130        data: d,
131        ..ShadowTable::<D>::default()
132    };
133    t.topics[0] = *t0;
134    t.topics[1] = *t1;
135    t.topics[2] = *t2;
136    t.topics[3] = *t3;
137    unsafe {
138        impls::write_result(&t as *const _ as *const u8, 0);
139    }
140}
141
142#[cfg(feature = "alloc")]
143pub fn shadow_log_count(topics: [U; 4], topics_len: usize, data: &[u8]) {
144    let t = ShadowTableVec {
145        topics,
146        topics_len,
147        data_len: data.len(),
148        data: data.to_vec(),
149        ..ShadowTableVec::default()
150    };
151    unsafe {
152        impls::write_result(&t as *const _ as *const u8, 0);
153    }
154}
155
156#[cfg(not(feature = "shadow"))]
157pub fn emit_log_0_slice<const D: usize, const ALL: usize>(t0: &U, d: [u8; D]) {
158    assert_eq!(ALL, D + 32, "not properly sized: {}", D + 32);
159    let x: [u8; ALL] = concat_arrays!(t0.0, d);
160    unsafe {
161        impls::emit_log(x.as_ptr(), x.len(), 1);
162    }
163}
164
165#[cfg(feature = "shadow")]
166pub fn emit_log_0_slice<const D: usize, const ALL: usize>(t0: &U, d: [u8; D]) {
167    shadow_log_0_slice::<D, ALL>(t0, d);
168}
169
170#[cfg(not(feature = "shadow"))]
171pub fn emit_log_1_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, d: [u8; D]) {
172    assert_eq!(ALL, D + 32 * 2, "not properly sized: {}", D + 64);
173    let x: [u8; ALL] = concat_arrays!(t0.0, t1.0, d);
174    unsafe {
175        impls::emit_log(x.as_ptr(), x.len(), 2);
176    }
177}
178
179#[cfg(feature = "shadow")]
180pub fn emit_log_1_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, d: [u8; D]) {
181    shadow_log_1_slice::<D, ALL>(t0, t1, d);
182}
183
184#[cfg(not(feature = "shadow"))]
185pub fn emit_log_2_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, t2: &U, d: [u8; D]) {
186    assert_eq!(ALL, D + 32 * 3, "not properly sized: {}", D + 96);
187    let x: [u8; ALL] = concat_arrays!(t0.0, t1.0, t2.0, d);
188    unsafe {
189        impls::emit_log(x.as_ptr(), x.len(), 3);
190    }
191}
192
193#[cfg(feature = "shadow")]
194pub fn emit_log_2_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, t2: &U, d: [u8; D]) {
195    shadow_log_2_slice::<D, ALL>(t0, t1, t2, d);
196}
197
198#[cfg(not(feature = "shadow"))]
199pub fn emit_log_3_slice<const D: usize, const ALL: usize>(
200    t0: &U,
201    t1: &U,
202    t2: &U,
203    t3: &U,
204    d: [u8; D],
205) {
206    assert_eq!(ALL, D + 32 * 4, "not properly sized: {}", D + 128);
207    let x: [u8; ALL] = concat_arrays!(t0.0, t1.0, t2.0, t3.0, d);
208    unsafe {
209        impls::emit_log(x.as_ptr(), x.len(), 4);
210    }
211}
212
213#[cfg(feature = "shadow")]
214pub fn emit_log_3_slice<const D: usize, const ALL: usize>(
215    t0: &U,
216    t1: &U,
217    t2: &U,
218    t3: &U,
219    d: [u8; D],
220) {
221    shadow_log_3_slice::<D, ALL>(t0, t1, t2, t3, d);
222}
223
224/// Emit a log with a variable amount of topics, with the topics provided
225/// by a slice with a fixed structure. Useful for glue to leverage the
226/// shadow feature with stylus-sdk.
227#[cfg(all(feature = "alloc", not(feature = "shadow")))]
228pub fn emit_log_count(topics: [U; 4], topics_len: usize, data: &[u8]) {
229    let mut d = Vec::with_capacity(topics_len * 32 + data.len());
230    for t in &topics[..topics_len] {
231        d.extend_from_slice(t.as_slice());
232    }
233    d.extend_from_slice(data);
234    unsafe {
235        impls::emit_log(d.as_ptr(), data.len(), topics_len);
236    }
237}
238
239#[cfg(all(feature = "alloc", feature = "shadow"))]
240pub fn emit_log_count(topics: [U; 4], topics_len: usize, data: &[u8]) {
241    shadow_log_count(topics, topics_len, data);
242}
243
244#[cfg(feature = "alloc")]
245pub fn emit_log_0_vec(t0: &U, d: &[u8]) {
246    let mut x = t0.to_vec();
247    x.extend_from_slice(d);
248    unsafe {
249        impls::emit_log(x.as_ptr(), x.len(), 1);
250    }
251}
252
253#[cfg(feature = "alloc")]
254pub fn emit_log_1_vec(t0: &U, t1: &U, d: &[u8]) {
255    let mut x = t0.to_vec();
256    x.extend_from_slice(&t1.0);
257    x.extend_from_slice(d);
258    unsafe {
259        impls::emit_log(x.as_ptr(), x.len(), 2);
260    }
261}
262
263#[cfg(feature = "alloc")]
264pub fn emit_log_2_vec(t0: &U, t1: &U, t2: &U, d: &[u8]) {
265    let mut x = t0.to_vec();
266    x.extend_from_slice(&t1.0);
267    x.extend_from_slice(&t2.0);
268    x.extend_from_slice(d);
269    unsafe {
270        impls::emit_log(x.as_ptr(), x.len(), 3);
271    }
272}
273
274#[cfg(feature = "alloc")]
275pub fn emit_log_3_vec(t0: &U, t1: &U, t2: &U, t3: &U, d: &[u8]) {
276    let mut x = t0.to_vec();
277    x.extend_from_slice(&t1.0);
278    x.extend_from_slice(&t2.0);
279    x.extend_from_slice(&t3.0);
280    x.extend_from_slice(d);
281    unsafe {
282        impls::emit_log(x.as_ptr(), x.len(), 4);
283    }
284}
285
286// Emit an event, doing some into() use and copying of reference Us to
287// make it easier to do printing.
288#[macro_export]
289macro_rules! emit {
290    ($t0:expr) => {{
291        const DATA_LEN: usize = 0;
292        const ALL_LEN: usize = 32;
293        let t0: $crate::U = $t0.into();
294        $crate::emit_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, [])
295    }};
296
297    ($t0:expr, data: $data:expr) => {{
298        let t0: $crate::U = $t0.into();
299        $crate::emit_log_0_vec(&t0, $data)
300    }};
301
302    ($t0:expr, data: $data:expr, $data_len:expr) => {{
303        const DATA_LEN: usize = $data_len;
304        const ALL_LEN: usize = DATA_LEN + 32;
305        let t0: $crate::U = $t0.into();
306        $crate::emit_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, $data)
307    }};
308
309    ($t0:expr, $t1:expr) => {{
310        const DATA_LEN: usize = 0;
311        const ALL_LEN: usize = 32 * 2;
312        let t0: $crate::U = $t0.into();
313        let t1: $crate::U = $t1.into();
314        $crate::emit_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, [])
315    }};
316
317    ($t0:expr, $t1:expr, data: $data:expr) => {{
318        let t0: $crate::U = $t0.into();
319        let t1: $crate::U = $t1.into();
320        $crate::emit_log_1_vec(&t0, &t1, $data)
321    }};
322
323    ($t0:expr, $t1:expr, data: $data:expr, $data_len:expr) => {{
324        const DATA_LEN: usize = $data_len;
325        const ALL_LEN: usize = DATA_LEN + 32 * 2;
326        let t0: $crate::U = $t0.into();
327        let t1: $crate::U = $t1.into();
328        $crate::emit_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, $data)
329    }};
330
331    ($t0:expr, $t1:expr, $t2:expr) => {{
332        const DATA_LEN: usize = 0;
333        const ALL_LEN: usize = 32 * 3;
334        let t0: $crate::U = $t0.into();
335        let t1: $crate::U = $t1.into();
336        let t2: $crate::U = $t2.into();
337        $crate::emit_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, [])
338    }};
339
340    ($t0:expr, $t1:expr, $t2:expr, data: $data:expr) => {{
341        let t0: $crate::U = $t0.into();
342        let t1: $crate::U = $t1.into();
343        let t2: $crate::U = $t2.into();
344        $crate::emit_log_2_vec(&t0, &t1, &t2, $data)
345    }};
346
347    ($t0:expr, $t1:expr, $t2:expr, data: $data:expr, $data_len:expr) => {{
348        const DATA_LEN: usize = $data_len;
349        const ALL_LEN: usize = DATA_LEN + 32 * 3;
350        let t0: $crate::U = $t0.into();
351        let t1: $crate::U = $t1.into();
352        let t2: $crate::U = $t2.into();
353        $crate::emit_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, $data)
354    }};
355
356    ($t0:expr, $t1:expr, $t2:expr, $t3:expr) => {{
357        const DATA_LEN: usize = 0;
358        const ALL_LEN: usize = 32 * 4;
359        let t0: $crate::U = $t0.into();
360        let t1: $crate::U = $t1.into();
361        let t2: $crate::U = $t2.into();
362        let t3: $crate::U = $t3.into();
363        $crate::emit_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, [])
364    }};
365
366    ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr) => {{
367        let t0: $crate::U = $t0.into();
368        let t1: $crate::U = $t1.into();
369        let t2: $crate::U = $t2.into();
370        let t3: $crate::U = $t3.into();
371        $crate::emit_log_3_vec(&t0, &t1, &t2, &t3, $data)
372    }};
373
374    ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr, $data_len:expr) => {{
375        const DATA_LEN: usize = $data_len;
376        const ALL_LEN: usize = DATA_LEN + 32 * 4;
377        let t0: $crate::U = $t0.into();
378        let t1: $crate::U = $t1.into();
379        let t2: $crate::U = $t2.into();
380        let t3: $crate::U = $t3.into();
381        $crate::emit_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, $data)
382    }};
383}
384
385#[macro_export]
386macro_rules! shadow {
387    ($t0:expr) => {{
388        const DATA_LEN: usize = 0;
389        const ALL_LEN: usize = 32;
390        let t0: $crate::U = $t0.into();
391        $crate::shadow_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, [])
392    }};
393
394    ($t0:expr, data: $data:expr) => {{
395        let t0: $crate::U = $t0.into();
396        $crate::shadow_log_0_vec(&t0, $data)
397    }};
398
399    ($t0:expr, data: $data:expr, $data_len:expr) => {{
400        const DATA_LEN: usize = $data_len;
401        const ALL_LEN: usize = DATA_LEN + 32;
402        let t0: $crate::U = $t0.into();
403        $crate::shadow_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, $data)
404    }};
405
406    ($t0:expr, $t1:expr) => {{
407        const DATA_LEN: usize = 0;
408        const ALL_LEN: usize = 32 * 2;
409        let t0: $crate::U = $t0.into();
410        let t1: $crate::U = $t1.into();
411        $crate::shadow_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, [])
412    }};
413
414    ($t0:expr, $t1:expr, data: $data:expr) => {{
415        let t0: $crate::U = $t0.into();
416        let t1: $crate::U = $t1.into();
417        $crate::shadow_log_1_vec(&t0, &t1, $data)
418    }};
419
420    ($t0:expr, $t1:expr, data: $data:expr, $data_len:expr) => {{
421        const DATA_LEN: usize = $data_len;
422        const ALL_LEN: usize = DATA_LEN + 32 * 2;
423        let t0: $crate::U = $t0.into();
424        let t1: $crate::U = $t1.into();
425        $crate::shadow_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, $data)
426    }};
427
428    ($t0:expr, $t1:expr, $t2:expr) => {{
429        const DATA_LEN: usize = 0;
430        const ALL_LEN: usize = 32 * 3;
431        let t0: $crate::U = $t0.into();
432        let t1: $crate::U = $t1.into();
433        let t2: $crate::U = $t2.into();
434        $crate::shadow_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, [])
435    }};
436
437    ($t0:expr, $t1:expr, $t2:expr, data: $data:expr) => {{
438        let t0: $crate::U = $t0.into();
439        let t1: $crate::U = $t1.into();
440        let t2: $crate::U = $t2.into();
441        $crate::shadow_log_2_vec(&t0, &t1, &t2, $data)
442    }};
443
444    ($t0:expr, $t1:expr, $t2:expr, data: $data:expr, $data_len:expr) => {{
445        const DATA_LEN: usize = $data_len;
446        const ALL_LEN: usize = DATA_LEN + 32 * 3;
447        let t0: $crate::U = $t0.into();
448        let t1: $crate::U = $t1.into();
449        let t2: $crate::U = $t2.into();
450        $crate::shadow_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, $data)
451    }};
452
453    ($t0:expr, $t1:expr, $t2:expr, $t3:expr) => {{
454        const DATA_LEN: usize = 0;
455        const ALL_LEN: usize = 32 * 4;
456        let t0: $crate::U = $t0.into();
457        let t1: $crate::U = $t1.into();
458        let t2: $crate::U = $t2.into();
459        let t3: $crate::U = $t3.into();
460        $crate::shadow_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, [])
461    }};
462
463    ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr) => {{
464        let t0: $crate::U = $t0.into();
465        let t1: $crate::U = $t1.into();
466        let t2: $crate::U = $t2.into();
467        let t3: $crate::U = $t3.into();
468        $crate::shadow_log_3_vec(&t0, &t1, &t2, &t3, $data)
469    }};
470
471    ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr, $data_len:expr) => {{
472        const DATA_LEN: usize = $data_len;
473        const ALL_LEN: usize = DATA_LEN + 32 * 4;
474        let t0: $crate::U = $t0.into();
475        let t1: $crate::U = $t1.into();
476        let t2: $crate::U = $t2.into();
477        let t3: $crate::U = $t3.into();
478        $crate::shadow_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, $data)
479    }};
480}