1mod await_;
17pub use await_::*;
18
19mod branch;
20pub use branch::*;
21
22mod contains;
23pub use contains::*;
24
25mod get;
26pub use get::*;
27
28mod get_or_use;
29pub use get_or_use::*;
30
31mod rand_chacha;
32pub use crate::command::rand_chacha::*;
33
34mod remove;
35pub use remove::*;
36
37mod position;
38pub use position::*;
39
40mod set;
41pub use set::*;
42
43use crate::{
44 CastType,
45 FinalizeOperation,
46 FinalizeRegistersState,
47 FinalizeStoreTrait,
48 Instruction,
49 Operand,
50 StackTrait,
51};
52use console::{
53 network::{error, prelude::*},
54 program::{Identifier, Register},
55};
56use snarkvm_synthesizer_error::FinalizeError;
57
58#[derive(Clone, PartialEq, Eq, Hash)]
59pub enum Command<N: Network> {
60 Instruction(Instruction<N>),
62 Await(Await<N>),
64 Contains(Contains<N>),
66 ContainsDynamic(ContainsDynamic<N>),
68 Get(Get<N>),
70 GetDynamic(GetDynamic<N>),
72 GetOrUse(GetOrUse<N>),
75 GetOrUseDynamic(GetOrUseDynamic<N>),
78 RandChaCha(RandChaCha<N>),
80 Remove(Remove<N>),
82 Set(Set<N>),
84 BranchEq(BranchEq<N>),
86 BranchNeq(BranchNeq<N>),
88 Position(Position<N>),
90}
91
92impl<N: Network> Command<N> {
93 pub fn is_async(&self) -> bool {
95 matches!(self, Command::Instruction(Instruction::Async(_)))
96 }
97
98 #[inline]
100 pub fn is_await(&self) -> bool {
101 matches!(self, Command::Await(_))
102 }
103
104 pub fn is_call(&self) -> bool {
106 matches!(self, Command::Instruction(Instruction::Call(_) | Instruction::CallDynamic(_)))
107 }
108
109 pub fn is_dynamic_call(&self) -> bool {
111 matches!(self, Command::Instruction(Instruction::CallDynamic(_)))
112 }
113
114 pub fn is_cast_to_record(&self) -> bool {
117 matches!(
118 self,
119 Command::Instruction(Instruction::Cast(cast))
120 if matches!(
121 cast.cast_type(),
122 CastType::Record(_) | CastType::ExternalRecord(_) | CastType::DynamicRecord
123 )
124 )
125 }
126
127 pub fn is_get_record_dynamic(&self) -> bool {
129 matches!(self, Command::Instruction(Instruction::GetRecordDynamic(_)))
130 }
131
132 pub fn is_instruction_for_record(&self) -> bool {
135 self.is_cast_to_record() || self.is_get_record_dynamic()
136 }
137
138 pub fn is_rand_chacha(&self) -> bool {
140 matches!(self, Command::RandChaCha(_))
141 }
142
143 pub fn is_write(&self) -> bool {
145 matches!(self, Command::Set(_) | Command::Remove(_))
146 }
147
148 pub fn branch_to(&self) -> Option<&Identifier<N>> {
151 match self {
152 Command::BranchEq(branch_eq) => Some(branch_eq.position()),
153 Command::BranchNeq(branch_neq) => Some(branch_neq.position()),
154 _ => None,
155 }
156 }
157
158 pub fn position(&self) -> Option<&Identifier<N>> {
161 match self {
162 Command::Position(position) => Some(position.name()),
163 _ => None,
164 }
165 }
166
167 pub fn destinations(&self) -> Vec<Register<N>> {
169 match self {
170 Command::Instruction(instruction) => instruction.destinations(),
171 Command::Contains(contains) => vec![contains.destination().clone()],
172 Command::ContainsDynamic(contains) => vec![contains.destination().clone()],
173 Command::Get(get) => vec![get.destination().clone()],
174 Command::GetDynamic(get) => vec![get.destination().clone()],
175 Command::GetOrUse(get_or_use) => vec![get_or_use.destination().clone()],
176 Command::GetOrUseDynamic(get_or_use) => vec![get_or_use.destination().clone()],
177 Command::RandChaCha(rand_chacha) => vec![rand_chacha.destination().clone()],
178 Command::Await(_)
179 | Command::BranchEq(_)
180 | Command::BranchNeq(_)
181 | Command::Position(_)
182 | Command::Remove(_)
183 | Command::Set(_) => vec![],
184 }
185 }
186
187 #[inline]
189 pub fn operands(&self) -> &[Operand<N>] {
190 match self {
191 Command::Instruction(c) => c.operands(),
192 Command::Await(c) => c.operands(),
193 Command::Contains(c) => c.operands(),
194 Command::ContainsDynamic(c) => c.operands(),
195 Command::Get(c) => c.operands(),
196 Command::GetDynamic(c) => c.operands(),
197 Command::GetOrUse(c) => c.operands(),
198 Command::GetOrUseDynamic(c) => c.operands(),
199 Command::RandChaCha(c) => c.operands(),
200 Command::Remove(c) => c.operands(),
201 Command::Set(c) => c.operands(),
202 Command::BranchEq(c) => c.operands(),
203 Command::BranchNeq(c) => c.operands(),
204 Command::Position(_) => Default::default(),
205 }
206 }
207
208 pub fn finalize(
210 &self,
211 stack: &impl StackTrait<N>,
212 store: &dyn FinalizeStoreTrait<N>,
213 registers: &mut impl FinalizeRegistersState<N>,
214 ) -> Result<Option<FinalizeOperation<N>>, FinalizeError> {
215 match self {
216 Command::Instruction(instruction) => instruction.finalize(stack, Some(store), registers).map(|_| None),
218 Command::Await(_) => Err(FinalizeError::Anyhow(anyhow!("`await` commands cannot be finalized directly."))),
220 Command::Contains(contains) => contains.finalize(stack, store, registers).map(|_| None).map_err(Into::into),
222 Command::ContainsDynamic(contains_dynamic) => {
224 contains_dynamic.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
225 }
226 Command::Get(get) => get.finalize(stack, store, registers).map(|_| None).map_err(Into::into),
228 Command::GetDynamic(get_dynamic) => {
230 get_dynamic.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
231 }
232 Command::GetOrUse(get_or_use) => {
234 get_or_use.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
235 }
236 Command::GetOrUseDynamic(get_or_use_dynamic) => {
238 get_or_use_dynamic.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
239 }
240 Command::RandChaCha(rand_chacha) => {
242 rand_chacha.finalize(stack, registers).map(|_| None).map_err(Into::into)
243 }
244 Command::Remove(remove) => remove.finalize(stack, store, registers).map_err(Into::into),
246 Command::Set(set) => set.finalize(stack, store, registers).map(Some).map_err(Into::into),
248 Command::BranchEq(_) | Command::BranchNeq(_) => {
250 Err(FinalizeError::Anyhow(anyhow!("`branch` commands cannot be finalized directly.")))
251 }
252 Command::Position(position) => position.finalize().map(|_| None).map_err(Into::into),
254 }
255 }
256
257 pub fn contains_external_struct(&self) -> bool {
259 match self {
260 Command::Instruction(c) => c.contains_external_struct(),
261 Command::Await(c) => c.contains_external_struct(),
262 Command::Contains(c) => c.contains_external_struct(),
263 Command::ContainsDynamic(_) => false,
265 Command::Get(c) => c.contains_external_struct(),
266 Command::GetDynamic(c) => c.destination_type().contains_external_struct(),
267 Command::GetOrUse(c) => c.contains_external_struct(),
268 Command::GetOrUseDynamic(c) => c.destination_type().contains_external_struct(),
269 Command::RandChaCha(c) => c.contains_external_struct(),
270 Command::Remove(c) => c.contains_external_struct(),
271 Command::Set(c) => c.contains_external_struct(),
272 Command::BranchEq(c) => c.contains_external_struct(),
273 Command::BranchNeq(c) => c.contains_external_struct(),
274 Command::Position(c) => c.contains_external_struct(),
275 }
276 }
277
278 pub fn contains_string_type(&self) -> bool {
280 self.operands().iter().any(|operand| operand.contains_string_type())
281 }
282
283 pub fn contains_identifier_type(&self) -> Result<bool> {
285 match self {
286 Command::Instruction(instruction) => instruction.contains_identifier_type(),
287 _ => Ok(false),
288 }
289 }
290
291 pub fn exceeds_max_array_size(&self, max_array_size: u32) -> bool {
293 match self {
294 Command::Instruction(instruction) => instruction.exceeds_max_array_size(max_array_size),
295 _ => false,
296 }
297 }
298}
299
300impl<N: Network> FromBytes for Command<N> {
301 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
303 let variant = u8::read_le(&mut reader)?;
305 match variant {
306 0 => Ok(Self::Instruction(Instruction::read_le(&mut reader)?)),
308 1 => Ok(Self::Await(Await::read_le(&mut reader)?)),
310 2 => Ok(Self::Contains(Contains::read_le(&mut reader)?)),
312 3 => Ok(Self::Get(Get::read_le(&mut reader)?)),
314 4 => Ok(Self::GetOrUse(GetOrUse::read_le(&mut reader)?)),
316 5 => Ok(Self::RandChaCha(RandChaCha::read_le(&mut reader)?)),
318 6 => Ok(Self::Remove(Remove::read_le(&mut reader)?)),
320 7 => Ok(Self::Set(Set::read_le(&mut reader)?)),
322 8 => Ok(Self::BranchEq(BranchEq::read_le(&mut reader)?)),
324 9 => Ok(Self::BranchNeq(BranchNeq::read_le(&mut reader)?)),
326 10 => Ok(Self::Position(Position::read_le(&mut reader)?)),
328 11 => Ok(Self::ContainsDynamic(ContainsDynamic::read_le(&mut reader)?)),
330 12 => Ok(Self::GetDynamic(GetDynamic::read_le(&mut reader)?)),
332 13 => Ok(Self::GetOrUseDynamic(GetOrUseDynamic::read_le(&mut reader)?)),
334 14.. => Err(error(format!("Invalid command variant: {variant}"))),
336 }
337 }
338}
339
340impl<N: Network> ToBytes for Command<N> {
341 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
343 match self {
344 Self::Instruction(instruction) => {
345 0u8.write_le(&mut writer)?;
347 instruction.write_le(&mut writer)
349 }
350 Self::Await(await_) => {
351 1u8.write_le(&mut writer)?;
353 await_.write_le(&mut writer)
355 }
356 Self::Contains(contains) => {
357 2u8.write_le(&mut writer)?;
359 contains.write_le(&mut writer)
361 }
362 Self::Get(get) => {
363 3u8.write_le(&mut writer)?;
365 get.write_le(&mut writer)
367 }
368 Self::GetOrUse(get_or_use) => {
369 4u8.write_le(&mut writer)?;
371 get_or_use.write_le(&mut writer)
373 }
374 Self::RandChaCha(rand_chacha) => {
375 5u8.write_le(&mut writer)?;
377 rand_chacha.write_le(&mut writer)
379 }
380 Self::Remove(remove) => {
381 6u8.write_le(&mut writer)?;
383 remove.write_le(&mut writer)
385 }
386 Self::Set(set) => {
387 7u8.write_le(&mut writer)?;
389 set.write_le(&mut writer)
391 }
392 Self::BranchEq(branch_eq) => {
393 8u8.write_le(&mut writer)?;
395 branch_eq.write_le(&mut writer)
397 }
398 Self::BranchNeq(branch_neq) => {
399 9u8.write_le(&mut writer)?;
401 branch_neq.write_le(&mut writer)
403 }
404 Self::Position(position) => {
405 10u8.write_le(&mut writer)?;
407 position.write_le(&mut writer)
409 }
410 Self::ContainsDynamic(contains_dynamic) => {
411 11u8.write_le(&mut writer)?;
413 contains_dynamic.write_le(&mut writer)
415 }
416 Self::GetDynamic(get_dynamic) => {
417 12u8.write_le(&mut writer)?;
419 get_dynamic.write_le(&mut writer)
421 }
422 Self::GetOrUseDynamic(get_or_use_dynamic) => {
423 13u8.write_le(&mut writer)?;
425 get_or_use_dynamic.write_le(&mut writer)
427 }
428 }
429 }
430}
431
432impl<N: Network> Parser for Command<N> {
433 #[inline]
435 fn parse(string: &str) -> ParserResult<Self> {
436 alt((
439 map(Await::parse, |await_| Self::Await(await_)),
440 map(ContainsDynamic::parse, |contains_dynamic| Self::ContainsDynamic(contains_dynamic)),
441 map(Contains::parse, |contains| Self::Contains(contains)),
442 map(GetOrUseDynamic::parse, |get_or_use_dynamic| Self::GetOrUseDynamic(get_or_use_dynamic)),
443 map(GetOrUse::parse, |get_or_use| Self::GetOrUse(get_or_use)),
444 map(GetDynamic::parse, |get_dynamic| Self::GetDynamic(get_dynamic)),
445 map(Get::parse, |get| Self::Get(get)),
446 map(RandChaCha::parse, |rand_chacha| Self::RandChaCha(rand_chacha)),
447 map(Remove::parse, |remove| Self::Remove(remove)),
448 map(Set::parse, |set| Self::Set(set)),
449 map(BranchEq::parse, |branch_eq| Self::BranchEq(branch_eq)),
450 map(BranchNeq::parse, |branch_neq| Self::BranchNeq(branch_neq)),
451 map(Position::parse, |position| Self::Position(position)),
452 map(Instruction::parse, |instruction| Self::Instruction(instruction)),
453 ))(string)
454 }
455}
456
457impl<N: Network> FromStr for Command<N> {
458 type Err = Error;
459
460 #[inline]
462 fn from_str(string: &str) -> Result<Self> {
463 match Self::parse(string) {
464 Ok((remainder, object)) => {
465 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
467 Ok(object)
469 }
470 Err(error) => bail!("Failed to parse string. {error}"),
471 }
472 }
473}
474
475impl<N: Network> Debug for Command<N> {
476 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
478 Display::fmt(self, f)
479 }
480}
481
482impl<N: Network> Display for Command<N> {
483 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
485 match self {
486 Self::Instruction(instruction) => Display::fmt(instruction, f),
487 Self::Await(await_) => Display::fmt(await_, f),
488 Self::Contains(contains) => Display::fmt(contains, f),
489 Self::ContainsDynamic(contains_dynamic) => Display::fmt(contains_dynamic, f),
490 Self::Get(get) => Display::fmt(get, f),
491 Self::GetDynamic(get_dynamic) => Display::fmt(get_dynamic, f),
492 Self::GetOrUse(get_or_use) => Display::fmt(get_or_use, f),
493 Self::GetOrUseDynamic(get_or_use_dynamic) => Display::fmt(get_or_use_dynamic, f),
494 Self::RandChaCha(rand_chacha) => Display::fmt(rand_chacha, f),
495 Self::Remove(remove) => Display::fmt(remove, f),
496 Self::Set(set) => Display::fmt(set, f),
497 Self::BranchEq(branch_eq) => Display::fmt(branch_eq, f),
498 Self::BranchNeq(branch_neq) => Display::fmt(branch_neq, f),
499 Self::Position(position) => Display::fmt(position, f),
500 }
501 }
502}
503
504#[cfg(test)]
505mod tests {
506 use super::*;
507 use console::network::MainnetV0;
508
509 type CurrentNetwork = MainnetV0;
510
511 #[test]
512 fn test_command_bytes() {
513 let expected = "decrement object[r0] by r1;";
515 Command::<CurrentNetwork>::parse(expected).unwrap_err();
516
517 let expected = "add r0 r1 into r2;";
519 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
520 let bytes = command.to_bytes_le().unwrap();
521 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
522
523 let expected = "increment object[r0] by r1;";
525 Command::<CurrentNetwork>::parse(expected).unwrap_err();
526
527 let expected = "await r1;";
529 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
530 let bytes = command.to_bytes_le().unwrap();
531 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
532
533 let expected = "contains object[r0] into r1;";
535 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
536 let bytes = command.to_bytes_le().unwrap();
537 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
538
539 let expected = "contains.dynamic r0 r1 r2[r3] into r4;";
541 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
542 let bytes = command.to_bytes_le().unwrap();
543 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
544
545 let expected = "get object[r0] into r1;";
547 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
548 let bytes = command.to_bytes_le().unwrap();
549 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
550
551 let expected = "get.dynamic r0 r1 r2[r3] into r4 as field;";
553 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
554 let bytes = command.to_bytes_le().unwrap();
555 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
556
557 let expected = "get.or_use object[r0] r1 into r2;";
559 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
560 let bytes = command.to_bytes_le().unwrap();
561 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
562
563 let expected = "get.or_use.dynamic r0 r1 r2[r3] r4 into r5 as credits;";
565 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
566 let bytes = command.to_bytes_le().unwrap();
567 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
568
569 let expected = "rand.chacha into r1 as field;";
571 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
572 let bytes = command.to_bytes_le().unwrap();
573 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
574
575 let expected = "rand.chacha r0 r1 into r2 as group;";
577 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
578 let bytes = command.to_bytes_le().unwrap();
579 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
580
581 let expected = "remove object[r0];";
583 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
584 let bytes = command.to_bytes_le().unwrap();
585 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
586
587 let expected = "set r0 into object[r1];";
589 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
590 let bytes = command.to_bytes_le().unwrap();
591 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
592
593 let expected = "branch.eq r0 r1 to exit;";
595 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
596 let bytes = command.to_bytes_le().unwrap();
597 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
598
599 let expected = "branch.neq r2 r3 to start;";
601 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
602 let bytes = command.to_bytes_le().unwrap();
603 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
604
605 let expected = "position exit;";
607 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
608 let bytes = command.to_bytes_le().unwrap();
609 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
610 }
611
612 #[test]
613 fn test_command_parse() {
614 let expected = "decrement object[r0] by r1;";
616 Command::<CurrentNetwork>::parse(expected).unwrap_err();
617
618 let expected = "add r0 r1 into r2;";
620 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
621 assert_eq!(Command::Instruction(Instruction::from_str(expected).unwrap()), command);
622 assert_eq!(expected, command.to_string());
623
624 let expected = "increment object[r0] by r1;";
626 Command::<CurrentNetwork>::parse(expected).unwrap_err();
627
628 let expected = "contains object[r0] into r1;";
630 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
631 assert_eq!(Command::Contains(Contains::from_str(expected).unwrap()), command);
632 assert_eq!(expected, command.to_string());
633
634 let expected = "contains.dynamic r0 r1 r2[r3] into r4;";
636 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
637 assert_eq!(Command::ContainsDynamic(ContainsDynamic::from_str(expected).unwrap()), command);
638 assert_eq!(expected, command.to_string());
639
640 let expected = "get object[r0] into r1;";
642 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
643 assert_eq!(Command::Get(Get::from_str(expected).unwrap()), command);
644 assert_eq!(expected, command.to_string());
645
646 let expected = "get.dynamic r0 r1 r2[r3] into r4 as u8;";
648 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
649 assert_eq!(Command::GetDynamic(GetDynamic::from_str(expected).unwrap()), command);
650 assert_eq!(expected, command.to_string());
651
652 let expected = "get.or_use object[r0] r1 into r2;";
654 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
655 assert_eq!(Command::GetOrUse(GetOrUse::from_str(expected).unwrap()), command);
656 assert_eq!(expected, command.to_string());
657
658 let expected = "get.or_use.dynamic r0 r1 r2[r3] r4 into r5 as Foo;";
660 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
661 assert_eq!(Command::GetOrUseDynamic(GetOrUseDynamic::from_str(expected).unwrap()), command);
662 assert_eq!(expected, command.to_string());
663
664 let expected = "rand.chacha into r1 as field;";
666 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
667 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
668 assert_eq!(expected, command.to_string());
669
670 let expected = "rand.chacha r0 r1 into r2 as group;";
672 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
673 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
674 assert_eq!(expected, command.to_string());
675
676 let expected = "remove object[r0];";
678 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
679 assert_eq!(Command::Remove(Remove::from_str(expected).unwrap()), command);
680 assert_eq!(expected, command.to_string());
681
682 let expected = "set r0 into object[r1];";
684 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
685 assert_eq!(Command::Set(Set::from_str(expected).unwrap()), command);
686 assert_eq!(expected, command.to_string());
687
688 let expected = "branch.eq r0 r1 to exit;";
690 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
691 assert_eq!(Command::BranchEq(BranchEq::from_str(expected).unwrap()), command);
692 assert_eq!(expected, command.to_string());
693
694 let expected = "branch.neq r2 r3 to start;";
696 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
697 assert_eq!(Command::BranchNeq(BranchNeq::from_str(expected).unwrap()), command);
698 assert_eq!(expected, command.to_string());
699
700 let expected = "position exit;";
702 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
703 assert_eq!(Command::Position(Position::from_str(expected).unwrap()), command);
704 assert_eq!(expected, command.to_string());
705 }
706}