use miden_stdlib_sys::{Felt, Word};
use super::types::AccountId;
#[doc(hidden)]
pub trait SupportedForeignProcedureInputLen {}
macro_rules! supported_foreign_procedure_input_len {
($($len:expr),* $(,)?) => {
$(
impl SupportedForeignProcedureInputLen for [(); $len] {}
)*
};
}
supported_foreign_procedure_input_len!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ForeignProcedureInputs {
words: [Word; 4],
}
impl ForeignProcedureInputs {
pub fn new<const N: usize>(values: [Felt; N]) -> Self
where
[(); N]: SupportedForeignProcedureInputLen,
{
let mut padded = [Felt::ZERO; 16];
padded[..N].copy_from_slice(&values);
Self {
words: [
Word::new([padded[3], padded[2], padded[1], padded[0]]),
Word::new([padded[7], padded[6], padded[5], padded[4]]),
Word::new([padded[11], padded[10], padded[9], padded[8]]),
Word::new([padded[15], padded[14], padded[13], padded[12]]),
],
}
}
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ForeignProcedureOutputs {
words: [Word; 4],
}
impl ForeignProcedureOutputs {
pub fn get(&self, index: usize) -> Felt {
self.words[index / 4][3 - (index % 4)]
}
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ForeignProcedureInvocation {
pub words: [Word; 6],
}
impl ForeignProcedureInvocation {
pub fn new(
foreign_account_id: AccountId,
foreign_proc_root: Word,
inputs: ForeignProcedureInputs,
) -> Self {
let zero = Felt::ZERO;
Self {
words: [
Word::new([
foreign_account_id.prefix,
foreign_account_id.suffix,
foreign_proc_root[0],
foreign_proc_root[1],
]),
Word::new([
foreign_proc_root[2],
foreign_proc_root[3],
inputs.words[0][0],
inputs.words[0][1],
]),
Word::new([
inputs.words[0][2],
inputs.words[0][3],
inputs.words[1][0],
inputs.words[1][1],
]),
Word::new([
inputs.words[1][2],
inputs.words[1][3],
inputs.words[2][0],
inputs.words[2][1],
]),
Word::new([
inputs.words[2][2],
inputs.words[2][3],
inputs.words[3][0],
inputs.words[3][1],
]),
Word::new([inputs.words[3][2], inputs.words[3][3], zero, zero]),
],
}
}
}
#[allow(improper_ctypes)]
unsafe extern "C" {
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_block_number"]
pub fn extern_tx_get_block_number() -> Felt;
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_block_commitment"]
pub fn extern_tx_get_block_commitment(ptr: *mut Word);
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_block_timestamp"]
pub fn extern_tx_get_block_timestamp() -> Felt;
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_input_notes_commitment"]
pub fn extern_tx_get_input_notes_commitment(ptr: *mut Word);
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_output_notes_commitment"]
pub fn extern_tx_get_output_notes_commitment(ptr: *mut Word);
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_num_input_notes"]
pub fn extern_tx_get_num_input_notes() -> Felt;
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_num_output_notes"]
pub fn extern_tx_get_num_output_notes() -> Felt;
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_expiration_block_delta"]
pub fn extern_tx_get_expiration_block_delta() -> Felt;
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::update_expiration_block_delta"]
pub fn extern_tx_update_expiration_block_delta(delta: Felt);
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::get_tx_script_root"]
pub fn extern_tx_get_tx_script_root(ptr: *mut Word);
#[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
#[link_name = "miden::protocol::tx::execute_foreign_procedure_indirect"]
pub fn extern_tx_execute_foreign_procedure(
invocation: *const ForeignProcedureInvocation,
ptr: *mut ForeignProcedureOutputs,
);
}
pub fn get_block_number() -> Felt {
unsafe { extern_tx_get_block_number() }
}
pub fn get_input_notes_commitment() -> Word {
unsafe {
let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
extern_tx_get_input_notes_commitment(ret_area.as_mut_ptr());
ret_area.assume_init()
}
}
pub fn get_block_commitment() -> Word {
unsafe {
let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
extern_tx_get_block_commitment(ret_area.as_mut_ptr());
ret_area.assume_init()
}
}
pub fn get_block_timestamp() -> Felt {
unsafe { extern_tx_get_block_timestamp() }
}
pub fn get_num_input_notes() -> Felt {
unsafe { extern_tx_get_num_input_notes() }
}
pub fn get_num_output_notes() -> Felt {
unsafe { extern_tx_get_num_output_notes() }
}
pub fn get_expiration_block_delta() -> Felt {
unsafe { extern_tx_get_expiration_block_delta() }
}
pub fn update_expiration_block_delta(delta: Felt) {
unsafe {
extern_tx_update_expiration_block_delta(delta);
}
}
pub fn get_tx_script_root() -> Word {
unsafe {
let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
extern_tx_get_tx_script_root(ret_area.as_mut_ptr());
ret_area.assume_init()
}
}
pub fn get_output_notes_commitment() -> Word {
unsafe {
let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
extern_tx_get_output_notes_commitment(ret_area.as_mut_ptr());
ret_area.assume_init()
}
}
pub fn execute_foreign_procedure(
foreign_account_id: AccountId,
foreign_proc_root: Word,
inputs: ForeignProcedureInputs,
) -> ForeignProcedureOutputs {
unsafe {
let invocation =
ForeignProcedureInvocation::new(foreign_account_id, foreign_proc_root, inputs);
let mut ret_area = ::core::mem::MaybeUninit::<ForeignProcedureOutputs>::uninit();
extern_tx_execute_foreign_procedure(&invocation, ret_area.as_mut_ptr());
ret_area.assume_init()
}
}