snarkvm_console_program/data/future/
argument.rs1use super::*;
17
18#[derive(Clone, Debug)]
20pub enum Argument<N: Network> {
21 Plaintext(Plaintext<N>),
23 Future(Future<N>),
25 DynamicFuture(DynamicFuture<N>),
27}
28
29impl<N: Network> Equal<Self> for Argument<N> {
30 type Output = Boolean<N>;
31
32 fn is_equal(&self, other: &Self) -> Self::Output {
34 match (self, other) {
35 (Self::Plaintext(a), Self::Plaintext(b)) => a.is_equal(b),
36 (Self::Future(a), Self::Future(b)) => a.is_equal(b),
37 (Self::DynamicFuture(a), Self::DynamicFuture(b)) => a.is_equal(b),
38 (Self::Plaintext(..), _) | (Self::Future(..), _) | (Self::DynamicFuture(..), _) => Boolean::new(false),
39 }
40 }
41
42 fn is_not_equal(&self, other: &Self) -> Self::Output {
44 match (self, other) {
45 (Self::Plaintext(a), Self::Plaintext(b)) => a.is_not_equal(b),
46 (Self::Future(a), Self::Future(b)) => a.is_not_equal(b),
47 (Self::DynamicFuture(a), Self::DynamicFuture(b)) => a.is_not_equal(b),
48 (Self::Plaintext(..), _) | (Self::Future(..), _) | (Self::DynamicFuture(..), _) => Boolean::new(true),
49 }
50 }
51}
52
53impl<N: Network> ToBits for Argument<N> {
54 #[inline]
56 fn write_bits_le(&self, vec: &mut Vec<bool>) {
57 match self {
58 Self::Plaintext(plaintext) => {
59 vec.push(false);
60 plaintext.write_bits_le(vec);
61 }
62 Self::Future(future) => {
63 vec.push(true);
64 future.write_bits_le(vec);
65 }
66 Self::DynamicFuture(dynamic_future) => {
67 vec.push(true);
68 vec.extend(std::iter::repeat_n(false, 12));
75 dynamic_future.write_bits_le(vec);
76 }
77 }
78 }
79
80 #[inline]
82 fn write_bits_be(&self, vec: &mut Vec<bool>) {
83 match self {
84 Self::Plaintext(plaintext) => {
85 vec.push(false);
86 plaintext.write_bits_be(vec);
87 }
88 Self::Future(future) => {
89 vec.push(true);
90 future.write_bits_be(vec);
91 }
92 Self::DynamicFuture(dynamic_future) => {
93 vec.push(true);
94 vec.extend(std::iter::repeat_n(false, 12));
101 dynamic_future.write_bits_be(vec);
102 }
103 }
104 }
105}
106
107impl<N: Network> ToFields for Argument<N> {
108 type Field = Field<N>;
109
110 fn to_fields(&self) -> Result<Vec<Self::Field>> {
112 let mut bits_le = self.to_bits_le();
114 bits_le.push(true);
117 let fields = bits_le
119 .chunks(Field::<N>::size_in_data_bits())
120 .map(Field::<N>::from_bits_le)
121 .collect::<Result<Vec<_>>>()?;
122 match fields.len() <= N::MAX_DATA_SIZE_IN_FIELDS as usize {
124 true => Ok(fields),
125 false => bail!("Argument exceeds maximum allowed size"),
126 }
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use snarkvm_console_network::MainnetV0;
134
135 use core::str::FromStr;
136
137 type CurrentNetwork = MainnetV0;
138
139 #[test]
140 fn test_plaintext_argument_bit_encoding() {
141 let plaintext = Plaintext::<CurrentNetwork>::from_str("42u64").unwrap();
143 let argument = Argument::Plaintext(plaintext);
144
145 let bits = argument.to_bits_le();
147
148 assert!(!bits[0], "Plaintext argument should start with false tag bit");
150 }
151
152 #[test]
153 fn test_future_argument_bit_encoding() {
154 let future = Future::<CurrentNetwork>::new(
156 ProgramID::from_str("test.aleo").unwrap(),
157 Identifier::from_str("foo").unwrap(),
158 vec![],
159 );
160 let argument = Argument::Future(future);
161
162 let bits = argument.to_bits_le();
164
165 assert!(bits[0], "Future argument should start with true tag bit");
167
168 let first_byte_bits = &bits[1..9];
171 assert!(first_byte_bits.iter().any(|&b| b), "Static future's program ID should not start with a zero byte");
172 }
173
174 #[test]
175 fn test_dynamic_future_argument_bit_encoding() {
176 let future = Future::<CurrentNetwork>::new(
178 ProgramID::from_str("test.aleo").unwrap(),
179 Identifier::from_str("foo").unwrap(),
180 vec![Argument::Plaintext(Plaintext::from_str("100u64").unwrap())],
181 );
182 let dynamic_future = DynamicFuture::from_future(&future).unwrap();
183 let argument = Argument::DynamicFuture(dynamic_future);
184
185 let bits = argument.to_bits_le();
187
188 assert!(bits[0], "DynamicFuture argument should start with true tag bit");
190
191 for (i, &bit) in bits[1..13].iter().enumerate() {
193 assert!(!bit, "DynamicFuture should have false bit at position {} (1-indexed: {})", i, i + 1);
194 }
195 }
196
197 #[test]
198 fn test_dynamic_future_distinguishable_from_static_future() {
199 let static_future = Future::<CurrentNetwork>::new(
201 ProgramID::from_str("test.aleo").unwrap(),
202 Identifier::from_str("foo").unwrap(),
203 vec![],
204 );
205 let static_argument = Argument::Future(static_future.clone());
206
207 let dynamic_future = DynamicFuture::from_future(&static_future).unwrap();
209 let dynamic_argument = Argument::DynamicFuture(dynamic_future);
210
211 let static_bits = static_argument.to_bits_le();
213 let dynamic_bits = dynamic_argument.to_bits_le();
214
215 assert!(static_bits[0], "Static future should start with true tag bit");
217 assert!(dynamic_bits[0], "Dynamic future should start with true tag bit");
218
219 let static_first_12 = &static_bits[1..13];
223 let dynamic_first_12 = &dynamic_bits[1..13];
224
225 assert!(
227 static_first_12[..8].iter().any(|&b| b),
228 "Static future should have non-zero first byte (program ID identifier)"
229 );
230
231 assert!(dynamic_first_12.iter().all(|&b| !b), "Dynamic future should have all-zero disambiguation prefix");
233 }
234
235 fn check_equality(
237 same1: &Argument<CurrentNetwork>,
238 same2: &Argument<CurrentNetwork>,
239 different: &Argument<CurrentNetwork>,
240 ) {
241 assert!(*same1.is_equal(same2));
243 assert!(!*same1.is_not_equal(same2));
244 assert!(!*same1.is_equal(different));
246 assert!(*same1.is_not_equal(different));
247 }
248
249 #[test]
250 fn test_argument_equality() {
251 let p1 = Argument::Plaintext(Plaintext::from_str("42u64").unwrap());
253 let p2 = Argument::Plaintext(Plaintext::from_str("42u64").unwrap());
254 let p3 = Argument::Plaintext(Plaintext::from_str("100u64").unwrap());
255 check_equality(&p1, &p2, &p3);
256
257 let make_future = |name: &str| {
259 Future::<CurrentNetwork>::new(
260 ProgramID::from_str("test.aleo").unwrap(),
261 Identifier::from_str(name).unwrap(),
262 vec![Argument::Plaintext(Plaintext::from_str("100u64").unwrap())],
263 )
264 };
265 let f1 = Argument::Future(make_future("foo"));
266 let f2 = Argument::Future(make_future("foo"));
267 let f3 = Argument::Future(make_future("bar"));
268 check_equality(&f1, &f2, &f3);
269
270 let make_dynamic = |program: &str| {
272 let future = Future::<CurrentNetwork>::new(
273 ProgramID::from_str(program).unwrap(),
274 Identifier::from_str("foo").unwrap(),
275 vec![Argument::Plaintext(Plaintext::from_str("100u64").unwrap())],
276 );
277 DynamicFuture::from_future(&future).unwrap()
278 };
279 let d1 = Argument::DynamicFuture(make_dynamic("test.aleo"));
280 let d2 = Argument::DynamicFuture(make_dynamic("test.aleo"));
281 let d3 = Argument::DynamicFuture(make_dynamic("other.aleo"));
282 check_equality(&d1, &d2, &d3);
283 }
284
285 #[test]
286 fn test_argument_equality_cross_variant() {
287 let plaintext = Plaintext::<CurrentNetwork>::from_str("42u64").unwrap();
289 let future = Future::<CurrentNetwork>::new(
290 ProgramID::from_str("test.aleo").unwrap(),
291 Identifier::from_str("foo").unwrap(),
292 vec![],
293 );
294 let dynamic_future = DynamicFuture::from_future(&future).unwrap();
295
296 let arg_plaintext = Argument::Plaintext(plaintext);
297 let arg_future = Argument::Future(future);
298 let arg_dynamic = Argument::DynamicFuture(dynamic_future);
299
300 assert!(!*arg_plaintext.is_equal(&arg_future));
302 assert!(!*arg_plaintext.is_equal(&arg_dynamic));
303 assert!(!*arg_future.is_equal(&arg_plaintext));
304 assert!(!*arg_future.is_equal(&arg_dynamic));
305 assert!(!*arg_dynamic.is_equal(&arg_plaintext));
306 assert!(!*arg_dynamic.is_equal(&arg_future));
307
308 assert!(*arg_plaintext.is_not_equal(&arg_future));
310 assert!(*arg_plaintext.is_not_equal(&arg_dynamic));
311 assert!(*arg_future.is_not_equal(&arg_plaintext));
312 assert!(*arg_future.is_not_equal(&arg_dynamic));
313 assert!(*arg_dynamic.is_not_equal(&arg_plaintext));
314 assert!(*arg_dynamic.is_not_equal(&arg_future));
315 }
316}