1pub mod deny;
6
7pub use checked::*;
8
9#[iota_macros::with_checked_arithmetic]
10mod checked {
11 use std::{
12 collections::{BTreeMap, HashSet},
13 sync::Arc,
14 };
15
16 use iota_config::verifier_signing_config::VerifierSigningConfig;
17 use iota_protocol_config::ProtocolConfig;
18 use iota_sdk_types::ObjectId;
19 use iota_types::{
20 IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_CLOCK_OBJECT_SHARED_VERSION,
21 base_types::{IotaAddress, ObjectRef, SequenceNumber},
22 error::{IotaError, IotaResult, UserInputError, UserInputResult},
23 executable_transaction::VerifiedExecutableTransaction,
24 fp_bail, fp_ensure,
25 gas::IotaGasStatus,
26 metrics::BytecodeVerifierMetrics,
27 object::{Object, Owner},
28 transaction::{
29 CheckedInputObjects, InputObjectKind, InputObjects, ObjectReadResult,
30 ObjectReadResultKind, ProgrammableTransactionExt, ReceivingObjectReadResult,
31 ReceivingObjects, TransactionData, TransactionDataAPI, TransactionKind,
32 TransactionKindExt,
33 },
34 };
35 use tracing::{error, instrument};
36
37 trait IntoChecked {
38 fn into_checked(self) -> CheckedInputObjects;
39 }
40
41 impl IntoChecked for InputObjects {
42 fn into_checked(self) -> CheckedInputObjects {
43 CheckedInputObjects::new_with_checked_transaction_inputs(self)
44 }
45 }
46
47 fn get_gas_status(
52 objects: &InputObjects,
53 gas: &[ObjectRef],
54 protocol_config: &ProtocolConfig,
55 reference_gas_price: u64,
56 transaction: &TransactionData,
57 authentication_gas_budget: u64,
58 is_execute_transaction_to_effects: bool,
59 ) -> IotaResult<IotaGasStatus> {
60 if transaction.is_system_tx() {
61 Ok(IotaGasStatus::new_unmetered())
62 } else {
63 check_gas(
64 objects,
65 protocol_config,
66 reference_gas_price,
67 gas,
68 transaction.gas_price(),
69 transaction.gas_budget(),
70 authentication_gas_budget,
71 is_execute_transaction_to_effects,
72 )
73 }
74 }
75
76 #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
77 pub fn check_transaction_input(
78 protocol_config: &ProtocolConfig,
79 reference_gas_price: u64,
80 transaction: &TransactionData,
81 input_objects: InputObjects,
82 receiving_objects: &ReceivingObjects,
83 metrics: &Arc<BytecodeVerifierMetrics>,
84 verifier_signing_config: &VerifierSigningConfig,
85 authentication_gas_budget: u64,
86 ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> {
87 let gas_status = check_transaction_input_inner(
88 protocol_config,
89 reference_gas_price,
90 transaction,
91 &input_objects,
92 &[],
93 authentication_gas_budget,
94 false,
95 )?;
96 check_receiving_objects(&input_objects, receiving_objects)?;
97 check_non_system_packages_to_be_published(
99 transaction,
100 protocol_config,
101 metrics,
102 verifier_signing_config,
103 )?;
104
105 Ok((gas_status, input_objects.into_checked()))
106 }
107
108 #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
109 pub fn check_transaction_input_with_given_gas(
110 protocol_config: &ProtocolConfig,
111 reference_gas_price: u64,
112 transaction: &TransactionData,
113 mut input_objects: InputObjects,
114 receiving_objects: ReceivingObjects,
115 gas_object: Object,
116 metrics: &Arc<BytecodeVerifierMetrics>,
117 verifier_signing_config: &VerifierSigningConfig,
118 ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> {
119 let gas_object_ref = gas_object.compute_object_reference();
120 input_objects.push(ObjectReadResult::new_from_gas_object(&gas_object));
121
122 let gas_status = check_transaction_input_inner(
123 protocol_config,
124 reference_gas_price,
125 transaction,
126 &input_objects,
127 &[gas_object_ref],
128 0,
129 true,
130 )?;
131 check_receiving_objects(&input_objects, &receiving_objects)?;
132 check_non_system_packages_to_be_published(
134 transaction,
135 protocol_config,
136 metrics,
137 verifier_signing_config,
138 )?;
139
140 Ok((gas_status, input_objects.into_checked()))
141 }
142
143 #[instrument(level = "trace", skip_all)]
149 pub fn check_certificate_input(
150 cert: &VerifiedExecutableTransaction,
151 input_objects: InputObjects,
152 protocol_config: &ProtocolConfig,
153 reference_gas_price: u64,
154 ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> {
155 let transaction = cert.data().transaction_data();
156 let gas_status = check_transaction_input_inner(
157 protocol_config,
158 reference_gas_price,
159 transaction,
160 &input_objects,
161 &[],
162 0,
163 true,
164 )?;
165 Ok((gas_status, input_objects.into_checked()))
170 }
171
172 #[instrument(level = "trace", skip_all)]
175 pub fn check_dev_inspect_input(
176 config: &ProtocolConfig,
177 kind: &TransactionKind,
178 input_objects: InputObjects,
179 _receiving_objects: ReceivingObjects,
181 ) -> IotaResult<CheckedInputObjects> {
182 kind.validity_check(config)?;
183 if kind.is_system() {
184 return Err(UserInputError::Unsupported(format!(
185 "Transaction kind {kind} is not supported in dev-inspect"
186 ))
187 .into());
188 }
189 let mut used_objects: HashSet<IotaAddress> = HashSet::new();
190 for input_object in input_objects.iter() {
191 let Some(object) = input_object.as_object() else {
192 continue;
194 };
195
196 if !object.is_immutable() {
197 fp_ensure!(
198 used_objects.insert(object.id().into()),
199 UserInputError::MutableObjectUsedMoreThanOnce {
200 object_id: object.id()
201 }
202 .into()
203 );
204 }
205 }
206
207 Ok(input_objects.into_checked())
208 }
209
210 #[instrument(level = "trace", skip_all)]
216 pub fn check_move_authenticator_input_for_signing(
217 authenticator_input_objects: InputObjects,
218 ) -> IotaResult<CheckedInputObjects> {
219 check_move_authenticator_objects(&authenticator_input_objects)?;
220
221 Ok(authenticator_input_objects.into_checked())
222 }
223
224 pub fn aggregate_authenticator_input_objects(
228 per_authenticator_checked_input_objects: &[&CheckedInputObjects],
229 ) -> IotaResult<CheckedInputObjects> {
230 let mut aggregated_authenticator_input_objects =
231 CheckedInputObjects::new_with_checked_transaction_inputs(InputObjects::new(vec![]));
232
233 for authenticator_checked_input_objects in per_authenticator_checked_input_objects.iter() {
234 aggregated_authenticator_input_objects = checked_input_objects_union(
235 aggregated_authenticator_input_objects,
236 authenticator_checked_input_objects,
237 )?;
238 }
239
240 Ok(aggregated_authenticator_input_objects)
241 }
242
243 #[instrument(level = "trace", skip_all)]
255 pub fn check_certificate_and_move_authenticator_input(
256 cert: &VerifiedExecutableTransaction,
257 tx_input_objects: InputObjects,
258 per_authenticator_input_objects: Vec<InputObjects>,
259 authenticator_gas_budget: u64,
260 protocol_config: &ProtocolConfig,
261 reference_gas_price: u64,
262 ) -> IotaResult<(IotaGasStatus, Vec<CheckedInputObjects>, CheckedInputObjects)> {
263 per_authenticator_input_objects
265 .iter()
266 .try_for_each(check_move_authenticator_objects)?;
267
268 let transaction = cert.data().transaction_data();
270 let gas_status = check_transaction_input_inner(
271 protocol_config,
272 reference_gas_price,
273 transaction,
274 &tx_input_objects,
275 &[],
276 authenticator_gas_budget,
277 true,
278 )?;
279
280 let per_authenticator_checked_input_objects = per_authenticator_input_objects
281 .into_iter()
282 .map(|objects| objects.into_checked())
283 .collect::<Vec<_>>();
284
285 let mut input_objects_union = tx_input_objects.into_checked();
287 for objects in per_authenticator_checked_input_objects.iter() {
288 input_objects_union = checked_input_objects_union(input_objects_union, objects)?;
289 }
290
291 Ok((
292 gas_status,
293 per_authenticator_checked_input_objects,
294 input_objects_union,
295 ))
296 }
297
298 fn check_transaction_input_inner(
300 protocol_config: &ProtocolConfig,
301 reference_gas_price: u64,
302 transaction: &TransactionData,
303 input_objects: &InputObjects,
304 gas_override: &[ObjectRef],
306 authentication_gas_budget: u64,
307 is_execute_transaction_to_effects: bool,
308 ) -> IotaResult<IotaGasStatus> {
309 let gas = if gas_override.is_empty() {
311 transaction.gas()
312 } else {
313 gas_override
314 };
315
316 let gas_status = get_gas_status(
317 input_objects,
318 gas,
319 protocol_config,
320 reference_gas_price,
321 transaction,
322 authentication_gas_budget,
323 is_execute_transaction_to_effects,
324 )?;
325 check_objects(transaction, input_objects)?;
326
327 Ok(gas_status)
328 }
329
330 #[instrument(level = "trace", skip_all)]
331 fn check_receiving_objects(
332 input_objects: &InputObjects,
333 receiving_objects: &ReceivingObjects,
334 ) -> Result<(), IotaError> {
335 let mut objects_in_txn: HashSet<_> = input_objects
336 .object_kinds()
337 .map(|x| x.object_id())
338 .collect();
339
340 for ReceivingObjectReadResult { object_ref, object } in receiving_objects.iter() {
349 fp_ensure!(
350 object_ref.version < SequenceNumber::MAX_VALID_EXCL,
351 UserInputError::InvalidSequenceNumber.into()
352 );
353
354 let Some(object) = object.as_object() else {
355 continue;
357 };
358
359 if !(object.owner.is_address()
360 && object.version() == object_ref.version
361 && object.digest() == object_ref.digest)
362 {
363 fp_ensure!(
365 object.version() == object_ref.version,
366 UserInputError::ObjectVersionUnavailableForConsumption {
367 provided_obj_ref: *object_ref,
368 current_version: object.version(),
369 }
370 .into()
371 );
372
373 fp_ensure!(
375 !object.is_package(),
376 UserInputError::MovePackageAsObject {
377 object_id: object_ref.object_id
378 }
379 .into()
380 );
381
382 let expected_digest = object.digest();
384 fp_ensure!(
385 expected_digest == object_ref.digest,
386 UserInputError::InvalidObjectDigest {
387 object_id: object_ref.object_id,
388 expected_digest
389 }
390 .into()
391 );
392
393 match object.owner {
394 Owner::Address(_) => {
395 debug_assert!(
396 false,
397 "Receiving object {object_ref:?} is invalid but we expect it should be valid. {object:?}"
398 );
399 error!(
400 "Receiving object {:?} is invalid but we expect it should be valid. {:?}",
401 object_ref, object
402 );
403 fp_bail!(
406 UserInputError::ObjectNotFound {
407 object_id: object_ref.object_id,
408 version: Some(object_ref.version),
409 }
410 .into()
411 )
412 }
413 Owner::Object(owner) => {
414 fp_bail!(
415 UserInputError::InvalidChildObjectArgument {
416 child_id: object.id(),
417 parent_id: owner,
418 }
419 .into()
420 )
421 }
422 Owner::Shared(_) => fp_bail!(UserInputError::NotSharedObject.into()),
423 Owner::Immutable => fp_bail!(
424 UserInputError::MutableParameterExpected {
425 object_id: object_ref.object_id
426 }
427 .into()
428 ),
429 _ => {
430 unimplemented!("a new Owner enum variant was added and needs to be handled")
431 }
432 };
433 }
434
435 fp_ensure!(
436 !objects_in_txn.contains(&object_ref.object_id),
437 UserInputError::DuplicateObjectRefInput.into()
438 );
439
440 objects_in_txn.insert(object_ref.object_id);
441 }
442 Ok(())
443 }
444
445 #[instrument(level = "trace", skip_all)]
448 fn check_gas(
449 objects: &InputObjects,
450 protocol_config: &ProtocolConfig,
451 reference_gas_price: u64,
452 gas: &[ObjectRef],
453 gas_price: u64,
454 transaction_gas_budget: u64,
455 authentication_gas_budget: u64,
456 is_execute_transaction_to_effects: bool,
457 ) -> IotaResult<IotaGasStatus> {
458 let gas_budget_to_set = if authentication_gas_budget > 0 {
459 let protocol_max_auth_gas =
462 protocol_config.max_auth_gas_as_option().ok_or_else(|| {
463 UserInputError::Unsupported(
464 "Transaction requires authentication gas but max_auth_gas is not enabled"
465 .to_string(),
466 )
467 })?;
468
469 if is_execute_transaction_to_effects {
476 transaction_gas_budget
477 } else {
478 authentication_gas_budget.min(protocol_max_auth_gas)
479 }
480 } else {
481 transaction_gas_budget
484 };
485
486 let gas_budget_to_check = transaction_gas_budget;
489
490 let gas_status = IotaGasStatus::new(
491 gas_budget_to_set,
492 gas_price,
493 reference_gas_price,
494 protocol_config,
495 )?;
496
497 let objects: BTreeMap<_, _> = objects.iter().map(|o| (o.id(), o)).collect();
500 let mut gas_objects = vec![];
501 for obj_ref in gas {
502 let obj = objects.get(&obj_ref.object_id);
503 let obj = *obj.ok_or(UserInputError::ObjectNotFound {
504 object_id: obj_ref.object_id,
505 version: Some(obj_ref.version),
506 })?;
507 gas_objects.push(obj);
508 }
509 gas_status.check_gas_balance(&gas_objects, gas_budget_to_check)?;
510 Ok(gas_status)
511 }
512
513 #[instrument(level = "trace", skip_all)]
516 fn check_objects(transaction: &TransactionData, objects: &InputObjects) -> UserInputResult<()> {
517 let mut used_objects: HashSet<IotaAddress> = HashSet::new();
519 for object in objects.iter() {
520 if object.is_mutable() {
521 fp_ensure!(
522 used_objects.insert(object.id().into()),
523 UserInputError::MutableObjectUsedMoreThanOnce {
524 object_id: object.id()
525 }
526 );
527 }
528 }
529
530 if !transaction.is_genesis_tx() && objects.is_empty() {
531 return Err(UserInputError::ObjectInputArityViolation);
532 }
533
534 let gas_coins: HashSet<ObjectId> =
535 HashSet::from_iter(transaction.gas().iter().map(|obj_ref| obj_ref.object_id));
536 for object in objects.iter() {
537 let input_object_kind = object.input_object_kind;
538
539 match &object.object {
540 ObjectReadResultKind::Object(object) => {
541 let owner_address = if gas_coins.contains(&object.id()) {
543 transaction.gas_owner()
544 } else {
545 transaction.sender()
546 };
547 let system_transaction = transaction.is_system_tx();
550 check_one_object(
551 &owner_address,
552 input_object_kind,
553 object,
554 system_transaction,
555 )?;
556 }
557 ObjectReadResultKind::DeletedSharedObject(_, _) => (),
559 ObjectReadResultKind::CancelledTransactionSharedObject(_) => (),
562 }
563 }
564
565 Ok(())
566 }
567
568 fn check_one_object(
570 owner: &IotaAddress,
571 object_kind: InputObjectKind,
572 object: &Object,
573 system_transaction: bool,
574 ) -> UserInputResult {
575 match object_kind {
576 InputObjectKind::MovePackage(package_id) => {
577 fp_ensure!(
578 object.data.as_package_opt().is_some(),
579 UserInputError::MoveObjectAsPackage {
580 object_id: package_id
581 }
582 );
583 }
584 InputObjectKind::ImmOrOwnedMoveObject(object_ref) => {
585 fp_ensure!(
586 !object.is_package(),
587 UserInputError::MovePackageAsObject {
588 object_id: object_ref.object_id
589 }
590 );
591 fp_ensure!(
592 object_ref.version < SequenceNumber::MAX_VALID_EXCL,
593 UserInputError::InvalidSequenceNumber
594 );
595
596 assert_eq!(
598 object.version(),
599 object_ref.version,
600 "The fetched object version {} does not match the requested version {}, object id: {}",
601 object.version(),
602 object_ref.version,
603 object.id(),
604 );
605
606 let expected_digest = object.digest();
608 fp_ensure!(
609 expected_digest == object_ref.digest,
610 UserInputError::InvalidObjectDigest {
611 object_id: object_ref.object_id,
612 expected_digest
613 }
614 );
615
616 match object.owner {
617 Owner::Immutable => {
618 }
620 Owner::Address(actual_owner) => {
621 fp_ensure!(
623 owner == &actual_owner,
624 UserInputError::IncorrectUserSignature {
625 error: format!(
626 "Object {} is owned by account address {}, but given owner/signer address is {}",
627 object_ref.object_id, actual_owner, owner
628 ),
629 }
630 );
631 }
632 Owner::Object(owner) => {
633 return Err(UserInputError::InvalidChildObjectArgument {
634 child_id: object.id(),
635 parent_id: owner,
636 });
637 }
638 Owner::Shared(_) => {
639 return Err(UserInputError::NotSharedObject);
642 }
643 _ => {
644 unimplemented!("a new Owner enum variant was added and needs to be handled")
645 }
646 };
647 }
648 InputObjectKind::SharedMoveObject {
649 id: ObjectId::CLOCK,
650 initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION,
651 mutable: true,
652 } => {
653 if system_transaction {
656 return Ok(());
657 } else {
658 return Err(UserInputError::ImmutableParameterExpected {
659 object_id: ObjectId::CLOCK,
660 });
661 }
662 }
663 InputObjectKind::SharedMoveObject {
664 id: ObjectId::AUTHENTICATOR_STATE,
665 ..
666 } => {
667 if system_transaction {
668 return Ok(());
669 } else {
670 return Err(UserInputError::InaccessibleSystemObject {
671 object_id: ObjectId::AUTHENTICATOR_STATE,
672 });
673 }
674 }
675 InputObjectKind::SharedMoveObject {
676 id: ObjectId::RANDOMNESS_STATE,
677 mutable: true,
678 ..
679 } => {
680 if system_transaction {
683 return Ok(());
684 } else {
685 return Err(UserInputError::ImmutableParameterExpected {
686 object_id: ObjectId::RANDOMNESS_STATE,
687 });
688 }
689 }
690 InputObjectKind::SharedMoveObject {
691 initial_shared_version: input_initial_shared_version,
692 ..
693 } => {
694 fp_ensure!(
695 object.version() < SequenceNumber::MAX_VALID_EXCL,
696 UserInputError::InvalidSequenceNumber
697 );
698
699 match object.owner {
700 Owner::Address(_) | Owner::Object(_) | Owner::Immutable => {
701 return Err(UserInputError::NotSharedObject);
703 }
704 Owner::Shared(actual_initial_shared_version) => {
705 fp_ensure!(
706 input_initial_shared_version == actual_initial_shared_version,
707 UserInputError::SharedObjectStartingVersionMismatch
708 )
709 }
710 _ => {
711 unimplemented!("a new Owner enum variant was added and needs to be handled")
712 }
713 }
714 }
715 };
716 Ok(())
717 }
718
719 #[instrument(level = "trace", skip_all)]
722 fn check_move_authenticator_objects(
723 authenticator_objects: &InputObjects,
724 ) -> UserInputResult<()> {
725 for object in authenticator_objects.iter() {
726 let input_object_kind = object.input_object_kind;
727
728 match &object.object {
729 ObjectReadResultKind::Object(object) => {
730 check_one_move_authenticator_object(input_object_kind, object)?;
731 }
732 ObjectReadResultKind::DeletedSharedObject(_, _) => (),
734 ObjectReadResultKind::CancelledTransactionSharedObject(_) => (),
737 }
738 }
739
740 Ok(())
741 }
742
743 fn check_one_move_authenticator_object(
745 object_kind: InputObjectKind,
746 object: &Object,
747 ) -> UserInputResult {
748 match object_kind {
749 InputObjectKind::MovePackage(package_id) => {
750 return Err(UserInputError::PackageIsInMoveAuthenticatorInput { package_id });
751 }
752 InputObjectKind::ImmOrOwnedMoveObject(object_ref) => {
753 fp_ensure!(
754 !object.is_package(),
755 UserInputError::MovePackageAsObject {
756 object_id: object_ref.object_id
757 }
758 );
759 fp_ensure!(
760 object_ref.version < SequenceNumber::MAX_VALID_EXCL,
761 UserInputError::InvalidSequenceNumber
762 );
763
764 assert_eq!(
766 object.version(),
767 object_ref.version,
768 "The fetched object version {} does not match the requested version {}, object id: {}",
769 object.version(),
770 object_ref.version,
771 object.id(),
772 );
773
774 let expected_digest = object.digest();
776 fp_ensure!(
777 expected_digest == object_ref.digest,
778 UserInputError::InvalidObjectDigest {
779 object_id: object_ref.object_id,
780 expected_digest
781 }
782 );
783
784 match object.owner {
785 Owner::Immutable => {
786 }
788 Owner::Address(_) => {
789 return Err(UserInputError::AddressOwnedIsInMoveAuthenticatorInput {
790 object_id: object.id(),
791 });
792 }
793 Owner::Object(_) => {
794 return Err(UserInputError::ObjectOwnedIsInMoveAuthenticatorInput {
795 object_id: object.id(),
796 });
797 }
798 Owner::Shared(_) => {
799 return Err(UserInputError::NotSharedObject);
802 }
803 _ => {
804 unimplemented!("a new Owner enum variant was added and needs to be handled")
805 }
806 };
807 }
808 InputObjectKind::SharedMoveObject {
809 id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
810 ..
811 } => {
812 return Err(UserInputError::InaccessibleSystemObject {
813 object_id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
814 });
815 }
816 InputObjectKind::SharedMoveObject {
817 id, mutable: true, ..
818 } => {
819 return Err(UserInputError::MutableSharedIsInMoveAuthenticatorInput {
820 object_id: id,
821 });
822 }
823 InputObjectKind::SharedMoveObject {
824 initial_shared_version: input_initial_shared_version,
825 ..
826 } => {
827 fp_ensure!(
828 object.version() < SequenceNumber::MAX_VALID_EXCL,
829 UserInputError::InvalidSequenceNumber
830 );
831
832 match object.owner {
833 Owner::Address(_) | Owner::Object(_) | Owner::Immutable => {
834 return Err(UserInputError::NotSharedObject);
836 }
837 Owner::Shared(actual_initial_shared_version) => {
838 fp_ensure!(
839 input_initial_shared_version == actual_initial_shared_version,
840 UserInputError::SharedObjectStartingVersionMismatch
841 )
842 }
843 _ => {
844 unimplemented!("a new Owner enum variant was added and needs to be handled")
845 }
846 }
847 }
848 };
849 Ok(())
850 }
851
852 fn checked_input_objects_union(
859 base_set: CheckedInputObjects,
860 other_set: &CheckedInputObjects,
861 ) -> IotaResult<CheckedInputObjects> {
862 let mut base_set = base_set.into_inner();
863 for other_object in other_set.inner().iter() {
864 if let Some(base_object) = base_set.find_object_id_mut(other_object.id()) {
865 assert_eq!(
867 base_object.object, other_object.object,
868 "The object read result for input objects with the same id must be equal"
869 );
870
871 if let ObjectReadResultKind::Object(_) = &other_object.object {
874 base_object
875 .input_object_kind
876 .left_union_with_checks(&other_object.input_object_kind)?;
877 }
878 } else {
879 base_set.push(other_object.clone());
880 }
881 }
882 Ok(base_set.into_checked())
883 }
884
885 #[instrument(level = "trace", skip_all)]
887 pub fn check_non_system_packages_to_be_published(
888 transaction: &TransactionData,
889 protocol_config: &ProtocolConfig,
890 metrics: &Arc<BytecodeVerifierMetrics>,
891 verifier_signing_config: &VerifierSigningConfig,
892 ) -> UserInputResult<()> {
893 if transaction.is_system_tx() {
895 return Ok(());
896 }
897
898 let TransactionKind::Programmable(pt) = transaction.kind() else {
899 return Ok(());
900 };
901
902 let signing_limits = Some(verifier_signing_config.limits_for_signing());
905 let mut verifier = iota_execution::verifier(protocol_config, signing_limits, metrics);
906 let mut meter = verifier.meter(verifier_signing_config.meter_config_for_signing());
907
908 let shared_meter_verifier_timer = metrics
910 .verifier_runtime_per_ptb_success_latency
911 .start_timer();
912
913 let verifier_status = pt
914 .non_system_packages_to_be_published()
915 .try_for_each(|module_bytes| {
916 verifier.meter_module_bytes(protocol_config, module_bytes, meter.as_mut())
917 })
918 .map_err(|e| UserInputError::PackageVerificationTimedout { err: e.to_string() });
919
920 match verifier_status {
921 Ok(_) => {
922 shared_meter_verifier_timer.stop_and_record();
924 }
925 Err(err) => {
926 metrics
929 .verifier_runtime_per_ptb_timeout_latency
930 .observe(shared_meter_verifier_timer.stop_and_discard());
931 return Err(err);
932 }
933 };
934
935 Ok(())
936 }
937}