use core::ops::Range;
use crate::api::*;
use crate::uninit_buf;
#[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 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 AccountId,
otnx_acc_id: &mut AccountId,
) -> 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::<GUARD_ID>(
&hook_acc_id[..],
&otnx_acc_id[..],
))
}
#[inline(always)]
pub fn is_txn_ingoing<const GUARD_ID: u32>(
hook_acc_id: &mut AccountId,
otnx_acc_id: &mut AccountId,
) -> 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: &Amount) -> 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 fn prepare_payment_simple(
buf_out: &mut TxnPaymentSimple,
drops_amount: u64,
drops_fee: u64,
to_address: &AccountId,
dest_tag: u32,
src_tag: u32,
) -> Result<()> {
const TT_RANGE: Range<usize> = Range { start: 0, end: 3 };
const FLAGS_RANGE: Range<usize> = Range { start: 3, end: 8 };
const TAG_SRC_RANGE: Range<usize> = Range { start: 8, end: 13 };
const SEQUENCE_RANGE: Range<usize> = Range { start: 13, end: 18 };
const TAG_DST_RANGE: Range<usize> = Range { start: 18, end: 23 };
const FLS_RANGE: Range<usize> = Range { start: 23, end: 29 };
const LLS_RANGE: Range<usize> = Range { start: 29, end: 35 };
const DROPS_RANGE: Range<usize> = Range { start: 35, end: 44 };
const DROPS_FEE_RANGE: Range<usize> = Range { start: 44, end: 53 };
const SIGNING_PUBKEY_RANGE: Range<usize> = Range { start: 53, end: 88 };
const ACCOUNT_SRC_RANGE: Range<usize> = Range {
start: 88,
end: 110,
};
const ACCOUNT_DST_RANGE: Range<usize> = Range {
start: 110,
end: 132,
};
const ETXN_DETAILS_RANGE: Range<usize> = Range {
start: 132,
end: 237,
};
let mut acc: AccountId = uninit_buf!();
match hook_account(&mut acc) {
Err(e) => return Err(e),
Ok(_) => {}
}
let cls = ledger_seq() as u32;
encode_tt(&mut buf_out[TT_RANGE], TxnType::Payment);
encode_flags(&mut buf_out[FLAGS_RANGE], TF_CANONICAL);
encode_tag_src(&mut buf_out[TAG_SRC_RANGE], src_tag);
encode_sequence(&mut buf_out[SEQUENCE_RANGE], 0);
encode_tag_dst(&mut buf_out[TAG_DST_RANGE], dest_tag);
encode_fls(&mut buf_out[FLS_RANGE], cls + 1);
encode_lls(&mut buf_out[LLS_RANGE], cls + 5);
encode_drops_amount(&mut buf_out[DROPS_RANGE], drops_amount);
encode_drops_fee(&mut buf_out[DROPS_FEE_RANGE], drops_fee);
encode_signing_pubkey_null(&mut buf_out[SIGNING_PUBKEY_RANGE]);
encode_account_src(&mut buf_out[ACCOUNT_SRC_RANGE], &acc);
encode_account_dst(&mut buf_out[ACCOUNT_DST_RANGE], to_address);
match etxn_details(&mut buf_out[ETXN_DETAILS_RANGE]) {
Err(e) => return Err(e),
Ok(_) => {}
}
Ok(())
}
#[inline(always)]
fn encode_tt(buf_out: &mut [u8], tt: TxnType) {
buf_out[0] = 0x12;
buf_out[1] = ((tt as u16 >> 8) & 0xFF) as u8;
buf_out[2] = ((tt as u16 >> 0) & 0xFF) as u8;
}
#[inline(always)]
fn encode_flags(buf_out: &mut [u8], flags: u32) {
encode_u32_common(buf_out, flags, 0x2)
}
#[inline(always)]
fn encode_tag_src(buf_out: &mut [u8], tag: u32) {
encode_u32_common(buf_out, tag, 0x3)
}
#[inline(always)]
fn encode_sequence(buf_out: &mut [u8], sequence: u32) {
encode_u32_common(buf_out, sequence, 0x4)
}
#[inline(always)]
fn encode_tag_dst(buf_out: &mut [u8], tag: u32) {
encode_u32_common(buf_out, tag, 0xE)
}
#[inline(always)]
fn encode_fls(buf_out: &mut [u8], fls: u32) {
encode_u32_uncommon(buf_out, fls, 0x1A)
}
#[inline(always)]
fn encode_lls(buf_out: &mut [u8], lls: u32) {
encode_u32_uncommon(buf_out, lls, 0x1B)
}
#[inline(always)]
fn encode_drops_amount(buf_out: &mut [u8], drops: u64) {
encode_drops(buf_out, drops, AmountType::Amount)
}
#[inline(always)]
fn encode_drops_fee(buf_out: &mut [u8], drops: u64) {
encode_drops(buf_out, drops, AmountType::Fee)
}
#[inline(always)]
fn encode_account_src(buf_out: &mut [u8], account_id: &Buffer<ACC_ID_LEN>) {
encode_account(buf_out, account_id, AccountType::Account)
}
#[inline(always)]
fn encode_account_dst(buf_out: &mut [u8], account_id: &Buffer<ACC_ID_LEN>) {
encode_account(buf_out, account_id, AccountType::Destination)
}
#[inline(always)]
fn encode_u32_common(buf_out: &mut [u8], i: u32, field: u8) {
buf_out[0] = 0x20 + (field & 0x0F);
buf_out[1] = ((i >> 24) & 0xFF) as u8;
buf_out[2] = ((i >> 16) & 0xFF) as u8;
buf_out[3] = ((i >> 8) & 0xFF) as u8;
buf_out[4] = ((i >> 0) & 0xFF) as u8;
}
#[inline(always)]
fn encode_u32_uncommon(buf_out: &mut [u8], i: u32, field: u8) {
buf_out[0] = 0x20;
buf_out[1] = field;
buf_out[2] = ((i >> 24) & 0xFF) as u8;
buf_out[3] = ((i >> 16) & 0xFF) as u8;
buf_out[4] = ((i >> 8) & 0xFF) as u8;
buf_out[5] = ((i >> 0) & 0xFF) as u8;
}
#[inline(always)]
fn encode_drops(buf_out: &mut [u8], drops: u64, amount_type: AmountType) {
buf_out[0] = 0x60 + (amount_type as u8 & 0x0F);
buf_out[1] = (0b01000000 + ((drops >> 56) & 0b00111111)) as u8;
buf_out[2] = ((drops >> 48) & 0xFF) as u8;
buf_out[3] = ((drops >> 40) & 0xFF) as u8;
buf_out[4] = ((drops >> 32) & 0xFF) as u8;
buf_out[5] = ((drops >> 24) & 0xFF) as u8;
buf_out[6] = ((drops >> 16) & 0xFF) as u8;
buf_out[7] = ((drops >> 8) & 0xFF) as u8;
buf_out[8] = ((drops >> 0) & 0xFF) as u8;
}
#[inline(always)]
fn encode_signing_pubkey_null(buf_out: &mut [u8]) {
buf_out[0] = 0x73;
buf_out[1] = 0x21;
buf_out[2..35].clone_from_slice(&[0; 33]);
}
#[inline(always)]
fn encode_account(buf_out: &mut [u8], account_id: &AccountId, account_type: AccountType) {
buf_out[0] = 0x80 + account_type as u8;
buf_out[1] = 0x14;
buf_out[2..22].clone_from_slice(&account_id[..]);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::_c;
const ACCOUNT_ID: AccountId = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
];
#[test]
fn enc_account() {
let mut encoded: [u8; _c::ENCODE_ACCOUNT_SIZE as usize] = uninit_buf!();
encode_account(&mut encoded, &ACCOUNT_ID, AccountType::Account);
assert_eq!(
encoded,
[0x81, 0x14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
);
}
#[test]
fn enc_signing_pubkey_null() {
let mut key: [u8; _c::ENCODE_SIGNING_PUBKEY_NULL_SIZE as usize] = [255; 35];
encode_signing_pubkey_null(&mut key);
assert_eq!(
key,
[
0x73, 0x21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0
]
)
}
}