use crate::api::*;
use byteorder::{ByteOrder, LittleEndian};
#[cfg(not(doctest))]
#[inline]
pub fn slice<const T: usize>(data: &[u8], offset: usize) -> &[u8; T] {
let sliced_data: &[u8] = &data[offset..(T + offset)];
if sliced_data.len() < T {
rollback(b"Too Big slice length.", 0);
}
let ptr = sliced_data.as_ptr() as *const [u8; T];
return unsafe { &*ptr };
}
#[cfg(not(doctest))]
#[inline]
pub fn slice_mut<const T: usize>(data: &mut [u8], offset: usize) -> &mut [u8; T] {
let sliced_data: &mut [u8] = &mut data[offset..(T + offset)];
if sliced_data.len() < T {
rollback(b"Too Big slice length.", 0);
}
let ptr = sliced_data.as_mut_ptr() as *mut [u8; T];
return unsafe { &mut *ptr };
}
#[cfg(not(doctest))]
#[inline(always)]
pub fn require(cond: bool, message: &[u8]) -> () {
if !cond {
rollback(message, 0);
}
}
#[inline(always)]
pub fn is_buffer_equal<const GUARD_ID: u32>(buf_1: &[u8], buf_2: &[u8]) -> bool {
let buf1_len = buf_1.len();
if buf1_len != buf_2.len() {
return false;
};
let mut i = 0;
while {
_g(GUARD_ID, buf1_len as u32 + 1);
i < buf1_len
} {
if buf_1[i] != buf_2[i] {
return false;
}
i += 1;
}
true
}
#[inline(always)]
pub fn is_buffer_equal_20(buf_1: &[u8], buf_2: &[u8]) -> bool {
LittleEndian::read_u64(&buf_1[0..]) == LittleEndian::read_u64(&buf_2[0..])
&& LittleEndian::read_u64(&buf_1[8..]) == LittleEndian::read_u64(&buf_2[8..])
&& LittleEndian::read_u32(&buf_1[16..]) == LittleEndian::read_u32(&buf_2[16..])
}
#[inline(always)]
pub fn is_buffer_equal_32(buf_1: &[u8], buf_2: &[u8]) -> bool {
if LittleEndian::read_u64(&buf_1[0..]) == LittleEndian::read_u64(&buf_2[0..])
&& LittleEndian::read_u64(&buf_1[8..]) == LittleEndian::read_u64(&buf_2[8..])
&& LittleEndian::read_u64(&buf_1[16..]) == LittleEndian::read_u64(&buf_2[16..])
&& LittleEndian::read_u64(&buf_1[24..]) == LittleEndian::read_u64(&buf_2[24..])
{
return true;
}
return false;
}
#[inline(always)]
pub fn buffer_zeroize<const GUARD_ID: u32>(buf: &mut [u8]) {
let buf_len = buf.len();
let mut i = 0;
while {
_g(GUARD_ID, buf_len as u32 + 1);
i < buf_len
} {
buf[0] = 0;
i += 1;
}
}
#[inline(always)]
pub fn is_txn_outgoing<const GUARD_ID: u32>(
hook_acc_id: &mut [u8],
otnx_acc_id: &mut [u8],
) -> Result<bool> {
match hook_account(hook_acc_id) {
Err(e) => return Err(e),
Ok(_) => {}
}
match otxn_field(otnx_acc_id, FieldId::Account) {
Err(e) => return Err(e),
Ok(_) => {}
}
Ok(is_buffer_equal_20(&hook_acc_id[..], &otnx_acc_id[..]))
}
#[inline(always)]
pub fn is_txn_ingoing<const GUARD_ID: u32>(
hook_acc_id: &mut [u8],
otnx_acc_id: &mut [u8],
) -> Result<bool> {
match is_txn_outgoing::<GUARD_ID>(hook_acc_id, otnx_acc_id) {
Err(e) => Err(e),
Ok(res) => Ok(!res),
}
}
#[inline(always)]
pub const fn amount_to_drops(amount_buf: &[u8]) -> Result<u64> {
if (amount_buf[0] >> 7) == 1 {
return Err(Error::InternalError);
}
Ok((((amount_buf[0] as u64) & 0xb00111111) << 56)
+ ((amount_buf[1] as u64) << 48)
+ ((amount_buf[2] as u64) << 40)
+ ((amount_buf[3] as u64) << 32)
+ ((amount_buf[4] as u64) << 24)
+ ((amount_buf[5] as u64) << 16)
+ ((amount_buf[6] as u64) << 8)
+ (amount_buf[7] as u64))
}
#[inline(always)]
pub const fn drops_to_amount(drops: u64) -> Result<NativeAmount> {
if (drops >> 63) == 1 {
return Err(Error::InternalError);
}
let mut out: NativeAmount = [0; 8];
out[0] = 0b01000000 + ((drops >> 56) & 0b00111111) as u8;
out[1] = ((drops >> 48) & 0xFF) as u8;
out[2] = ((drops >> 40) & 0xFF) as u8;
out[3] = ((drops >> 32) & 0xFF) as u8;
out[4] = ((drops >> 24) & 0xFF) as u8;
out[5] = ((drops >> 16) & 0xFF) as u8;
out[6] = ((drops >> 8) & 0xFF) as u8;
out[7] = ((drops >> 0) & 0xFF) as u8;
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_buffer_equal_20_test() {
const ACCOUNT_ID: AccountId = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
];
const ACCOUNT_ID_2: AccountId = [
0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
];
const ACCOUNT_ID_3: [u8; 21] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
];
assert_eq!(is_buffer_equal_20(&ACCOUNT_ID, &ACCOUNT_ID), true);
assert_eq!(is_buffer_equal_20(&ACCOUNT_ID, &ACCOUNT_ID_2), false);
assert_eq!(is_buffer_equal_20(&ACCOUNT_ID, &ACCOUNT_ID_3), true);
}
#[test]
fn is_buffer_equal_32_test() {
const DATA_1: Hash = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
];
const DATA_2: Hash = [
0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
];
const DATA_3: [u8; 33] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33,
];
assert_eq!(is_buffer_equal_32(&DATA_1, &DATA_1), true);
assert_eq!(is_buffer_equal_32(&DATA_1, &DATA_2), false);
assert_eq!(is_buffer_equal_32(&DATA_1, &DATA_3), true);
}
#[test]
fn amount_to_drops_test() {
let amount_buf: NativeAmount = [0b10000000, 0, 0, 0, 0, 0, 0, 0];
assert!(amount_to_drops(&amount_buf).is_err());
let amount_buf: NativeAmount = [0, 0, 0, 0, 0, 0, 0, 0];
match amount_to_drops(&amount_buf) {
Ok(amount) => assert_eq!(amount, 0),
Err(_) => (),
}
let amount_buf: NativeAmount = [0, 0, 0, 0, 0, 0, 0, 1];
match amount_to_drops(&amount_buf) {
Ok(amount) => assert_eq!(amount, 1),
Err(_) => (),
}
let amount_buf: NativeAmount = [0, 0, 0, 0, 0, 0, 0, 100];
match amount_to_drops(&amount_buf) {
Ok(amount) => assert_eq!(amount, 100),
Err(_) => (),
}
let amount_buf: NativeAmount = [0, 0, 0, 0, 0x05, 0xF5, 0xE1, 0];
match amount_to_drops(&amount_buf) {
Ok(amount) => assert_eq!(amount, 100000000),
Err(_) => (),
}
let amount_buf: NativeAmount = [0x01, 0x63, 0x45, 0x78, 0x5D, 0x8A, 0, 0];
match amount_to_drops(&amount_buf) {
Ok(amount) => assert_eq!(amount, 100000000000000000),
Err(_) => (),
}
}
#[test]
fn drops_to_amount_test() {
assert!(drops_to_amount(0x8000000000000000).is_err());
let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0, 0, 0, 0];
match drops_to_amount(0) {
Ok(amount) => assert_eq!(amount, amount_buf),
Err(_) => (),
}
let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0, 0, 0, 1];
match drops_to_amount(1) {
Ok(amount) => assert_eq!(amount, amount_buf),
Err(_) => (),
}
let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0, 0, 0, 100];
match drops_to_amount(100) {
Ok(amount) => assert_eq!(amount, amount_buf),
Err(_) => (),
}
let amount_buf: NativeAmount = [0b01000000, 0, 0, 0, 0x05, 0xF5, 0xE1, 0];
match drops_to_amount(100000000) {
Ok(amount) => assert_eq!(amount, amount_buf),
Err(_) => (),
}
let amount_buf: NativeAmount = [0b01000000 | 0x01, 0x63, 0x45, 0x78, 0x5D, 0x8A, 0, 0];
match drops_to_amount(100000000000000000) {
Ok(amount) => assert_eq!(amount, amount_buf),
Err(_) => (),
}
}
}