1use crate::api::*;
2use byteorder::{ByteOrder, LittleEndian};
3
4#[cfg(not(doctest))]
20#[inline]
21pub fn slice<const T: usize>(data: &[u8], offset: usize) -> &[u8; T] {
22 let sliced_data: &[u8] = &data[offset..(T + offset)];
23 if sliced_data.len() < T {
24 rollback(b"Too Big slice length.", 0);
25 }
26 let ptr = sliced_data.as_ptr() as *const [u8; T];
27 return unsafe { &*ptr };
28}
29
30#[cfg(not(doctest))]
46#[inline]
47pub fn slice_mut<const T: usize>(data: &mut [u8], offset: usize) -> &mut [u8; T] {
48 let sliced_data: &mut [u8] = &mut data[offset..(T + offset)];
49 if sliced_data.len() < T {
50 rollback(b"Too Big slice length.", 0);
51 }
52 let ptr = sliced_data.as_mut_ptr() as *mut [u8; T];
53 return unsafe { &mut *ptr };
54}
55
56#[cfg(not(doctest))]
67#[inline(always)]
68pub fn require(cond: bool, message: &[u8]) -> () {
69 if !cond {
70 rollback(message, 0);
71 }
72}
73
74#[inline(always)]
80pub fn is_buffer_equal<const GUARD_ID: u32>(buf_1: &[u8], buf_2: &[u8]) -> bool {
81 let buf1_len = buf_1.len();
82
83 if buf1_len != buf_2.len() {
84 return false;
85 };
86
87 let mut i = 0;
89 while {
90 _g(GUARD_ID, buf1_len as u32 + 1);
91 i < buf1_len
92 } {
93 if buf_1[i] != buf_2[i] {
94 return false;
95 }
96 i += 1;
97 }
98
99 true
100}
101
102#[inline(always)]
115pub fn is_buffer_equal_20(buf_1: &[u8], buf_2: &[u8]) -> bool {
116 LittleEndian::read_u64(&buf_1[0..]) == LittleEndian::read_u64(&buf_2[0..])
117 && LittleEndian::read_u64(&buf_1[8..]) == LittleEndian::read_u64(&buf_2[8..])
118 && LittleEndian::read_u32(&buf_1[16..]) == LittleEndian::read_u32(&buf_2[16..])
119}
120
121#[inline(always)]
134pub fn is_buffer_equal_32(buf_1: &[u8], buf_2: &[u8]) -> bool {
135 if LittleEndian::read_u64(&buf_1[0..]) == LittleEndian::read_u64(&buf_2[0..])
136 && LittleEndian::read_u64(&buf_1[8..]) == LittleEndian::read_u64(&buf_2[8..])
137 && LittleEndian::read_u64(&buf_1[16..]) == LittleEndian::read_u64(&buf_2[16..])
138 && LittleEndian::read_u64(&buf_1[24..]) == LittleEndian::read_u64(&buf_2[24..])
139 {
140 return true;
141 }
142
143 return false;
144}
145
146#[inline(always)]
152pub fn buffer_zeroize<const GUARD_ID: u32>(buf: &mut [u8]) {
153 let buf_len = buf.len();
154 let mut i = 0;
156 while {
157 _g(GUARD_ID, buf_len as u32 + 1);
158 i < buf_len
159 } {
160 buf[0] = 0;
161 i += 1;
162 }
163}
164
165#[inline(always)]
171pub fn is_txn_outgoing<const GUARD_ID: u32>(
172 hook_acc_id: &mut [u8],
173 otnx_acc_id: &mut [u8],
174) -> Result<bool> {
175 match hook_account(hook_acc_id) {
176 Err(e) => return Err(e),
177 Ok(_) => {}
178 }
179
180 match otxn_field(otnx_acc_id, FieldId::Account) {
181 Err(e) => return Err(e),
182 Ok(_) => {}
183 }
184
185 Ok(is_buffer_equal_20(&hook_acc_id[..], &otnx_acc_id[..]))
186}
187
188#[inline(always)]
194pub fn is_txn_ingoing<const GUARD_ID: u32>(
195 hook_acc_id: &mut [u8],
196 otnx_acc_id: &mut [u8],
197) -> Result<bool> {
198 match is_txn_outgoing::<GUARD_ID>(hook_acc_id, otnx_acc_id) {
199 Err(e) => Err(e),
200 Ok(res) => Ok(!res),
201 }
202}
203
204#[inline(always)]
206pub const fn amount_to_drops(amount_buf: &[u8]) -> Result<u64> {
207 if (amount_buf[0] >> 7) == 1 {
208 return Err(Error::InternalError);
209 }
210
211 Ok((((amount_buf[0] as u64) & 0xb00111111) << 56)
212 + ((amount_buf[1] as u64) << 48)
213 + ((amount_buf[2] as u64) << 40)
214 + ((amount_buf[3] as u64) << 32)
215 + ((amount_buf[4] as u64) << 24)
216 + ((amount_buf[5] as u64) << 16)
217 + ((amount_buf[6] as u64) << 8)
218 + (amount_buf[7] as u64))
219}
220
221#[inline(always)]
223pub const fn drops_to_amount(drops: u64) -> Result<NativeAmount> {
224 if (drops >> 63) == 1 {
225 return Err(Error::InternalError);
226 }
227
228 let mut out: NativeAmount = [0; 8];
229 out[0] = 0b01000000 + ((drops >> 56) & 0b00111111) as u8;
230 out[1] = ((drops >> 48) & 0xFF) as u8;
231 out[2] = ((drops >> 40) & 0xFF) as u8;
232 out[3] = ((drops >> 32) & 0xFF) as u8;
233 out[4] = ((drops >> 24) & 0xFF) as u8;
234 out[5] = ((drops >> 16) & 0xFF) as u8;
235 out[6] = ((drops >> 8) & 0xFF) as u8;
236 out[7] = ((drops >> 0) & 0xFF) as u8;
237 Ok(out)
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243 #[test]
244 fn is_buffer_equal_20_test() {
245 const ACCOUNT_ID: AccountId = [
246 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
247 ];
248 const ACCOUNT_ID_2: AccountId = [
249 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
250 ];
251 const ACCOUNT_ID_3: [u8; 21] = [
252 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
253 ];
254 assert_eq!(is_buffer_equal_20(&ACCOUNT_ID, &ACCOUNT_ID), true);
255 assert_eq!(is_buffer_equal_20(&ACCOUNT_ID, &ACCOUNT_ID_2), false);
256 assert_eq!(is_buffer_equal_20(&ACCOUNT_ID, &ACCOUNT_ID_3), true);
257 }
258
259 #[test]
260 fn is_buffer_equal_32_test() {
261 const DATA_1: Hash = [
262 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
263 25, 26, 27, 28, 29, 30, 31, 32,
264 ];
265 const DATA_2: Hash = [
266 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
267 25, 26, 27, 28, 29, 30, 31, 32,
268 ];
269 const DATA_3: [u8; 33] = [
270 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
271 25, 26, 27, 28, 29, 30, 31, 32, 33,
272 ];
273 assert_eq!(is_buffer_equal_32(&DATA_1, &DATA_1), true);
274 assert_eq!(is_buffer_equal_32(&DATA_1, &DATA_2), false);
275 assert_eq!(is_buffer_equal_32(&DATA_1, &DATA_3), true);
276 }
277
278 #[test]
279 fn amount_to_drops_test() {
280 let amount_buf: NativeAmount = [0b10000000, 0, 0, 0, 0, 0, 0, 0];
281 assert!(amount_to_drops(&amount_buf).is_err());
282 let amount_buf: NativeAmount = [0, 0, 0, 0, 0, 0, 0, 0];
283 match amount_to_drops(&amount_buf) {
284 Ok(amount) => assert_eq!(amount, 0),
285 Err(_) => (),
286 }
287 let amount_buf: NativeAmount = [0, 0, 0, 0, 0, 0, 0, 1];
288 match amount_to_drops(&amount_buf) {
289 Ok(amount) => assert_eq!(amount, 1),
290 Err(_) => (),
291 }
292 let amount_buf: NativeAmount = [0, 0, 0, 0, 0, 0, 0, 100];
293 match amount_to_drops(&amount_buf) {
294 Ok(amount) => assert_eq!(amount, 100),
295 Err(_) => (),
296 }
297 let amount_buf: NativeAmount = [0, 0, 0, 0, 0x05, 0xF5, 0xE1, 0];
298 match amount_to_drops(&amount_buf) {
299 Ok(amount) => assert_eq!(amount, 100000000),
300 Err(_) => (),
301 }
302 let amount_buf: NativeAmount = [0x01, 0x63, 0x45, 0x78, 0x5D, 0x8A, 0, 0];
303 match amount_to_drops(&amount_buf) {
304 Ok(amount) => assert_eq!(amount, 100000000000000000),
305 Err(_) => (),
306 }
307 }
308
309 #[test]
310 fn drops_to_amount_test() {
311 assert!(drops_to_amount(0x8000000000000000).is_err());
312 let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0, 0, 0, 0];
313 match drops_to_amount(0) {
314 Ok(amount) => assert_eq!(amount, amount_buf),
315 Err(_) => (),
316 }
317 let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0, 0, 0, 1];
318 match drops_to_amount(1) {
319 Ok(amount) => assert_eq!(amount, amount_buf),
320 Err(_) => (),
321 }
322 let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0, 0, 0, 100];
323 match drops_to_amount(100) {
324 Ok(amount) => assert_eq!(amount, amount_buf),
325 Err(_) => (),
326 }
327 let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0x05, 0xF5, 0xE1, 0];
328 match drops_to_amount(100000000) {
329 Ok(amount) => assert_eq!(amount, amount_buf),
330 Err(_) => (),
331 }
332 let amount_buf: NativeAmount = [0b01000000 | 0x01, 0x63, 0x45, 0x78, 0x5D, 0x8A, 0, 0];
333 match drops_to_amount(100000000000000000) {
334 Ok(amount) => assert_eq!(amount, amount_buf),
335 Err(_) => (),
336 }
337 }
338}