1use crate::internal_prelude::*;
2use core::ops::ControlFlow;
3
4use traversal::*;
5use ManifestInstructionEffect as Effect;
6
7pub struct StaticManifestInterpreter<'a, M: ReadableManifest + ?Sized> {
13 validation_ruleset: ValidationRuleset,
14 manifest: &'a M,
15 location: ManifestLocation,
16 registered_blobs: IndexSet<ManifestBlobRef>,
17 bucket_state: Vec<BucketState<'a>>,
18 proof_state: Vec<ProofState<'a>>,
19 address_reservation_state: Vec<AddressReservationState<'a>>,
20 named_address_state: Vec<NamedAddressState<'a>>,
21 intent_state: Vec<IntentState<'a>>,
22 next_instruction_requirement: NextInstructionRequirement,
23}
24
25impl<'a, M: ReadableManifest + ?Sized> StaticManifestInterpreter<'a, M> {
48 pub fn new(validation_ruleset: ValidationRuleset, manifest: &'a M) -> Self {
49 Self {
50 validation_ruleset,
51 manifest,
52 location: ManifestLocation::Preamble,
53 registered_blobs: Default::default(),
54 bucket_state: Default::default(),
55 proof_state: Default::default(),
56 address_reservation_state: Default::default(),
57 named_address_state: Default::default(),
58 intent_state: Default::default(),
59 next_instruction_requirement: NextInstructionRequirement::None,
60 }
61 }
62
63 pub fn validate(self) -> Result<(), ManifestValidationError> {
64 self.validate_and_apply_visitor(&mut ())
65 }
66
67 pub fn validate_and_apply_visitor<V: ManifestInterpretationVisitor>(
68 self,
69 visitor: &mut V,
70 ) -> Result<(), V::Output> {
71 match self.interpret_internal(visitor) {
73 ControlFlow::Continue(()) => Ok(()),
74 ControlFlow::Break(err) => Err(err),
75 }
76 }
77
78 #[must_use]
79 fn interpret_internal<V: ManifestInterpretationVisitor>(
80 mut self,
81 visitor: &mut V,
82 ) -> ControlFlow<V::Output> {
83 self.handle_preallocated_addresses(visitor, self.manifest.get_preallocated_addresses())?;
84 self.handle_child_subintents(visitor, self.manifest.get_child_subintent_hashes())?;
85 self.handle_blobs(visitor, self.manifest.get_blobs())?;
86 for (index, instruction_effect) in self.manifest.iter_instruction_effects().enumerate() {
87 self.handle_instruction(visitor, index, instruction_effect)?;
88 }
89 self.verify_final_instruction::<V>()?;
90 self.handle_wrap_up(visitor)?;
91 ControlFlow::Continue(())
92 }
93
94 #[must_use]
95 fn handle_preallocated_addresses<V: ManifestInterpretationVisitor>(
96 &mut self,
97 visitor: &mut V,
98 preallocated_addresses: &'a [PreAllocatedAddress],
99 ) -> ControlFlow<V::Output> {
100 for preallocated_address in preallocated_addresses.iter() {
101 let _ = self.handle_new_address_reservation(
102 visitor,
103 &preallocated_address.blueprint_id.package_address,
104 preallocated_address.blueprint_id.blueprint_name.as_str(),
105 Some(&preallocated_address.address),
106 )?;
107 }
108 ControlFlow::Continue(())
109 }
110
111 #[must_use]
112 fn handle_child_subintents<V: ManifestInterpretationVisitor>(
113 &mut self,
114 visitor: &mut V,
115 child_subintents: impl Iterator<Item = &'a ChildSubintentSpecifier>,
116 ) -> ControlFlow<V::Output> {
117 for child_subintent in child_subintents {
118 self.handle_new_intent(
119 visitor,
120 IntentHash::Subintent(child_subintent.hash),
121 IntentType::Child,
122 )?;
123 }
124 ControlFlow::Continue(())
125 }
126
127 #[must_use]
128 fn handle_blobs<'b, V: ManifestInterpretationVisitor>(
129 &mut self,
130 visitor: &mut V,
131 blobs: impl Iterator<Item = (&'b Hash, &'b Vec<u8>)>,
132 ) -> ControlFlow<V::Output> {
133 for (hash, content) in blobs {
134 if !self.registered_blobs.insert(ManifestBlobRef(hash.0)) {
135 if self.validation_ruleset.validate_no_duplicate_blobs {
136 return ControlFlow::Break(
137 ManifestValidationError::DuplicateBlob(ManifestBlobRef(hash.0)).into(),
138 );
139 }
140 }
141 visitor.on_register_blob(OnRegisterBlob {
142 blob_ref: ManifestBlobRef(hash.0),
143 content: content.as_ref(),
144 })?;
145 }
146 ControlFlow::Continue(())
147 }
148
149 #[must_use]
150 fn handle_instruction<V: ManifestInterpretationVisitor>(
151 &mut self,
152 visitor: &mut V,
153 index: usize,
154 effect: ManifestInstructionEffect<'a>,
155 ) -> ControlFlow<V::Output> {
156 self.location = ManifestLocation::Instruction { index };
157
158 match self
159 .next_instruction_requirement
160 .handle_next_instruction(effect)
161 {
162 Ok(()) => {}
163 Err(error) => return ControlFlow::Break(error.into()),
164 }
165
166 visitor.on_start_instruction(OnStartInstruction { index })?;
167
168 match effect {
169 Effect::CreateBucket { source_amount } => {
170 self.handle_new_bucket(visitor, source_amount)?;
171 }
172 Effect::CreateProof { source_amount } => {
173 self.handle_new_proof(visitor, source_amount)?;
174 }
175 Effect::ConsumeBucket {
176 consumed_bucket,
177 destination,
178 } => {
179 self.consume_bucket(visitor, consumed_bucket, destination)?;
180 }
181 Effect::ConsumeProof {
182 consumed_proof,
183 destination,
184 } => {
185 self.consume_proof(visitor, consumed_proof, destination)?;
186 }
187 Effect::CloneProof { cloned_proof } => {
188 self.handle_cloned_proof(visitor, cloned_proof)?;
189 }
190 Effect::DropManyProofs {
191 drop_all_named_proofs,
192 drop_all_authzone_signature_proofs,
193 drop_all_authzone_non_signature_proofs,
194 } => {
195 if drop_all_named_proofs {
196 let proofs_to_drop: Vec<_> = self
197 .proof_state
198 .iter()
199 .enumerate()
200 .filter_map(|(index, p)| match p.consumed_at {
201 Some(_) => None,
202 None => Some(ManifestProof(index as u32)),
203 })
204 .collect();
205 for proof in proofs_to_drop {
206 self.consume_proof(visitor, proof, ProofDestination::Drop)?;
207 }
208 }
209 if drop_all_authzone_signature_proofs || drop_all_authzone_non_signature_proofs {
210 visitor.on_drop_authzone_proofs(OnDropAuthZoneProofs {
211 drop_all_signature_proofs: drop_all_authzone_signature_proofs,
212 drop_all_non_signature_proofs: drop_all_authzone_non_signature_proofs,
213 })?;
214 }
215 }
216 Effect::Invocation { kind, args } => {
217 self.handle_invocation(visitor, kind, args)?;
218 }
219 Effect::CreateAddressAndReservation {
220 package_address,
221 blueprint_name,
222 } => {
223 let reservation = self.handle_new_address_reservation(
224 visitor,
225 package_address,
226 blueprint_name,
227 None,
228 )?;
229 self.handle_new_named_address(
230 visitor,
231 Some(reservation),
232 package_address,
233 blueprint_name,
234 )?;
235 }
236 Effect::ResourceAssertion { assertion } => {
237 self.handle_resource_assertion(visitor, assertion)?;
238 }
239 Effect::Verification {
240 verification,
241 access_rule,
242 } => {
243 self.handle_verification(visitor, verification, access_rule)?;
244 }
245 }
246
247 visitor.on_end_instruction(OnEndInstruction { index, effect })
248 }
249
250 #[must_use]
251 fn verify_final_instruction<V: ManifestInterpretationVisitor>(
252 &mut self,
253 ) -> ControlFlow<V::Output> {
254 if !self.manifest.is_subintent() {
255 return ControlFlow::Continue(());
256 }
257 let instruction_count = self.manifest.instruction_count();
258 let last_instruction_index = if instruction_count > 0 {
259 instruction_count - 1
260 } else {
261 return ControlFlow::Break(
262 ManifestValidationError::SubintentDoesNotEndWithYieldToParent.into(),
263 );
264 };
265 match self.manifest.instruction_effect(last_instruction_index) {
266 ManifestInstructionEffect::Invocation {
267 kind: InvocationKind::YieldToParent,
268 ..
269 } => ControlFlow::Continue(()),
270 _ => ControlFlow::Break(
271 ManifestValidationError::SubintentDoesNotEndWithYieldToParent.into(),
272 ),
273 }
274 }
275
276 #[must_use]
277 fn handle_wrap_up<V: ManifestInterpretationVisitor>(
278 &mut self,
279 visitor: &mut V,
280 ) -> ControlFlow<V::Output> {
281 match self.next_instruction_requirement.validate_at_end() {
282 Ok(()) => {}
283 Err(error) => return ControlFlow::Break(error.into()),
284 }
285 if self.validation_ruleset.validate_no_dangling_nodes {
286 for (index, state) in self.bucket_state.iter().enumerate() {
287 if state.consumed_at.is_none() {
288 return ControlFlow::Break(
289 ManifestValidationError::DanglingBucket(
290 ManifestBucket(index as u32),
291 format!("{state:?}"),
292 )
293 .into(),
294 );
295 }
296 }
297 for (index, state) in self.address_reservation_state.iter().enumerate() {
298 if state.consumed_at.is_none() {
299 return ControlFlow::Break(
300 ManifestValidationError::DanglingAddressReservation(
301 ManifestAddressReservation(index as u32),
302 format!("{state:?}"),
303 )
304 .into(),
305 );
306 }
307 }
308 }
309 visitor.on_finish(OnFinish)?;
310
311 ControlFlow::Continue(())
312 }
313
314 #[must_use]
315 fn handle_invocation<V: ManifestInterpretationVisitor>(
316 &mut self,
317 visitor: &mut V,
318 invocation_kind: InvocationKind<'a>,
319 args: &'a ManifestValue,
320 ) -> ControlFlow<V::Output> {
321 let yields_across_intent = match invocation_kind {
322 InvocationKind::Method { address, .. } => {
323 if self
324 .validation_ruleset
325 .validate_dynamic_address_in_command_part
326 {
327 match address {
328 ManifestGlobalAddress::Static(_) => {}
329 ManifestGlobalAddress::Named(named_address) => {
330 self.get_existing_named_address::<V>(*named_address)?;
332 }
333 }
334 }
335 false
336 }
337 InvocationKind::Function { address, .. } => {
338 if self
339 .validation_ruleset
340 .validate_dynamic_address_in_command_part
341 {
342 match address {
343 ManifestPackageAddress::Static(_) => {}
344 ManifestPackageAddress::Named(named_address) => {
345 self.get_existing_named_address::<V>(*named_address)?;
347 }
348 }
349 }
350 false
351 }
352 InvocationKind::DirectMethod { .. } => false,
353 InvocationKind::YieldToParent => {
354 if !self.manifest.is_subintent() {
355 return ControlFlow::Break(
356 ManifestValidationError::InstructionNotSupportedInTransactionIntent.into(),
357 );
358 }
359 true
360 }
361 InvocationKind::YieldToChild { child_index } => {
362 let index = child_index.0 as usize;
363 if index >= self.manifest.get_child_subintent_hashes().len() {
364 return ControlFlow::Break(
365 ManifestValidationError::ChildIntentNotRegistered(child_index).into(),
366 );
367 }
368 true
369 }
370 };
371 let encoded = match manifest_encode(args) {
372 Ok(encoded) => encoded,
373 Err(error) => {
374 return ControlFlow::Break(ManifestValidationError::ArgsEncodeError(error).into())
375 }
376 };
377 let mut traverser = ManifestTraverser::new(
378 &encoded,
379 ExpectedStart::PayloadPrefix(MANIFEST_SBOR_V1_PAYLOAD_PREFIX),
380 VecTraverserConfig {
381 max_depth: MANIFEST_SBOR_V1_MAX_DEPTH,
382 check_exact_end: true,
383 },
384 );
385 loop {
386 let event = traverser.next_event();
387 match event.event {
388 TraversalEvent::ContainerStart(_) => {}
389 TraversalEvent::ContainerEnd(_) => {}
390 TraversalEvent::TerminalValue(r) => {
391 if let traversal::TerminalValueRef::Custom(c) = r {
392 match c.0 {
393 ManifestCustomValue::Address(address) => {
394 match address {
395 ManifestAddress::Static(_) => {}
396 ManifestAddress::Named(named_address) => {
397 self.get_existing_named_address::<V>(named_address)?;
399 }
400 }
401 }
402 ManifestCustomValue::Bucket(bucket) => {
403 self.consume_bucket(
404 visitor,
405 bucket,
406 BucketDestination::Invocation(invocation_kind),
407 )?;
408 }
409 ManifestCustomValue::Proof(proof) => {
410 if yields_across_intent {
411 return ControlFlow::Break(
412 ManifestValidationError::ProofCannotBePassedToAnotherIntent
413 .into(),
414 );
415 }
416 self.consume_proof(
417 visitor,
418 proof,
419 ProofDestination::Invocation(invocation_kind),
420 )?;
421 }
422 ManifestCustomValue::Expression(expression) => {
423 visitor.on_pass_expression(OnPassExpression {
424 expression,
425 destination: ExpressionDestination::Invocation(invocation_kind),
426 })?;
427 }
428 ManifestCustomValue::Blob(blob_ref) => {
429 if self.validation_ruleset.validate_blob_refs {
430 if !self.registered_blobs.contains(&blob_ref) {
431 return ControlFlow::Break(
432 ManifestValidationError::BlobNotRegistered(blob_ref)
433 .into(),
434 );
435 }
436 }
437 visitor.on_pass_blob(OnPassBlob {
438 blob_ref,
439 destination: BlobDestination::Invocation(invocation_kind),
440 })?;
441 }
442 ManifestCustomValue::AddressReservation(reservation) => {
443 self.consume_address_reservation(
444 visitor,
445 reservation,
446 AddressReservationDestination::Invocation(invocation_kind),
447 )?;
448 }
449 ManifestCustomValue::Decimal(_)
450 | ManifestCustomValue::NonFungibleLocalId(_)
451 | ManifestCustomValue::PreciseDecimal(_) => {}
452 }
453 }
454 }
455 TraversalEvent::TerminalValueBatch(_) => {}
456 TraversalEvent::End => {
457 break;
458 }
459 TraversalEvent::DecodeError(error) => {
460 return ControlFlow::Break(
461 ManifestValidationError::ArgsDecodeError(error).into(),
462 );
463 }
464 }
465 }
466 ControlFlow::Continue(())
467 }
468
469 #[must_use]
470 fn handle_resource_assertion<V: ManifestInterpretationVisitor>(
471 &mut self,
472 visitor: &mut V,
473 assertion: ResourceAssertion<'a>,
474 ) -> ControlFlow<V::Output> {
475 if self.validation_ruleset.validate_resource_assertions {
476 match assertion {
477 ResourceAssertion::Worktop(WorktopAssertion::ResourceNonZeroAmount { .. }) => {
478 }
480 ResourceAssertion::Worktop(WorktopAssertion::ResourceAtLeastAmount {
481 amount,
482 ..
483 }) => {
484 if amount.is_negative() {
485 return ControlFlow::Break(
486 ManifestValidationError::InvalidResourceConstraint.into(),
487 );
488 }
489 }
490 ResourceAssertion::Worktop(WorktopAssertion::ResourceAtLeastNonFungibles {
491 resource_address,
492 ..
493 }) => {
494 if resource_address.is_fungible() {
495 return ControlFlow::Break(
496 ManifestValidationError::InvalidResourceConstraint.into(),
497 );
498 }
499 }
500 ResourceAssertion::Worktop(WorktopAssertion::ResourcesOnly { constraints })
501 | ResourceAssertion::Worktop(WorktopAssertion::ResourcesInclude { constraints }) => {
502 if !constraints.is_valid() {
503 return ControlFlow::Break(
504 ManifestValidationError::InvalidResourceConstraint.into(),
505 );
506 }
507 }
508 ResourceAssertion::NextCall(NextCallAssertion::ReturnsOnly { constraints })
509 | ResourceAssertion::NextCall(NextCallAssertion::ReturnsInclude { constraints }) => {
510 if !constraints.is_valid() {
511 return ControlFlow::Break(
512 ManifestValidationError::InvalidResourceConstraint.into(),
513 );
514 }
515 self.next_instruction_requirement =
516 NextInstructionRequirement::RequiredInvocationDueToNextCallAssertion;
517 }
518 ResourceAssertion::Bucket(BucketAssertion::Contents { bucket, constraint }) => {
519 let state = self.get_existing_bucket::<V>(bucket)?;
521 let resource_address = state.source_amount.resource_address();
522 if !constraint.is_valid_for(resource_address) {
523 return ControlFlow::Break(
524 ManifestValidationError::InvalidResourceConstraint.into(),
525 );
526 }
527 }
528 }
529 }
530 visitor.on_resource_assertion(OnResourceAssertion { assertion })
531 }
532
533 #[must_use]
534 fn handle_verification<V: ManifestInterpretationVisitor>(
535 &mut self,
536 visitor: &mut V,
537 verification_kind: VerificationKind,
538 access_rule: &AccessRule,
539 ) -> ControlFlow<V::Output> {
540 match verification_kind {
541 VerificationKind::Parent => {
542 if !self.manifest.is_subintent() {
543 return ControlFlow::Break(
544 ManifestValidationError::InstructionNotSupportedInTransactionIntent.into(),
545 );
546 }
547 }
548 }
549 visitor.on_verification(OnVerification {
550 kind: verification_kind,
551 access_rule,
552 })?;
553 ControlFlow::Continue(())
554 }
555
556 #[must_use]
557 fn handle_new_bucket<V: ManifestInterpretationVisitor>(
558 &mut self,
559 visitor: &mut V,
560 source_amount: BucketSourceAmount<'a>,
561 ) -> ControlFlow<V::Output> {
562 let new_bucket = ManifestBucket(self.bucket_state.len() as u32);
563 let state = BucketState {
564 name: self
565 .manifest
566 .get_known_object_names_ref()
567 .known_bucket_name(new_bucket),
568 created_at: self.location,
569 proof_locks: 0,
570 consumed_at: None,
571 source_amount,
572 };
573 visitor.on_new_bucket(OnNewBucket {
574 bucket: new_bucket,
575 state: &state,
576 })?;
577 self.bucket_state.push(state);
578 ControlFlow::Continue(())
579 }
580
581 #[must_use]
582 fn get_existing_bucket<V: ManifestInterpretationVisitor>(
583 &mut self,
584 bucket: ManifestBucket,
585 ) -> ControlFlow<V::Output, &mut BucketState<'a>> {
586 match self.bucket_state.get_mut(bucket.0 as usize) {
587 Some(state) => {
588 if state.consumed_at.is_some() {
589 ControlFlow::Break(
590 ManifestValidationError::BucketAlreadyUsed(bucket, format!("{state:?}"))
591 .into(),
592 )
593 } else {
594 ControlFlow::Continue(state)
595 }
596 }
597 None => ControlFlow::Break(ManifestValidationError::BucketNotYetCreated(bucket).into()),
598 }
599 }
600
601 #[must_use]
602 fn consume_bucket<V: ManifestInterpretationVisitor>(
603 &mut self,
604 visitor: &mut V,
605 bucket: ManifestBucket,
606 destination: BucketDestination<'a>,
607 ) -> ControlFlow<V::Output> {
608 let check_proof_locks = self.validation_ruleset.validate_bucket_proof_lock;
609 let location = self.location;
610 let state = self.get_existing_bucket::<V>(bucket)?;
611 if check_proof_locks && state.proof_locks > 0 {
612 return ControlFlow::Break(
613 ManifestValidationError::BucketConsumedWhilstLockedByProof(
614 bucket,
615 format!("{state:?}"),
616 )
617 .into(),
618 );
619 }
620 state.consumed_at = Some(location);
621 visitor.on_consume_bucket(OnConsumeBucket {
622 bucket,
623 state: &state,
624 destination,
625 })
626 }
627
628 #[must_use]
629 fn handle_new_proof<V: ManifestInterpretationVisitor>(
630 &mut self,
631 visitor: &mut V,
632 source_amount: ProofSourceAmount<'a>,
633 ) -> ControlFlow<V::Output> {
634 match source_amount.proof_kind() {
635 ProofKind::BucketProof(bucket) => {
636 self.get_existing_bucket::<V>(bucket)?.proof_locks += 1;
637 }
638 ProofKind::AuthZoneProof => {}
639 }
640 let new_proof = ManifestProof(self.proof_state.len() as u32);
641 let state = ProofState {
642 name: self
643 .manifest
644 .get_known_object_names_ref()
645 .known_proof_name(new_proof),
646 created_at: self.location,
647 consumed_at: None,
648 source_amount,
649 };
650 visitor.on_new_proof(OnNewProof {
651 proof: new_proof,
652 state: &state,
653 })?;
654 self.proof_state.push(state);
655 ControlFlow::Continue(())
656 }
657
658 #[must_use]
659 fn get_existing_proof<V: ManifestInterpretationVisitor>(
660 &mut self,
661 proof: ManifestProof,
662 ) -> ControlFlow<V::Output, &mut ProofState<'a>> {
663 match self.proof_state.get_mut(proof.0 as usize) {
664 Some(state) => {
665 if state.consumed_at.is_some() {
666 ControlFlow::Break(
667 ManifestValidationError::ProofAlreadyUsed(proof, format!("{state:?}"))
668 .into(),
669 )
670 } else {
671 ControlFlow::Continue(state)
672 }
673 }
674 None => ControlFlow::Break(ManifestValidationError::ProofNotYetCreated(proof).into()),
675 }
676 }
677
678 #[must_use]
679 fn handle_cloned_proof<V: ManifestInterpretationVisitor>(
680 &mut self,
681 visitor: &mut V,
682 cloned_proof: ManifestProof,
683 ) -> ControlFlow<V::Output> {
684 let source_amount = self.get_existing_proof::<V>(cloned_proof)?.source_amount;
685 self.handle_new_proof(visitor, source_amount)
686 }
687
688 #[must_use]
689 fn consume_proof<V: ManifestInterpretationVisitor>(
690 &mut self,
691 visitor: &mut V,
692 proof: ManifestProof,
693 destination: ProofDestination<'a>,
694 ) -> ControlFlow<V::Output> {
695 let location = self.location;
696 let state = self.get_existing_proof::<V>(proof)?;
697 state.consumed_at = Some(location);
698 visitor.on_consume_proof(OnConsumeProof {
699 proof,
700 state: &state,
701 destination,
702 })?;
703 let source_amount = state.source_amount;
704 match source_amount.proof_kind() {
705 ProofKind::BucketProof(bucket) => {
706 self.get_existing_bucket::<V>(bucket)?.proof_locks -= 1;
707 }
708 ProofKind::AuthZoneProof => {}
709 }
710 ControlFlow::Continue(())
711 }
712
713 #[must_use]
714 fn handle_new_address_reservation<V: ManifestInterpretationVisitor>(
715 &mut self,
716 visitor: &mut V,
717 package_address: &'a PackageAddress,
718 blueprint_name: &'a str,
719 preallocated_address: Option<&'a GlobalAddress>,
720 ) -> ControlFlow<V::Output, ManifestAddressReservation> {
721 let new_address_reservation =
722 ManifestAddressReservation(self.address_reservation_state.len() as u32);
723 let state = AddressReservationState {
724 name: self
725 .manifest
726 .get_known_object_names_ref()
727 .known_address_reservation_name(new_address_reservation),
728 package_address,
729 blueprint_name,
730 preallocated_address,
731 created_at: self.location,
732 consumed_at: None,
733 };
734 visitor.on_new_address_reservation(OnNewAddressReservation {
735 address_reservation: new_address_reservation,
736 state: &state,
737 })?;
738 self.address_reservation_state.push(state);
739 ControlFlow::Continue(new_address_reservation)
740 }
741
742 #[must_use]
743 fn get_existing_address_reservation<V: ManifestInterpretationVisitor>(
744 &mut self,
745 address_reservation: ManifestAddressReservation,
746 ) -> ControlFlow<V::Output, &mut AddressReservationState<'a>> {
747 match self
748 .address_reservation_state
749 .get_mut(address_reservation.0 as usize)
750 {
751 Some(state) => {
752 if state.consumed_at.is_some() {
753 ControlFlow::Break(
754 ManifestValidationError::AddressReservationAlreadyUsed(
755 address_reservation,
756 format!("{state:?}"),
757 )
758 .into(),
759 )
760 } else {
761 ControlFlow::Continue(state)
762 }
763 }
764 None => ControlFlow::Break(
765 ManifestValidationError::AddressReservationNotYetCreated(address_reservation)
766 .into(),
767 ),
768 }
769 }
770
771 #[must_use]
772 fn consume_address_reservation<V: ManifestInterpretationVisitor>(
773 &mut self,
774 visitor: &mut V,
775 address_reservation: ManifestAddressReservation,
776 destination: AddressReservationDestination<'a>,
777 ) -> ControlFlow<V::Output> {
778 let location = self.location;
779 let state = self.get_existing_address_reservation::<V>(address_reservation)?;
780 state.consumed_at = Some(location);
781 visitor.on_consume_address_reservation(OnConsumeAddressReservation {
782 address_reservation,
783 state: &state,
784 destination,
785 })
786 }
787
788 #[must_use]
789 fn handle_new_named_address<V: ManifestInterpretationVisitor>(
790 &mut self,
791 visitor: &mut V,
792 associated_reservation: Option<ManifestAddressReservation>,
793 package_address: &PackageAddress,
794 blueprint_name: &str,
795 ) -> ControlFlow<V::Output> {
796 let new_named_address = ManifestNamedAddress(self.named_address_state.len() as u32);
797 let state = NamedAddressState {
798 name: self
799 .manifest
800 .get_known_object_names_ref()
801 .known_address_name(new_named_address),
802 associated_reservation,
803 created_at: self.location,
804 };
805 visitor.on_new_named_address(OnNewNamedAddress {
806 named_address: new_named_address,
807 state: &state,
808 package_address,
809 blueprint_name,
810 })?;
811 self.named_address_state.push(state);
812 ControlFlow::Continue(())
813 }
814
815 #[must_use]
816 fn get_existing_named_address<V: ManifestInterpretationVisitor>(
817 &mut self,
818 named_address: ManifestNamedAddress,
819 ) -> ControlFlow<V::Output, &mut NamedAddressState<'a>> {
820 match self.named_address_state.get_mut(named_address.0 as usize) {
821 Some(state) => ControlFlow::Continue(state),
822 None => ControlFlow::Break(
823 ManifestValidationError::NamedAddressNotYetCreated(named_address).into(),
824 ),
825 }
826 }
827
828 #[must_use]
829 fn handle_new_intent<V: ManifestInterpretationVisitor>(
830 &mut self,
831 visitor: &mut V,
832 intent_hash: IntentHash,
833 intent_type: IntentType,
834 ) -> ControlFlow<V::Output> {
835 let new_intent = ManifestNamedIntent(self.intent_state.len() as u32);
836 let state = IntentState {
837 name: self
838 .manifest
839 .get_known_object_names_ref()
840 .known_intent_name(new_intent),
841 intent_hash,
842 intent_type,
843 created_at: self.location,
844 };
845 visitor.on_new_intent(OnNewIntent {
846 intent: new_intent,
847 state: &state,
848 })?;
849 self.intent_state.push(state);
850 ControlFlow::Continue(())
851 }
852}
853
854#[derive(Debug, Copy, Clone, PartialEq, Eq)]
855pub enum ManifestLocation {
856 Preamble,
857 Instruction { index: usize },
858}
859
860#[derive(Debug, Clone, PartialEq, Eq)]
861pub struct BucketState<'a> {
862 pub name: Option<&'a str>,
863 pub source_amount: BucketSourceAmount<'a>,
864 pub created_at: ManifestLocation,
865 pub proof_locks: u32,
866 pub consumed_at: Option<ManifestLocation>,
867}
868
869#[derive(Debug, Clone, PartialEq, Eq)]
870pub struct ProofState<'a> {
871 pub name: Option<&'a str>,
872 pub source_amount: ProofSourceAmount<'a>,
873 pub created_at: ManifestLocation,
874 pub consumed_at: Option<ManifestLocation>,
875}
876
877#[derive(Debug, Clone, PartialEq, Eq)]
878pub struct AddressReservationState<'a> {
879 pub name: Option<&'a str>,
880 pub package_address: &'a PackageAddress,
881 pub blueprint_name: &'a str,
882 pub preallocated_address: Option<&'a GlobalAddress>,
883 pub created_at: ManifestLocation,
884 pub consumed_at: Option<ManifestLocation>,
885}
886
887#[derive(Debug, Clone, PartialEq, Eq)]
888pub struct NamedAddressState<'a> {
889 pub name: Option<&'a str>,
890 pub associated_reservation: Option<ManifestAddressReservation>,
891 pub created_at: ManifestLocation,
892}
893
894#[derive(Debug, Clone, PartialEq, Eq)]
895pub struct IntentState<'a> {
896 pub name: Option<&'a str>,
897 pub intent_hash: IntentHash,
898 pub intent_type: IntentType,
899 pub created_at: ManifestLocation,
900}
901
902#[derive(Debug, Clone, PartialEq, Eq)]
903pub enum IntentType {
904 Child,
905}
906
907enum NextInstructionRequirement {
908 None,
909 RequiredInvocationDueToNextCallAssertion,
910}
911
912impl NextInstructionRequirement {
913 fn handle_next_instruction(
914 &mut self,
915 effect: ManifestInstructionEffect,
916 ) -> Result<(), ManifestValidationError> {
917 match self {
918 NextInstructionRequirement::None => Ok(()),
919 NextInstructionRequirement::RequiredInvocationDueToNextCallAssertion => {
920 if matches!(effect, ManifestInstructionEffect::Invocation { .. }) {
921 *self = NextInstructionRequirement::None;
922 Ok(())
923 } else {
924 Err(ManifestValidationError::InstructionFollowingNextCallAssertionWasNotInvocation)
925 }
926 }
927 }
928 }
929
930 fn validate_at_end(&self) -> Result<(), ManifestValidationError> {
931 match self {
932 NextInstructionRequirement::None => Ok(()),
933 NextInstructionRequirement::RequiredInvocationDueToNextCallAssertion => {
934 Err(ManifestValidationError::ManifestEndedWhilstExpectingNextCallAssertion)
935 }
936 }
937 }
938}
939
940pub struct ValidationRuleset {
945 pub validate_no_duplicate_blobs: bool,
946 pub validate_blob_refs: bool,
947 pub validate_bucket_proof_lock: bool,
948 pub validate_no_dangling_nodes: bool,
949 pub validate_dynamic_address_in_command_part: bool,
950 pub validate_resource_assertions: bool,
951}
952
953impl Default for ValidationRuleset {
954 fn default() -> Self {
955 Self::all()
956 }
957}
958
959#[derive(Debug, Copy, Clone, PartialEq, Eq, Sbor)]
960pub enum InterpreterValidationRulesetSpecifier {
961 AllValidations,
962 Cuttlefish,
963}
964
965impl ValidationRuleset {
966 pub fn for_specifier(specifier: InterpreterValidationRulesetSpecifier) -> Self {
967 match specifier {
968 InterpreterValidationRulesetSpecifier::AllValidations => Self::all(),
969 InterpreterValidationRulesetSpecifier::Cuttlefish => Self::cuttlefish(),
970 }
971 }
972
973 pub fn all() -> Self {
974 Self {
975 validate_no_duplicate_blobs: true,
976 validate_blob_refs: true,
977 validate_bucket_proof_lock: true,
978 validate_no_dangling_nodes: true,
979 validate_dynamic_address_in_command_part: true,
980 validate_resource_assertions: true,
981 }
982 }
983
984 pub fn babylon_equivalent() -> Self {
985 Self {
986 validate_no_duplicate_blobs: false,
987 validate_blob_refs: false,
988 validate_bucket_proof_lock: true,
989 validate_no_dangling_nodes: false,
990 validate_dynamic_address_in_command_part: false,
991 validate_resource_assertions: false,
992 }
993 }
994
995 pub fn cuttlefish() -> Self {
996 Self {
997 validate_no_duplicate_blobs: true,
998 validate_blob_refs: true,
999 validate_bucket_proof_lock: true,
1000 validate_no_dangling_nodes: true,
1001 validate_dynamic_address_in_command_part: true,
1002 validate_resource_assertions: true,
1003 }
1004 }
1005}
1006
1007#[derive(Debug, Clone, PartialEq, Eq)]
1008pub enum ManifestValidationError {
1009 DuplicateBlob(ManifestBlobRef),
1010 BlobNotRegistered(ManifestBlobRef),
1011 BucketNotYetCreated(ManifestBucket),
1012 BucketAlreadyUsed(ManifestBucket, String),
1013 BucketConsumedWhilstLockedByProof(ManifestBucket, String),
1014 ProofNotYetCreated(ManifestProof),
1015 ProofAlreadyUsed(ManifestProof, String),
1016 AddressReservationNotYetCreated(ManifestAddressReservation),
1017 AddressReservationAlreadyUsed(ManifestAddressReservation, String),
1018 NamedAddressNotYetCreated(ManifestNamedAddress),
1019 ChildIntentNotRegistered(ManifestNamedIntent),
1020 DanglingBucket(ManifestBucket, String),
1021 DanglingAddressReservation(ManifestAddressReservation, String),
1022 ArgsEncodeError(EncodeError),
1023 ArgsDecodeError(DecodeError),
1024 InstructionNotSupportedInTransactionIntent,
1025 SubintentDoesNotEndWithYieldToParent,
1026 ProofCannotBePassedToAnotherIntent,
1027 TooManyInstructions,
1028 InvalidResourceConstraint,
1029 InstructionFollowingNextCallAssertionWasNotInvocation,
1030 ManifestEndedWhilstExpectingNextCallAssertion,
1031}
1032
1033#[allow(unused_variables)]
1035pub trait ManifestInterpretationVisitor {
1036 type Output: From<ManifestValidationError>;
1037
1038 #[must_use]
1039 fn on_start_instruction(&mut self, details: OnStartInstruction) -> ControlFlow<Self::Output> {
1040 ControlFlow::Continue(())
1041 }
1042
1043 #[must_use]
1044 fn on_end_instruction(&mut self, details: OnEndInstruction) -> ControlFlow<Self::Output> {
1045 ControlFlow::Continue(())
1046 }
1047
1048 #[must_use]
1049 fn on_new_bucket(&mut self, details: OnNewBucket) -> ControlFlow<Self::Output> {
1050 ControlFlow::Continue(())
1051 }
1052
1053 #[must_use]
1054 fn on_consume_bucket(&mut self, details: OnConsumeBucket) -> ControlFlow<Self::Output> {
1055 ControlFlow::Continue(())
1056 }
1057
1058 #[must_use]
1059 fn on_new_proof(&mut self, details: OnNewProof) -> ControlFlow<Self::Output> {
1060 ControlFlow::Continue(())
1061 }
1062
1063 #[must_use]
1064 fn on_consume_proof(&mut self, details: OnConsumeProof) -> ControlFlow<Self::Output> {
1065 ControlFlow::Continue(())
1066 }
1067
1068 #[must_use]
1069 fn on_new_address_reservation(
1070 &mut self,
1071 details: OnNewAddressReservation,
1072 ) -> ControlFlow<Self::Output> {
1073 ControlFlow::Continue(())
1074 }
1075
1076 #[must_use]
1077 fn on_consume_address_reservation(
1078 &mut self,
1079 details: OnConsumeAddressReservation,
1080 ) -> ControlFlow<Self::Output> {
1081 ControlFlow::Continue(())
1082 }
1083
1084 #[must_use]
1085 fn on_new_named_address(&mut self, details: OnNewNamedAddress) -> ControlFlow<Self::Output> {
1086 ControlFlow::Continue(())
1087 }
1088
1089 #[must_use]
1090 fn on_new_intent(&mut self, details: OnNewIntent) -> ControlFlow<Self::Output> {
1091 ControlFlow::Continue(())
1092 }
1093
1094 #[must_use]
1095 fn on_drop_authzone_proofs(
1096 &mut self,
1097 details: OnDropAuthZoneProofs,
1098 ) -> ControlFlow<Self::Output> {
1099 ControlFlow::Continue(())
1100 }
1101
1102 #[must_use]
1103 fn on_pass_expression(&mut self, details: OnPassExpression) -> ControlFlow<Self::Output> {
1104 ControlFlow::Continue(())
1105 }
1106
1107 #[must_use]
1108 fn on_register_blob(&mut self, details: OnRegisterBlob) -> ControlFlow<Self::Output> {
1109 ControlFlow::Continue(())
1110 }
1111
1112 #[must_use]
1113 fn on_pass_blob(&mut self, details: OnPassBlob) -> ControlFlow<Self::Output> {
1114 ControlFlow::Continue(())
1115 }
1116
1117 #[must_use]
1118 fn on_resource_assertion(&mut self, details: OnResourceAssertion) -> ControlFlow<Self::Output> {
1119 ControlFlow::Continue(())
1120 }
1121
1122 #[must_use]
1123 fn on_verification(&mut self, details: OnVerification) -> ControlFlow<Self::Output> {
1124 ControlFlow::Continue(())
1125 }
1126
1127 #[must_use]
1128 fn on_finish(&mut self, details: OnFinish) -> ControlFlow<Self::Output> {
1129 ControlFlow::Continue(())
1130 }
1131}
1132
1133impl ManifestInterpretationVisitor for () {
1134 type Output = ManifestValidationError;
1135}
1136
1137pub struct OnStartInstruction {
1139 pub index: usize,
1140}
1141
1142pub struct OnEndInstruction<'a> {
1144 pub index: usize,
1145 pub effect: ManifestInstructionEffect<'a>,
1146}
1147
1148pub struct OnNewBucket<'s, 'a> {
1150 pub bucket: ManifestBucket,
1151 pub state: &'s BucketState<'a>,
1152}
1153
1154pub struct OnConsumeBucket<'s, 'a> {
1156 pub bucket: ManifestBucket,
1157 pub state: &'s BucketState<'a>,
1158 pub destination: BucketDestination<'a>,
1159}
1160
1161pub struct OnNewProof<'s, 'a> {
1163 pub proof: ManifestProof,
1164 pub state: &'s ProofState<'a>,
1165}
1166
1167pub struct OnConsumeProof<'s, 'a> {
1169 pub proof: ManifestProof,
1170 pub state: &'s ProofState<'a>,
1171 pub destination: ProofDestination<'a>,
1172}
1173
1174pub struct OnNewAddressReservation<'s, 'a> {
1176 pub address_reservation: ManifestAddressReservation,
1177 pub state: &'s AddressReservationState<'a>,
1178}
1179
1180pub struct OnConsumeAddressReservation<'s, 'a> {
1182 pub address_reservation: ManifestAddressReservation,
1183 pub state: &'s AddressReservationState<'a>,
1184 pub destination: AddressReservationDestination<'a>,
1185}
1186
1187pub struct OnNewNamedAddress<'s, 'a> {
1189 pub named_address: ManifestNamedAddress,
1190 pub state: &'s NamedAddressState<'a>,
1191 pub package_address: &'a PackageAddress,
1192 pub blueprint_name: &'a str,
1193}
1194
1195pub struct OnNewIntent<'s, 'a> {
1197 pub intent: ManifestNamedIntent,
1198 pub state: &'s IntentState<'a>,
1199}
1200
1201pub struct OnDropAuthZoneProofs {
1203 pub drop_all_signature_proofs: bool,
1204 pub drop_all_non_signature_proofs: bool,
1205}
1206
1207pub struct OnPassExpression<'a> {
1209 pub expression: ManifestExpression,
1210 pub destination: ExpressionDestination<'a>,
1211}
1212
1213pub struct OnRegisterBlob<'a> {
1215 pub blob_ref: ManifestBlobRef,
1216 pub content: &'a [u8],
1217}
1218
1219pub struct OnPassBlob<'a> {
1221 pub blob_ref: ManifestBlobRef,
1222 pub destination: BlobDestination<'a>,
1223}
1224
1225pub struct OnResourceAssertion<'a> {
1227 pub assertion: ResourceAssertion<'a>,
1228}
1229
1230pub struct OnVerification<'a> {
1232 pub kind: VerificationKind,
1233 pub access_rule: &'a AccessRule,
1234}
1235
1236pub struct OnFinish;