1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6#[allow(unused)]
7use core::fmt::{Write, Result as FmtResult};
8
9#[cfg(target_arch = "wasm32")]
10mod wasm {
11 #[link(wasm_import_module = "console")]
12 #[cfg(feature = "console")]
13 unsafe extern "C" {
14 pub(crate) fn log_txt(ptr: *const u8, len: usize);
15 }
16
17 #[link(wasm_import_module = "vm_hooks")]
18 #[allow(unused)]
19 unsafe extern "C" {
20 pub(crate) fn exit_early(code: i32) -> !;
21 pub(crate) fn write_result(d: *const u8, l: usize);
22 }
23}
24
25#[cfg(target_arch = "wasm32")]
26fn write_result_slice(s: &[u8]) {
27 unsafe { wasm::write_result(s.as_ptr(), s.len()) }
28}
29
30pub const PANIC_PREAMBLE_WORD: [u8; 32 + 4] = match const_hex::const_decode_to_array::<{ 32 + 4 }>(
31 b"4e487b710000000000000000000000000000000000000000000000000000000000000000",
32) {
33 Ok(v) => v,
34 Err(_) => panic!(),
35};
36
37pub const ERROR_PREAMBLE_OFFSET: [u8; 4 + 32] = match const_hex::const_decode_to_array::<{ 4 + 32 }>(
38 b"08c379a00000000000000000000000000000000000000000000000000000000000000020",
39) {
40 Ok(v) => v,
41 Err(_) => panic!(),
42};
43
44#[derive(Clone, Debug, PartialEq)]
45#[repr(u8)]
46pub enum PanicCodes {
47 OverflowOrUnderflow = 0x11,
48 NoMemory = 0x41,
49 DivByZero = 0x12,
50 DecodingError = 0x22,
51}
52
53#[cfg(target_arch = "wasm32")]
54pub fn panic_with_code(x: PanicCodes) -> ! {
55 let mut b = PANIC_PREAMBLE_WORD;
56 b[4 + 32 - 1] = x as u8;
57 write_result_slice(&b);
58 unsafe { wasm::exit_early(1) }
59}
60
61#[cfg(not(target_arch = "wasm32"))]
62pub fn panic_with_code(x: PanicCodes) -> ! {
63 panic!("panicked with code: {x:?}");
64}
65
66#[macro_export]
67macro_rules! panic_on_err_overflow {
68 ($e:expr, $msg:expr) => {{
69 match $e {
70 Some(v) => v,
71 None => {
72 #[cfg(feature = "msg-on-sdk-err")]
73 panic!("overflow: {}", $msg);
74 #[cfg(not(feature = "msg-on-sdk-err"))]
75 $crate::panic_with_code($crate::PanicCodes::OverflowOrUnderflow);
76 }
77 }
78 }};
79}
80
81#[macro_export]
82macro_rules! panic_on_err_div_by_zero {
83 ($e:expr, $msg:expr) => {{
84 match $e {
85 Some(v) => v,
86 None => {
87 #[cfg(feature = "msg-on-sdk-err")]
88 panic!("division by zero: {}", $msg);
89 #[cfg(not(feature = "msg-on-sdk-err"))]
90 $crate::panic_with_code($crate::PanicCodes::DivByZero);
91 }
92 }
93 }}
94}
95
96#[macro_export]
97macro_rules! panic_on_err_bad_decoding_bool {
98 ($msg:expr) => {{
99 #[cfg(feature = "msg-on-sdk-err")]
100 panic!("error decoding: {}", $msg);
101 #[cfg(not(feature = "msg-on-sdk-err"))]
102 $crate::panic_with_code($crate::PanicCodes::DecodingError);
103 }};
104 ($e:expr, $msg:expr) => {{
105 if !$e {
106 panic_on_err_bad_decoding_bool!($msg);
107 }
108 }};
109}
110
111#[allow(unused)]
112struct SliceWriter<'a>(&'a mut [u8], usize);
113
114impl<'a> Write for SliceWriter<'a> {
115 fn write_str(&mut self, s: &str) -> FmtResult {
116 if self.1 + s.len() > self.0.len() {
117 panic_with_code(PanicCodes::NoMemory);
118 }
119 self.0[self.1..self.1 + s.len()].copy_from_slice(s.as_bytes());
120 self.1 += s.len();
121 Ok(())
122 }
123}
124
125#[allow(unused)]
129const REVERT_BUF_SIZE: usize = 1024 * 10;
130
131#[cfg(all(feature = "panic", target_arch = "wasm32"))]
132#[panic_handler]
133pub fn panic_handler(_msg: &core::panic::PanicInfo) -> ! {
134 #[cfg(feature = "console")]
135 {
136 let msg = alloc::format!("{_msg}");
137 unsafe { wasm::log_txt(msg.as_ptr(), msg.len()) }
138 }
139 #[cfg(feature = "panic-revert")]
140 {
141 let mut buf = [0u8; REVERT_BUF_SIZE];
142 buf[..ERROR_PREAMBLE_OFFSET.len()].copy_from_slice(&ERROR_PREAMBLE_OFFSET);
143 let mut w = SliceWriter(&mut buf[ERROR_PREAMBLE_OFFSET.len() + 32..], 0);
144 write!(&mut w, "{_msg}").unwrap();
145 let len_msg = w.1;
146 let len_offset = ERROR_PREAMBLE_OFFSET.len();
147 buf[len_offset + 28..len_offset + 32].copy_from_slice(&(len_msg as u32).to_be_bytes());
148 let len_full = ERROR_PREAMBLE_OFFSET.len() + 32 + len_msg;
149 let len_padded = len_full + (32 - (len_full % 32)) % 32;
150 write_result_slice(&buf[..len_padded]);
151 unsafe { wasm::exit_early(1) }
152 }
153 #[allow(unreachable_code)]
157 core::arch::wasm32::unreachable()
158}