1use crate::internal_prelude::*;
2
3impl TransactionValidator {
4 #[allow(deprecated)]
5 pub fn validate_notarized_v1(
6 &self,
7 transaction: PreparedNotarizedTransactionV1,
8 ) -> Result<ValidatedNotarizedTransactionV1, TransactionValidationError> {
9 let transaction_intent = &transaction.signed_intent.intent;
10
11 let signatures = AllPendingSignatureValidations::new_with_root(
12 TransactionVersion::V1,
13 &self.config,
14 transaction_intent.transaction_intent_hash().into(),
15 PendingIntentSignatureValidations::TransactionIntent {
16 notary_is_signatory: transaction_intent.header.inner.notary_is_signatory,
17 notary_public_key: transaction_intent.header.inner.notary_public_key,
18 notary_signature: transaction.notary_signature.inner.0,
19 notarized_hash: transaction.signed_transaction_intent_hash(),
20 intent_signatures: transaction
21 .signed_intent
22 .intent_signatures
23 .inner
24 .signatures
25 .as_slice(),
26 signed_hash: transaction_intent.transaction_intent_hash(),
27 },
28 )?;
29
30 let aggregation = self
31 .validate_intent_v1(&transaction.signed_intent.intent)
32 .map_err(|err| {
33 TransactionValidationError::IntentValidationError(
34 TransactionValidationErrorLocation::RootTransactionIntent(
35 transaction_intent.transaction_intent_hash(),
36 ),
37 err,
38 )
39 })?;
40 let _ = aggregation.finalize(&self.config)?; let encoded_instructions =
43 manifest_encode(&transaction.signed_intent.intent.instructions.inner.0)?;
44
45 let SignatureValidationSummary {
46 root_signer_keys: signer_keys,
47 non_root_signer_keys: _, total_signature_validations: num_of_signature_validations,
49 } = signatures.validate_all()?;
50
51 Ok(ValidatedNotarizedTransactionV1 {
52 prepared: transaction,
53 encoded_instructions,
54 signer_keys,
55 num_of_signature_validations,
56 })
57 }
58
59 #[allow(deprecated)]
60 pub fn validate_preview_intent_v1(
61 &self,
62 preview_intent: PreviewIntentV1,
63 ) -> Result<ValidatedPreviewIntent, TransactionValidationError> {
64 let fake_intent_hash = SimulatedTransactionIntentNullification.transaction_intent_hash();
65 let intent = preview_intent.intent.prepare(self.preparation_settings())?;
66
67 let aggregation = self.validate_intent_v1(&intent).map_err(|err| {
68 TransactionValidationError::IntentValidationError(
69 TransactionValidationErrorLocation::RootTransactionIntent(fake_intent_hash),
70 err,
71 )
72 })?;
73 aggregation.finalize(&self.config)?;
74
75 let encoded_instructions = manifest_encode(&intent.instructions.inner.0)?;
76
77 Ok(ValidatedPreviewIntent {
78 intent,
79 encoded_instructions,
80 signer_public_keys: preview_intent.signer_public_keys,
81 flags: preview_intent.flags,
82 })
83 }
84
85 #[allow(deprecated)]
87 pub fn validate_intent_v1(
88 &self,
89 intent: &PreparedIntentV1,
90 ) -> Result<AcrossIntentAggregation, IntentValidationError> {
91 let mut aggregation = AcrossIntentAggregation::start();
92 self.validate_header_v1(&intent.header.inner)?;
93 self.validate_message_v1(&intent.message.inner)?;
94 aggregation.record_reference_count(intent.instructions.references.len(), &self.config)?;
95 self.validate_instructions_v1(&intent.instructions.inner.0, &intent.blobs.blobs_by_hash)?;
96
97 Ok(aggregation)
98 }
99
100 pub fn validate_instructions_v1(
101 &self,
102 instructions: &[InstructionV1],
103 blobs: &IndexMap<Hash, Vec<u8>>,
104 ) -> Result<(), IntentValidationError> {
105 if instructions.len() > self.config.max_instructions {
106 return Err(ManifestValidationError::TooManyInstructions.into());
107 }
108
109 match self.config.manifest_validation {
110 ManifestValidationRuleset::BabylonBasicValidator => self
111 .validate_instructions_basic_v1(instructions)
112 .map_err(|err| err.into()),
113 ManifestValidationRuleset::Interpreter(specifier) => StaticManifestInterpreter::new(
114 ValidationRuleset::for_specifier(specifier),
115 &EphemeralManifest::new_childless_transaction_manifest(instructions, blobs),
116 )
117 .validate()
118 .map_err(|err| err.into()),
119 }
120 }
121
122 pub fn validate_instructions_basic_v1(
123 &self,
124 instructions: &[InstructionV1],
125 ) -> Result<(), ManifestBasicValidatorError> {
126 let mut id_validator = BasicManifestValidator::new();
127 for instruction in instructions {
128 match instruction.effect() {
129 ManifestInstructionEffect::CreateBucket { .. } => {
130 let _ = id_validator.new_bucket();
131 }
132 ManifestInstructionEffect::CreateProof { source_amount, .. } => {
133 let _ = id_validator.new_proof(source_amount.proof_kind())?;
134 }
135 ManifestInstructionEffect::ConsumeBucket {
136 consumed_bucket: bucket,
137 ..
138 } => {
139 id_validator.drop_bucket(&bucket)?;
140 }
141 ManifestInstructionEffect::ConsumeProof {
142 consumed_proof: proof,
143 ..
144 } => {
145 id_validator.drop_proof(&proof)?;
146 }
147 ManifestInstructionEffect::CloneProof { cloned_proof, .. } => {
148 let _ = id_validator.clone_proof(&cloned_proof)?;
149 }
150 ManifestInstructionEffect::DropManyProofs {
151 drop_all_named_proofs,
152 ..
153 } => {
154 if drop_all_named_proofs {
155 id_validator.drop_all_named_proofs()?;
156 }
157 }
158 ManifestInstructionEffect::Invocation { args, .. } => {
159 id_validator.process_call_data(args)?;
160 }
161 ManifestInstructionEffect::CreateAddressAndReservation { .. } => {
162 let _ = id_validator.new_address_reservation();
163 id_validator.new_named_address();
164 }
165 ManifestInstructionEffect::ResourceAssertion { .. } => {}
166 ManifestInstructionEffect::Verification { .. } => {
167 unreachable!("No InstructionV1 returns this effect");
168 }
169 }
170 }
171 Ok(())
172 }
173
174 pub fn validate_header_v1(
175 &self,
176 header: &TransactionHeaderV1,
177 ) -> Result<(), HeaderValidationError> {
178 if let Some(required_network_id) = self.required_network_id {
180 if header.network_id != required_network_id {
181 return Err(HeaderValidationError::InvalidNetwork);
182 }
183 }
184
185 if header.end_epoch_exclusive <= header.start_epoch_inclusive {
187 return Err(HeaderValidationError::InvalidEpochRange);
188 }
189 let max_end_epoch = header
190 .start_epoch_inclusive
191 .after(self.config.max_epoch_range)
192 .ok_or(HeaderValidationError::InvalidEpochRange)?;
193 if header.end_epoch_exclusive > max_end_epoch {
194 return Err(HeaderValidationError::InvalidEpochRange);
195 }
196
197 if header.tip_percentage < self.config.min_tip_percentage
199 || header.tip_percentage > self.config.max_tip_percentage
200 {
201 return Err(HeaderValidationError::InvalidTip);
202 }
203
204 Ok(())
205 }
206
207 pub fn validate_message_v1(&self, message: &MessageV1) -> Result<(), InvalidMessageError> {
208 let validation = &self.config.message_validation;
209 match message {
210 MessageV1::None => {}
211 MessageV1::Plaintext(plaintext_message) => {
212 let PlaintextMessageV1 { mime_type, message } = plaintext_message;
213 if mime_type.len() > validation.max_mime_type_length {
214 return Err(InvalidMessageError::MimeTypeTooLong {
215 actual: mime_type.len(),
216 permitted: validation.max_mime_type_length,
217 });
218 }
219 if message.len() > validation.max_plaintext_message_length {
220 return Err(InvalidMessageError::PlaintextMessageTooLong {
221 actual: message.len(),
222 permitted: validation.max_plaintext_message_length,
223 });
224 }
225 }
226 MessageV1::Encrypted(encrypted_message) => {
227 let EncryptedMessageV1 {
228 encrypted,
229 decryptors_by_curve,
230 } = encrypted_message;
231 if encrypted.0.len() > validation.max_encrypted_message_length {
232 return Err(InvalidMessageError::EncryptedMessageTooLong {
233 actual: encrypted.0.len(),
234 permitted: validation.max_encrypted_message_length,
235 });
236 }
237 if decryptors_by_curve.is_empty() {
238 return Err(InvalidMessageError::NoDecryptors);
239 }
240 let mut total_decryptors = 0;
241 for (curve_type, decryptors) in decryptors_by_curve.iter() {
242 if decryptors.curve_type() != *curve_type {
243 return Err(InvalidMessageError::MismatchingDecryptorCurves {
244 actual: decryptors.curve_type(),
245 expected: *curve_type,
246 });
247 }
248 if decryptors.number_of_decryptors() == 0 {
249 return Err(InvalidMessageError::NoDecryptorsForCurveType {
250 curve_type: decryptors.curve_type(),
251 });
252 }
253 total_decryptors += decryptors.number_of_decryptors();
255 }
256 if total_decryptors > validation.max_decryptors {
257 return Err(InvalidMessageError::TooManyDecryptors {
258 actual: total_decryptors,
259 permitted: validation.max_decryptors,
260 });
261 }
262 }
263 }
264 Ok(())
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use crate::internal_prelude::*;
271
272 macro_rules! assert_invalid_tx {
273 ($result: pat, ($start_epoch: expr, $end_epoch: expr, $nonce: expr, $signers: expr, $notary: expr)) => {{
274 let validator = TransactionValidator::new_for_latest_simulator();
275 assert_matches!(
276 create_transaction($start_epoch, $end_epoch, $nonce, $signers, $notary)
277 .prepare_and_validate(&validator)
278 .expect_err("Should be an error"),
279 $result,
280 );
281 }};
282 }
283
284 #[test]
285 fn test_invalid_header() {
286 assert_invalid_tx!(
287 TransactionValidationError::IntentValidationError(
288 TransactionValidationErrorLocation::RootTransactionIntent(_),
289 IntentValidationError::HeaderValidationError(
290 HeaderValidationError::InvalidEpochRange
291 ),
292 ),
293 (Epoch::zero(), Epoch::zero(), 5, vec![1], 2)
294 );
295 assert_invalid_tx!(
296 TransactionValidationError::IntentValidationError(
297 TransactionValidationErrorLocation::RootTransactionIntent(_),
298 IntentValidationError::HeaderValidationError(
299 HeaderValidationError::InvalidEpochRange
300 ),
301 ),
302 (
303 Epoch::zero(),
304 Epoch::of(TransactionValidationConfig::latest().max_epoch_range + 1),
305 5,
306 vec![1],
307 2
308 )
309 );
310 }
311
312 #[test]
313 fn test_epoch_overflow() {
314 assert_invalid_tx!(
315 TransactionValidationError::IntentValidationError(
316 TransactionValidationErrorLocation::RootTransactionIntent(_),
317 IntentValidationError::HeaderValidationError(
318 HeaderValidationError::InvalidEpochRange
319 ),
320 ),
321 (Epoch::of(u64::MAX - 5), Epoch::of(u64::MAX), 5, vec![1], 2)
322 );
323 }
324
325 #[test]
326 fn test_too_many_signatures() {
327 assert_invalid_tx!(
328 TransactionValidationError::SignatureValidationError(
329 TransactionValidationErrorLocation::RootTransactionIntent(_),
330 SignatureValidationError::TooManySignatures {
331 total: 19,
332 limit: 16,
333 }
334 ),
335 (Epoch::zero(), Epoch::of(100), 5, (1..20).collect(), 2)
336 );
337 }
338
339 #[test]
340 fn test_duplicate_signers() {
341 assert_invalid_tx!(
342 TransactionValidationError::SignatureValidationError(
343 TransactionValidationErrorLocation::RootTransactionIntent(_),
344 SignatureValidationError::DuplicateSigner
345 ),
346 (Epoch::zero(), Epoch::of(100), 5, vec![1, 1], 2)
347 );
348 }
349
350 #[test]
351 fn test_valid_preview() {
352 let tx = create_transaction(Epoch::zero(), Epoch::of(100), 5, vec![1, 2], 2);
354
355 let validator = TransactionValidator::new_for_latest_simulator();
356
357 let preview_intent = PreviewIntentV1 {
358 intent: tx.signed_intent.intent,
359 signer_public_keys: Vec::new(),
360 flags: PreviewFlags {
361 use_free_credit: true,
362 assume_all_signature_proofs: false,
363 skip_epoch_check: false,
364 disable_auth: false,
365 },
366 };
367
368 let result = validator.validate_preview_intent_v1(preview_intent);
369
370 assert!(result.is_ok());
371 }
372
373 #[test]
374 fn test_valid_messages() {
375 {
377 let message = MessageV1::None;
378 let result = validate_default(&create_transaction_with_message(message));
379 assert!(result.is_ok());
380 }
381 {
383 let message = MessageV1::Plaintext(PlaintextMessageV1 {
384 mime_type: "text/plain".to_owned(),
385 message: MessageContentsV1::String("Hello world!".to_string()),
386 });
387 let result = validate_default(&create_transaction_with_message(message));
388 assert!(result.is_ok());
389 }
390 {
392 let message = MessageV1::Encrypted(EncryptedMessageV1 {
395 encrypted: AesGcmPayload(vec![]),
396 decryptors_by_curve: indexmap!(
397 CurveType::Ed25519 => DecryptorsByCurve::Ed25519 {
398 dh_ephemeral_public_key: Ed25519PublicKey([0; Ed25519PublicKey::LENGTH]),
399 decryptors: indexmap!(
400 PublicKeyFingerprint([0; PublicKeyFingerprint::LENGTH]) => AesWrapped128BitKey([0; AesWrapped128BitKey::LENGTH]),
401 ),
402 },
403 CurveType::Secp256k1 => DecryptorsByCurve::Secp256k1 {
404 dh_ephemeral_public_key: Secp256k1PublicKey([0; Secp256k1PublicKey::LENGTH]),
405 decryptors: indexmap!(
406 PublicKeyFingerprint([0; PublicKeyFingerprint::LENGTH]) => AesWrapped128BitKey([0; AesWrapped128BitKey::LENGTH]),
407 PublicKeyFingerprint([1; PublicKeyFingerprint::LENGTH]) => AesWrapped128BitKey([0; AesWrapped128BitKey::LENGTH]),
408 ),
409 },
410 ),
411 });
412 let result = validate_default(&create_transaction_with_message(message));
413 assert!(result.is_ok());
414 }
415 }
416
417 #[test]
418 fn test_invalid_message_errors() {
419 {
421 let message = MessageV1::Plaintext(PlaintextMessageV1 {
422 mime_type: "very long mimetype, very long mimetype, very long mimetype, very long mimetype, very long mimetype, very long mimetype, very long mimetype, very long mimetype, ".to_owned(),
423 message: MessageContentsV1::String("Hello".to_string()),
424 });
425 let error =
426 validate_default_expecting_message_error(&create_transaction_with_message(message));
427 assert_matches!(error, InvalidMessageError::MimeTypeTooLong { .. })
428 }
429
430 {
432 let mut long_message: String = "".to_owned();
433 while long_message.len() <= 2048 {
434 long_message.push_str("more text please!");
435 }
436 let message = MessageV1::Plaintext(PlaintextMessageV1 {
437 mime_type: "text/plain".to_owned(),
438 message: MessageContentsV1::String(long_message),
439 });
440 let error =
441 validate_default_expecting_message_error(&create_transaction_with_message(message));
442 assert_matches!(error, InvalidMessageError::PlaintextMessageTooLong { .. })
443 }
444
445 {
447 let mut message_which_is_too_long: String = "".to_owned();
448 while message_which_is_too_long.len() <= 2048 + 50 {
449 message_which_is_too_long.push_str("more text please!");
451 }
452 let message = MessageV1::Encrypted(EncryptedMessageV1 {
453 encrypted: AesGcmPayload(message_which_is_too_long.as_bytes().to_vec()),
454 decryptors_by_curve: indexmap!(
455 CurveType::Ed25519 => DecryptorsByCurve::Ed25519 {
456 dh_ephemeral_public_key: Ed25519PublicKey([0; Ed25519PublicKey::LENGTH]),
457 decryptors: indexmap!(
458 PublicKeyFingerprint([0; PublicKeyFingerprint::LENGTH]) => AesWrapped128BitKey([0; AesWrapped128BitKey::LENGTH]),
459 ),
460 }
461 ),
462 });
463 let error =
464 validate_default_expecting_message_error(&create_transaction_with_message(message));
465 assert_matches!(error, InvalidMessageError::EncryptedMessageTooLong { .. })
466 }
467
468 {
470 let message = MessageV1::Encrypted(EncryptedMessageV1 {
471 encrypted: AesGcmPayload(vec![]),
472 decryptors_by_curve: indexmap!(),
473 });
474 let error =
475 validate_default_expecting_message_error(&create_transaction_with_message(message));
476 assert_matches!(error, InvalidMessageError::NoDecryptors)
477 }
478
479 {
481 let message = MessageV1::Encrypted(EncryptedMessageV1 {
482 encrypted: AesGcmPayload(vec![]),
483 decryptors_by_curve: indexmap!(
484 CurveType::Ed25519 => DecryptorsByCurve::Ed25519 {
485 dh_ephemeral_public_key: Ed25519PublicKey([0; Ed25519PublicKey::LENGTH]),
486 decryptors: indexmap!(),
487 }
488 ),
489 });
490 let error =
491 validate_default_expecting_message_error(&create_transaction_with_message(message));
492 assert_matches!(
493 error,
494 InvalidMessageError::NoDecryptorsForCurveType {
495 curve_type: CurveType::Ed25519
496 }
497 )
498 }
499
500 {
502 let message = MessageV1::Encrypted(EncryptedMessageV1 {
503 encrypted: AesGcmPayload(vec![]),
504 decryptors_by_curve: indexmap!(
505 CurveType::Ed25519 => DecryptorsByCurve::Secp256k1 {
506 dh_ephemeral_public_key: Secp256k1PublicKey([0; Secp256k1PublicKey::LENGTH]),
507 decryptors: indexmap!(
508 PublicKeyFingerprint([0; PublicKeyFingerprint::LENGTH]) => AesWrapped128BitKey([0; AesWrapped128BitKey::LENGTH]),
509 ),
510 }
511 ),
512 });
513 let error =
514 validate_default_expecting_message_error(&create_transaction_with_message(message));
515 assert_matches!(
516 error,
517 InvalidMessageError::MismatchingDecryptorCurves {
518 actual: CurveType::Secp256k1,
519 expected: CurveType::Ed25519
520 }
521 )
522 }
523
524 {
526 let mut decryptors = IndexMap::<PublicKeyFingerprint, AesWrapped128BitKey>::default();
527 for i in 0..30 {
528 decryptors.insert(
529 PublicKeyFingerprint([0, 0, 0, 0, 0, 0, 0, i as u8]),
530 AesWrapped128BitKey([0; AesWrapped128BitKey::LENGTH]),
531 );
532 }
533 let message = MessageV1::Encrypted(EncryptedMessageV1 {
534 encrypted: AesGcmPayload(vec![]),
535 decryptors_by_curve: indexmap!(
536 CurveType::Ed25519 => DecryptorsByCurve::Ed25519 {
537 dh_ephemeral_public_key: Ed25519PublicKey([0; Ed25519PublicKey::LENGTH]),
538 decryptors,
539 }
540 ),
541 });
542 let error =
543 validate_default_expecting_message_error(&create_transaction_with_message(message));
544 assert_matches!(
545 error,
546 InvalidMessageError::TooManyDecryptors {
547 actual: 30,
548 permitted: 20
549 }
550 )
551 }
552 }
553
554 fn validate_default_expecting_message_error(
555 transaction: &NotarizedTransactionV1,
556 ) -> InvalidMessageError {
557 match validate_default(transaction).expect_err("Expected validation error") {
558 TransactionValidationError::IntentValidationError(
559 _,
560 IntentValidationError::InvalidMessage(error),
561 ) => error,
562 error => {
563 panic!("Expected InvalidMessage error, got: {:?}", error)
564 }
565 }
566 }
567
568 fn validate_default(
569 transaction: &NotarizedTransactionV1,
570 ) -> Result<(), TransactionValidationError> {
571 let validator = TransactionValidator::new_for_latest_simulator();
572 transaction.prepare_and_validate(&validator).map(|_| ())
573 }
574
575 fn create_transaction_with_message(message: MessageV1) -> NotarizedTransactionV1 {
576 let sk_notary = Secp256k1PrivateKey::from_u64(1).unwrap();
577
578 let mut builder = TransactionBuilder::new()
579 .header(TransactionHeaderV1 {
580 network_id: NetworkDefinition::simulator().id,
581 start_epoch_inclusive: Epoch::of(1),
582 end_epoch_exclusive: Epoch::of(10),
583 nonce: 0,
584 notary_public_key: sk_notary.public_key().into(),
585 notary_is_signatory: false,
586 tip_percentage: 5,
587 })
588 .manifest(ManifestBuilder::new().drop_auth_zone_proofs().build())
589 .message(message);
590
591 builder = builder.notarize(&sk_notary);
592
593 builder.build()
594 }
595
596 fn create_transaction(
597 start_epoch: Epoch,
598 end_epoch: Epoch,
599 nonce: u32,
600 signers: Vec<u64>,
601 notary: u64,
602 ) -> NotarizedTransactionV1 {
603 create_transaction_advanced(
604 start_epoch,
605 end_epoch,
606 nonce,
607 signers,
608 notary,
609 ManifestBuilder::new().drop_auth_zone_proofs().build(),
610 )
611 }
612
613 fn create_transaction_advanced(
614 start_epoch: Epoch,
615 end_epoch: Epoch,
616 nonce: u32,
617 signers: Vec<u64>,
618 notary: u64,
619 manifest: TransactionManifestV1,
620 ) -> NotarizedTransactionV1 {
621 let sk_notary = Secp256k1PrivateKey::from_u64(notary).unwrap();
622
623 let mut builder = TransactionBuilder::new()
624 .header(TransactionHeaderV1 {
625 network_id: NetworkDefinition::simulator().id,
626 start_epoch_inclusive: start_epoch,
627 end_epoch_exclusive: end_epoch,
628 nonce,
629 notary_public_key: sk_notary.public_key().into(),
630 notary_is_signatory: false,
631 tip_percentage: 5,
632 })
633 .manifest(manifest);
634
635 for signer in signers {
636 builder = builder.sign(Secp256k1PrivateKey::from_u64(signer).unwrap());
637 }
638 builder = builder.notarize(&sk_notary);
639
640 builder.build()
641 }
642
643 #[test]
644 fn test_drop_bucket_before_proof() {
645 let transaction = create_transaction_advanced(
646 Epoch::of(0),
647 Epoch::of(40),
648 123,
649 vec![55],
650 66,
651 ManifestBuilder::new()
652 .take_from_worktop(XRD, dec!(100), "bucket")
653 .create_proof_from_bucket_of_amount("bucket", dec!(5), "proof1")
654 .return_to_worktop("bucket")
655 .drop_proof("proof1")
656 .build_no_validate(),
657 );
658 let validator = TransactionValidator::new_for_latest_simulator();
659 assert_matches!(
660 transaction.prepare_and_validate(&validator),
661 Err(TransactionValidationError::IntentValidationError(
662 _,
663 IntentValidationError::ManifestValidationError(
664 ManifestValidationError::BucketConsumedWhilstLockedByProof(
665 ManifestBucket(0),
666 _,
667 )
668 )
669 ))
670 );
671 }
672
673 #[test]
674 fn test_clone_invalid_proof() {
675 let transaction = create_transaction_advanced(
676 Epoch::of(0),
677 Epoch::of(40),
678 123,
679 vec![55],
680 66,
681 ManifestBuilder::new()
682 .take_from_worktop(XRD, dec!(100), "bucket")
683 .create_proof_from_bucket_of_amount("bucket", dec!(5), "proof1")
684 .then(|builder| {
685 let lookup = builder.name_lookup();
686 let proof_id = lookup.proof("proof1");
687
688 builder
689 .drop_proof("proof1")
690 .return_to_worktop("bucket")
691 .add_raw_instruction_ignoring_all_side_effects(CloneProof { proof_id })
692 })
693 .build_no_validate(),
694 );
695 let validator = TransactionValidator::new_for_latest_simulator();
696 assert_matches!(
697 transaction.prepare_and_validate(&validator),
698 Err(TransactionValidationError::IntentValidationError(
699 _,
700 IntentValidationError::ManifestValidationError(
701 ManifestValidationError::ProofAlreadyUsed(ManifestProof(0), _,)
702 )
703 ))
704 );
705 }
706
707 #[test]
708 fn verify_call_direct_method_args_are_processed() {
709 let transaction = create_transaction_advanced(
710 Epoch::of(0),
711 Epoch::of(40),
712 123,
713 vec![55],
714 66,
715 ManifestBuilder::new()
716 .take_from_worktop(XRD, dec!(100), "bucket")
717 .then(|builder| {
718 let lookup = builder.name_lookup();
719 builder
720 .call_direct_access_method(
721 InternalAddress::new_or_panic(
722 [EntityType::InternalFungibleVault as u8; NodeId::LENGTH],
723 ),
724 "test",
725 manifest_args!(lookup.bucket("bucket")),
726 )
727 .return_to_worktop("bucket")
728 })
729 .build_no_validate(),
730 );
731 let validator = TransactionValidator::new_for_latest_simulator();
732 assert_matches!(
733 transaction.prepare_and_validate(&validator),
734 Err(TransactionValidationError::IntentValidationError(
735 _,
736 IntentValidationError::ManifestValidationError(
737 ManifestValidationError::BucketAlreadyUsed(ManifestBucket(0), _,)
738 )
739 ))
740 );
741 }
742}