1use miden_stdlib_sys::{Felt, Word};
2
3use super::types::AccountId;
4
5#[doc(hidden)]
7pub trait SupportedForeignProcedureInputLen {}
8
9macro_rules! supported_foreign_procedure_input_len {
10 ($($len:expr),* $(,)?) => {
11 $(
12 impl SupportedForeignProcedureInputLen for [(); $len] {}
13 )*
14 };
15}
16
17supported_foreign_procedure_input_len!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
18
19#[derive(Clone, Copy, Debug)]
21#[repr(C)]
22pub struct ForeignProcedureInputs {
23 words: [Word; 4],
24}
25
26impl ForeignProcedureInputs {
27 pub fn new<const N: usize>(values: [Felt; N]) -> Self
31 where
32 [(); N]: SupportedForeignProcedureInputLen,
33 {
34 let mut padded = [Felt::ZERO; 16];
35 padded[..N].copy_from_slice(&values);
36
37 Self {
38 words: [
39 Word::new([padded[3], padded[2], padded[1], padded[0]]),
40 Word::new([padded[7], padded[6], padded[5], padded[4]]),
41 Word::new([padded[11], padded[10], padded[9], padded[8]]),
42 Word::new([padded[15], padded[14], padded[13], padded[12]]),
43 ],
44 }
45 }
46}
47
48#[derive(Clone, Copy, Debug)]
50#[repr(C)]
51pub struct ForeignProcedureOutputs {
52 words: [Word; 4],
53}
54
55impl ForeignProcedureOutputs {
56 pub fn get(&self, index: usize) -> Felt {
62 self.words[index / 4][3 - (index % 4)]
63 }
64}
65
66#[derive(Clone, Copy, Debug)]
68#[repr(C)]
69pub struct ForeignProcedureInvocation {
70 pub words: [Word; 6],
72}
73
74impl ForeignProcedureInvocation {
75 pub fn new(
77 foreign_account_id: AccountId,
78 foreign_proc_root: Word,
79 inputs: ForeignProcedureInputs,
80 ) -> Self {
81 let zero = Felt::ZERO;
82 Self {
83 words: [
84 Word::new([
85 foreign_account_id.prefix,
86 foreign_account_id.suffix,
87 foreign_proc_root[0],
88 foreign_proc_root[1],
89 ]),
90 Word::new([
91 foreign_proc_root[2],
92 foreign_proc_root[3],
93 inputs.words[0][0],
94 inputs.words[0][1],
95 ]),
96 Word::new([
97 inputs.words[0][2],
98 inputs.words[0][3],
99 inputs.words[1][0],
100 inputs.words[1][1],
101 ]),
102 Word::new([
103 inputs.words[1][2],
104 inputs.words[1][3],
105 inputs.words[2][0],
106 inputs.words[2][1],
107 ]),
108 Word::new([
109 inputs.words[2][2],
110 inputs.words[2][3],
111 inputs.words[3][0],
112 inputs.words[3][1],
113 ]),
114 Word::new([inputs.words[3][2], inputs.words[3][3], zero, zero]),
115 ],
116 }
117 }
118}
119
120#[allow(improper_ctypes)]
121unsafe extern "C" {
122 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
123 #[link_name = "miden::protocol::tx::get_block_number"]
124 pub fn extern_tx_get_block_number() -> Felt;
125 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
126 #[link_name = "miden::protocol::tx::get_block_commitment"]
127 pub fn extern_tx_get_block_commitment(ptr: *mut Word);
128 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
129 #[link_name = "miden::protocol::tx::get_block_timestamp"]
130 pub fn extern_tx_get_block_timestamp() -> Felt;
131 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
132 #[link_name = "miden::protocol::tx::get_input_notes_commitment"]
133 pub fn extern_tx_get_input_notes_commitment(ptr: *mut Word);
134 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
135 #[link_name = "miden::protocol::tx::get_output_notes_commitment"]
136 pub fn extern_tx_get_output_notes_commitment(ptr: *mut Word);
137 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
138 #[link_name = "miden::protocol::tx::get_num_input_notes"]
139 pub fn extern_tx_get_num_input_notes() -> Felt;
140 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
141 #[link_name = "miden::protocol::tx::get_num_output_notes"]
142 pub fn extern_tx_get_num_output_notes() -> Felt;
143 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
144 #[link_name = "miden::protocol::tx::get_expiration_block_delta"]
145 pub fn extern_tx_get_expiration_block_delta() -> Felt;
146 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
147 #[link_name = "miden::protocol::tx::update_expiration_block_delta"]
148 pub fn extern_tx_update_expiration_block_delta(delta: Felt);
149 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
150 #[link_name = "miden::protocol::tx::get_tx_script_root"]
151 pub fn extern_tx_get_tx_script_root(ptr: *mut Word);
152 #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
153 #[link_name = "miden::protocol::tx::execute_foreign_procedure_indirect"]
154 pub fn extern_tx_execute_foreign_procedure(
155 invocation: *const ForeignProcedureInvocation,
156 ptr: *mut ForeignProcedureOutputs,
157 );
158}
159
160pub fn get_block_number() -> Felt {
162 unsafe { extern_tx_get_block_number() }
163}
164
165pub fn get_input_notes_commitment() -> Word {
167 unsafe {
168 let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
169 extern_tx_get_input_notes_commitment(ret_area.as_mut_ptr());
170 ret_area.assume_init()
171 }
172}
173
174pub fn get_block_commitment() -> Word {
176 unsafe {
177 let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
178 extern_tx_get_block_commitment(ret_area.as_mut_ptr());
179 ret_area.assume_init()
180 }
181}
182
183pub fn get_block_timestamp() -> Felt {
185 unsafe { extern_tx_get_block_timestamp() }
186}
187
188pub fn get_num_input_notes() -> Felt {
190 unsafe { extern_tx_get_num_input_notes() }
191}
192
193pub fn get_num_output_notes() -> Felt {
195 unsafe { extern_tx_get_num_output_notes() }
196}
197
198pub fn get_expiration_block_delta() -> Felt {
200 unsafe { extern_tx_get_expiration_block_delta() }
201}
202
203pub fn update_expiration_block_delta(delta: Felt) {
205 unsafe {
206 extern_tx_update_expiration_block_delta(delta);
207 }
208}
209
210pub fn get_tx_script_root() -> Word {
212 unsafe {
213 let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
214 extern_tx_get_tx_script_root(ret_area.as_mut_ptr());
215 ret_area.assume_init()
216 }
217}
218
219pub fn get_output_notes_commitment() -> Word {
221 unsafe {
222 let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
223 extern_tx_get_output_notes_commitment(ret_area.as_mut_ptr());
224 ret_area.assume_init()
225 }
226}
227
228pub fn execute_foreign_procedure(
240 foreign_account_id: AccountId,
241 foreign_proc_root: Word,
242 inputs: ForeignProcedureInputs,
243) -> ForeignProcedureOutputs {
244 unsafe {
245 let invocation =
246 ForeignProcedureInvocation::new(foreign_account_id, foreign_proc_root, inputs);
247 let mut ret_area = ::core::mem::MaybeUninit::<ForeignProcedureOutputs>::uninit();
248 extern_tx_execute_foreign_procedure(&invocation, ret_area.as_mut_ptr());
249 ret_area.assume_init()
250 }
251}