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::{
19 Address, ObjectId, ObjectReference, Owner, Transaction, TransactionKind, Version,
20 };
21 use iota_types::{
22 IOTA_CLOCK_OBJECT_SHARED_VERSION,
23 error::{IotaError, IotaResult, UserInputError, UserInputResult},
24 executable_transaction::VerifiedExecutableTransaction,
25 fp_bail, fp_ensure,
26 gas::IotaGasStatus,
27 metrics::BytecodeVerifierMetrics,
28 object::Object,
29 transaction::{
30 CheckedInputObjects, InputObjectKind, InputObjects, ObjectReadResult,
31 ObjectReadResultKind, ProgrammableTransactionExt, ReceivingObjectReadResult,
32 ReceivingObjects, TransactionAPI, 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: &[ObjectReference],
54 protocol_config: &ProtocolConfig,
55 reference_gas_price: u64,
56 transaction: &Transaction,
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 #[derive(Clone, Copy, Debug)]
79 pub enum VerifierLimitsSource<'a> {
80 NodeConfig(&'a VerifierSigningConfig),
84
85 ProtocolConfig,
89 }
90
91 #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
92 pub fn check_transaction_input(
93 protocol_config: &ProtocolConfig,
94 reference_gas_price: u64,
95 transaction: &Transaction,
96 input_objects: InputObjects,
97 receiving_objects: &ReceivingObjects,
98 metrics: &Arc<BytecodeVerifierMetrics>,
99 verifier_limits_source: VerifierLimitsSource<'_>,
100 authentication_gas_budget: u64,
101 ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> {
102 let gas_status = check_transaction_input_inner(
103 protocol_config,
104 reference_gas_price,
105 transaction,
106 &input_objects,
107 &[],
108 authentication_gas_budget,
109 false,
110 )?;
111 check_receiving_objects(&input_objects, receiving_objects)?;
112 check_non_system_packages_to_be_published(
114 transaction,
115 protocol_config,
116 metrics,
117 verifier_limits_source,
118 )?;
119
120 Ok((gas_status, input_objects.into_checked()))
121 }
122
123 #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
124 pub fn check_transaction_input_with_given_gas(
125 protocol_config: &ProtocolConfig,
126 reference_gas_price: u64,
127 transaction: &Transaction,
128 mut input_objects: InputObjects,
129 receiving_objects: ReceivingObjects,
130 gas_object: Object,
131 metrics: &Arc<BytecodeVerifierMetrics>,
132 verifier_limits_source: VerifierLimitsSource<'_>,
133 ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> {
134 let gas_object_ref = gas_object.object_ref();
135 input_objects.push(ObjectReadResult::new_from_gas_object(&gas_object));
136
137 let gas_status = check_transaction_input_inner(
138 protocol_config,
139 reference_gas_price,
140 transaction,
141 &input_objects,
142 &[gas_object_ref],
143 0,
144 true,
145 )?;
146 check_receiving_objects(&input_objects, &receiving_objects)?;
147 check_non_system_packages_to_be_published(
149 transaction,
150 protocol_config,
151 metrics,
152 verifier_limits_source,
153 )?;
154
155 Ok((gas_status, input_objects.into_checked()))
156 }
157
158 #[instrument(level = "trace", skip_all)]
164 pub fn check_certificate_input(
165 cert: &VerifiedExecutableTransaction,
166 input_objects: InputObjects,
167 protocol_config: &ProtocolConfig,
168 reference_gas_price: u64,
169 ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> {
170 let transaction = cert.data().transaction();
171 let gas_status = check_transaction_input_inner(
172 protocol_config,
173 reference_gas_price,
174 transaction,
175 &input_objects,
176 &[],
177 0,
178 true,
179 )?;
180 Ok((gas_status, input_objects.into_checked()))
185 }
186
187 #[instrument(level = "trace", skip_all)]
193 pub fn check_simulation_input(
194 config: &ProtocolConfig,
195 kind: &TransactionKind,
196 input_objects: InputObjects,
197 _receiving_objects: ReceivingObjects,
199 ) -> IotaResult<CheckedInputObjects> {
200 kind.validity_check(config)?;
201 if kind.is_system() {
202 return Err(UserInputError::Unsupported(format!(
203 "Transaction kind {kind} is not supported in a simulation"
204 ))
205 .into());
206 }
207 let mut used_objects: HashSet<Address> = HashSet::new();
208 for input_object in input_objects.iter() {
209 let Some(object) = input_object.as_object() else {
210 continue;
212 };
213
214 if !object.is_immutable() {
215 fp_ensure!(
216 used_objects.insert(object.id().into()),
217 UserInputError::MutableObjectUsedMoreThanOnce {
218 object_id: object.id()
219 }
220 .into()
221 );
222 }
223 }
224
225 Ok(input_objects.into_checked())
226 }
227
228 #[instrument(level = "trace", skip_all)]
234 pub fn check_move_authenticator_input_for_validation(
235 authenticator_input_objects: InputObjects,
236 ) -> IotaResult<CheckedInputObjects> {
237 check_move_authenticator_objects(&authenticator_input_objects)?;
238
239 Ok(authenticator_input_objects.into_checked())
240 }
241
242 pub fn aggregate_authenticator_input_objects(
246 per_authenticator_checked_input_objects: &[&CheckedInputObjects],
247 ) -> IotaResult<CheckedInputObjects> {
248 let mut aggregated_authenticator_input_objects =
249 CheckedInputObjects::new_with_checked_transaction_inputs(InputObjects::new(vec![]));
250
251 for authenticator_checked_input_objects in per_authenticator_checked_input_objects.iter() {
252 aggregated_authenticator_input_objects = checked_input_objects_union(
253 aggregated_authenticator_input_objects,
254 authenticator_checked_input_objects,
255 )?;
256 }
257
258 Ok(aggregated_authenticator_input_objects)
259 }
260
261 #[instrument(level = "trace", skip_all)]
273 pub fn check_certificate_and_move_authenticator_input(
274 cert: &VerifiedExecutableTransaction,
275 tx_input_objects: InputObjects,
276 per_authenticator_input_objects: Vec<InputObjects>,
277 authenticator_gas_budget: u64,
278 protocol_config: &ProtocolConfig,
279 reference_gas_price: u64,
280 ) -> IotaResult<(IotaGasStatus, Vec<CheckedInputObjects>, CheckedInputObjects)> {
281 per_authenticator_input_objects
283 .iter()
284 .try_for_each(check_move_authenticator_objects)?;
285
286 let transaction = cert.data().transaction();
288 let gas_status = check_transaction_input_inner(
289 protocol_config,
290 reference_gas_price,
291 transaction,
292 &tx_input_objects,
293 &[],
294 authenticator_gas_budget,
295 true,
296 )?;
297
298 let per_authenticator_checked_input_objects = per_authenticator_input_objects
299 .into_iter()
300 .map(|objects| objects.into_checked())
301 .collect::<Vec<_>>();
302
303 let mut input_objects_union = tx_input_objects.into_checked();
305 for objects in per_authenticator_checked_input_objects.iter() {
306 input_objects_union = checked_input_objects_union(input_objects_union, objects)?;
307 }
308
309 Ok((
310 gas_status,
311 per_authenticator_checked_input_objects,
312 input_objects_union,
313 ))
314 }
315
316 fn check_transaction_input_inner(
318 protocol_config: &ProtocolConfig,
319 reference_gas_price: u64,
320 transaction: &Transaction,
321 input_objects: &InputObjects,
322 gas_override: &[ObjectReference],
324 authentication_gas_budget: u64,
325 is_execute_transaction_to_effects: bool,
326 ) -> IotaResult<IotaGasStatus> {
327 let gas = if gas_override.is_empty() {
329 transaction.gas()
330 } else {
331 gas_override
332 };
333
334 let gas_status = get_gas_status(
335 input_objects,
336 gas,
337 protocol_config,
338 reference_gas_price,
339 transaction,
340 authentication_gas_budget,
341 is_execute_transaction_to_effects,
342 )?;
343 check_objects(transaction, input_objects)?;
344
345 Ok(gas_status)
346 }
347
348 fn input_object_ids(input_objects: &InputObjects) -> HashSet<ObjectId> {
349 input_objects
350 .object_kinds()
351 .map(|x| x.object_id())
352 .collect()
353 }
354
355 fn check_receiving_version_bound(object_ref: &ObjectReference) -> Result<(), IotaError> {
356 fp_ensure!(
357 object_ref.version < Version::MAX_VALID_EXCL,
358 UserInputError::InvalidSequenceNumber.into()
359 );
360 Ok(())
361 }
362
363 fn check_not_already_in_transaction(
364 objects_in_txn: &mut HashSet<ObjectId>,
365 object_ref: &ObjectReference,
366 ) -> Result<(), IotaError> {
367 fp_ensure!(
368 objects_in_txn.insert(object_ref.object_id),
369 UserInputError::DuplicateObjectRefInput.into()
370 );
371 Ok(())
372 }
373
374 #[instrument(level = "trace", skip_all)]
375 fn check_receiving_objects(
376 input_objects: &InputObjects,
377 receiving_objects: &ReceivingObjects,
378 ) -> Result<(), IotaError> {
379 let mut objects_in_txn = input_object_ids(input_objects);
380
381 for ReceivingObjectReadResult { object_ref, object } in receiving_objects.iter() {
390 check_receiving_version_bound(object_ref)?;
391
392 let Some(object) = object.as_object() else {
393 continue;
395 };
396
397 if !(object.owner.is_address()
398 && object.version() == object_ref.version
399 && object.digest() == object_ref.digest)
400 {
401 fp_ensure!(
403 object.version() == object_ref.version,
404 UserInputError::ObjectVersionUnavailableForConsumption {
405 provided_obj_ref: *object_ref,
406 current_version: object.version(),
407 }
408 .into()
409 );
410
411 fp_ensure!(
413 !object.is_package(),
414 UserInputError::MovePackageAsObject {
415 object_id: object_ref.object_id
416 }
417 .into()
418 );
419
420 let expected_digest = object.digest();
422 fp_ensure!(
423 expected_digest == object_ref.digest,
424 UserInputError::InvalidObjectDigest {
425 object_id: object_ref.object_id,
426 expected_digest
427 }
428 .into()
429 );
430
431 match object.owner {
432 Owner::Address(_) => {
433 debug_assert!(
434 false,
435 "Receiving object {object_ref:?} is invalid but we expect it should be valid. {object:?}"
436 );
437 error!(
438 "Receiving object {:?} is invalid but we expect it should be valid. {:?}",
439 object_ref, object
440 );
441 fp_bail!(
444 UserInputError::ObjectNotFound {
445 object_id: object_ref.object_id,
446 version: Some(object_ref.version),
447 }
448 .into()
449 )
450 }
451 Owner::Object(owner) => {
452 fp_bail!(
453 UserInputError::InvalidChildObjectArgument {
454 child_id: object.id(),
455 parent_id: owner,
456 }
457 .into()
458 )
459 }
460 Owner::Shared(_) => fp_bail!(UserInputError::NotSharedObject.into()),
461 Owner::Immutable => fp_bail!(
462 UserInputError::MutableParameterExpected {
463 object_id: object_ref.object_id
464 }
465 .into()
466 ),
467 _ => {
468 unimplemented!("a new Owner enum variant was added and needs to be handled")
469 }
470 };
471 }
472
473 check_not_already_in_transaction(&mut objects_in_txn, object_ref)?;
474 }
475 Ok(())
476 }
477
478 #[instrument(level = "trace", skip_all)]
481 fn check_gas(
482 objects: &InputObjects,
483 protocol_config: &ProtocolConfig,
484 reference_gas_price: u64,
485 gas: &[ObjectReference],
486 gas_price: u64,
487 transaction_gas_budget: u64,
488 authentication_gas_budget: u64,
489 is_execute_transaction_to_effects: bool,
490 ) -> IotaResult<IotaGasStatus> {
491 let gas_budget_to_set = if authentication_gas_budget > 0 {
492 let protocol_max_auth_gas =
495 protocol_config.max_auth_gas_as_option().ok_or_else(|| {
496 UserInputError::Unsupported(
497 "Transaction requires authentication gas but max_auth_gas is not enabled"
498 .to_string(),
499 )
500 })?;
501
502 if is_execute_transaction_to_effects {
509 transaction_gas_budget
510 } else {
511 authentication_gas_budget.min(protocol_max_auth_gas)
512 }
513 } else {
514 transaction_gas_budget
517 };
518
519 let gas_budget_to_check = transaction_gas_budget;
522
523 let gas_status = IotaGasStatus::new(
524 gas_budget_to_set,
525 gas_price,
526 reference_gas_price,
527 protocol_config,
528 )?;
529
530 let objects: BTreeMap<_, _> = objects.iter().map(|o| (o.id(), o)).collect();
533 let mut gas_objects = vec![];
534 for obj_ref in gas {
535 let obj = objects.get(&obj_ref.object_id);
536 let obj = *obj.ok_or(UserInputError::ObjectNotFound {
537 object_id: obj_ref.object_id,
538 version: Some(obj_ref.version),
539 })?;
540 gas_objects.push(obj);
541 }
542 gas_status.check_gas_balance(&gas_objects, gas_budget_to_check)?;
543 Ok(gas_status)
544 }
545
546 #[instrument(level = "trace", skip_all)]
549 fn check_objects(transaction: &Transaction, objects: &InputObjects) -> UserInputResult<()> {
550 let mut used_objects: HashSet<Address> = HashSet::new();
552 for object in objects.iter() {
553 if object.is_mutable() {
554 fp_ensure!(
555 used_objects.insert(object.id().into()),
556 UserInputError::MutableObjectUsedMoreThanOnce {
557 object_id: object.id()
558 }
559 );
560 }
561 }
562
563 if !transaction.is_genesis_tx() && objects.is_empty() {
564 return Err(UserInputError::ObjectInputArityViolation);
565 }
566
567 let gas_coins: HashSet<ObjectId> =
568 HashSet::from_iter(transaction.gas().iter().map(|obj_ref| obj_ref.object_id));
569 for object in objects.iter() {
570 let input_object_kind = object.input_object_kind;
571
572 match &object.object {
573 ObjectReadResultKind::Object(object) => {
574 let owner_address = if gas_coins.contains(&object.id()) {
576 transaction.gas_owner()
577 } else {
578 transaction.sender()
579 };
580 let system_transaction = transaction.is_system_tx();
583 check_one_object(
584 &owner_address,
585 input_object_kind,
586 object,
587 system_transaction,
588 )?;
589 }
590 ObjectReadResultKind::DeletedSharedObject(_, _) => (),
592 ObjectReadResultKind::CancelledTransactionObject(_) => (),
595 ObjectReadResultKind::UnreadSharedObject => {
598 check_shared_object_declaration(
599 &input_object_kind,
600 transaction.is_system_tx(),
601 )?;
602 }
603 }
604 }
605
606 Ok(())
607 }
608
609 fn check_one_object(
611 owner: &Address,
612 object_kind: InputObjectKind,
613 object: &Object,
614 system_transaction: bool,
615 ) -> UserInputResult {
616 match object_kind {
617 InputObjectKind::MovePackage(package_id) => {
618 fp_ensure!(
619 object.data.as_opt_package().is_some(),
620 UserInputError::MoveObjectAsPackage {
621 object_id: package_id
622 }
623 );
624 }
625 InputObjectKind::ImmOrOwnedMoveObject(object_ref) => {
626 fp_ensure!(
627 !object.is_package(),
628 UserInputError::MovePackageAsObject {
629 object_id: object_ref.object_id
630 }
631 );
632 fp_ensure!(
633 object_ref.version < Version::MAX_VALID_EXCL,
634 UserInputError::InvalidSequenceNumber
635 );
636
637 assert_eq!(
639 object.version(),
640 object_ref.version,
641 "The fetched object version {} does not match the requested version {}, object id: {}",
642 object.version(),
643 object_ref.version,
644 object.id(),
645 );
646
647 let expected_digest = object.digest();
649 fp_ensure!(
650 expected_digest == object_ref.digest,
651 UserInputError::InvalidObjectDigest {
652 object_id: object_ref.object_id,
653 expected_digest
654 }
655 );
656
657 match object.owner {
658 Owner::Immutable => {
659 }
661 Owner::Address(actual_owner) => {
662 fp_ensure!(
664 owner == &actual_owner,
665 UserInputError::IncorrectUserSignature {
666 error: format!(
667 "Object {} is owned by account address {}, but given owner/signer address is {}",
668 object_ref.object_id, actual_owner, owner
669 ),
670 }
671 );
672 }
673 Owner::Object(owner) => {
674 return Err(UserInputError::InvalidChildObjectArgument {
675 child_id: object.id(),
676 parent_id: owner,
677 });
678 }
679 Owner::Shared(_) => {
680 return Err(UserInputError::NotSharedObject);
683 }
684 _ => {
685 unimplemented!("a new Owner enum variant was added and needs to be handled")
686 }
687 };
688 }
689 InputObjectKind::SharedMoveObject {
690 initial_shared_version: input_initial_shared_version,
691 ..
692 } => {
693 if check_shared_object_declaration(&object_kind, system_transaction)? {
694 return Ok(());
695 }
696
697 fp_ensure!(
698 object.version() < Version::MAX_VALID_EXCL,
699 UserInputError::InvalidSequenceNumber
700 );
701
702 match object.owner {
703 Owner::Address(_) | Owner::Object(_) | Owner::Immutable => {
704 return Err(UserInputError::NotSharedObject);
706 }
707 Owner::Shared(actual_initial_shared_version) => {
708 fp_ensure!(
709 input_initial_shared_version == actual_initial_shared_version,
710 UserInputError::SharedObjectStartingVersionMismatch
711 )
712 }
713 _ => {
714 unimplemented!("a new Owner enum variant was added and needs to be handled")
715 }
716 }
717 }
718 };
719
720 Ok(())
721 }
722
723 fn check_shared_object_declaration(
730 object_kind: &InputObjectKind,
731 system_transaction: bool,
732 ) -> UserInputResult<bool> {
733 match object_kind {
734 InputObjectKind::SharedMoveObject {
735 id: ObjectId::CLOCK,
736 initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION,
737 mutable: true,
738 } => {
739 if system_transaction {
742 Ok(true)
743 } else {
744 Err(UserInputError::ImmutableParameterExpected {
745 object_id: ObjectId::CLOCK,
746 })
747 }
748 }
749 InputObjectKind::SharedMoveObject {
750 id: ObjectId::AUTHENTICATOR_STATE,
751 ..
752 } => {
753 if system_transaction {
754 Ok(true)
755 } else {
756 Err(UserInputError::InaccessibleSystemObject {
757 object_id: ObjectId::AUTHENTICATOR_STATE,
758 })
759 }
760 }
761 InputObjectKind::SharedMoveObject {
762 id: ObjectId::RANDOMNESS_STATE,
763 mutable: true,
764 ..
765 } => {
766 if system_transaction {
769 Ok(true)
770 } else {
771 Err(UserInputError::ImmutableParameterExpected {
772 object_id: ObjectId::RANDOMNESS_STATE,
773 })
774 }
775 }
776 InputObjectKind::SharedMoveObject {
777 id: ObjectId::TRANSACTION_DENY_RULES,
778 ..
779 } => {
780 if system_transaction {
783 Ok(true)
784 } else {
785 Err(UserInputError::InaccessibleSystemObject {
786 object_id: ObjectId::TRANSACTION_DENY_RULES,
787 })
788 }
789 }
790 _ => Ok(false),
791 }
792 }
793
794 #[instrument(level = "trace", skip_all)]
798 fn check_move_authenticator_objects(
799 authenticator_objects: &InputObjects,
800 ) -> UserInputResult<()> {
801 for object in authenticator_objects.iter() {
802 let input_object_kind = object.input_object_kind;
803
804 match &object.object {
805 ObjectReadResultKind::Object(object) => {
806 check_one_move_authenticator_object(input_object_kind, object)?;
807 }
808 ObjectReadResultKind::DeletedSharedObject(_, _) => (),
810 ObjectReadResultKind::CancelledTransactionObject(_) => (),
813 ObjectReadResultKind::UnreadSharedObject => {
816 check_move_authenticator_shared_object_declaration(&input_object_kind)?;
817 }
818 }
819 }
820
821 Ok(())
822 }
823
824 fn check_one_move_authenticator_object(
826 object_kind: InputObjectKind,
827 object: &Object,
828 ) -> UserInputResult {
829 match object_kind {
830 InputObjectKind::MovePackage(package_id) => {
831 return Err(UserInputError::PackageIsInMoveAuthenticatorInput { package_id });
832 }
833 InputObjectKind::ImmOrOwnedMoveObject(object_ref) => {
834 fp_ensure!(
835 !object.is_package(),
836 UserInputError::MovePackageAsObject {
837 object_id: object_ref.object_id
838 }
839 );
840 fp_ensure!(
841 object_ref.version < Version::MAX_VALID_EXCL,
842 UserInputError::InvalidSequenceNumber
843 );
844
845 assert_eq!(
847 object.version(),
848 object_ref.version,
849 "The fetched object version {} does not match the requested version {}, object id: {}",
850 object.version(),
851 object_ref.version,
852 object.id(),
853 );
854
855 let expected_digest = object.digest();
857 fp_ensure!(
858 expected_digest == object_ref.digest,
859 UserInputError::InvalidObjectDigest {
860 object_id: object_ref.object_id,
861 expected_digest
862 }
863 );
864
865 match object.owner {
866 Owner::Immutable => {
867 }
869 Owner::Address(_) => {
870 return Err(UserInputError::AddressOwnedIsInMoveAuthenticatorInput {
871 object_id: object.id(),
872 });
873 }
874 Owner::Object(_) => {
875 return Err(UserInputError::ObjectOwnedIsInMoveAuthenticatorInput {
876 object_id: object.id(),
877 });
878 }
879 Owner::Shared(_) => {
880 return Err(UserInputError::NotSharedObject);
883 }
884 _ => {
885 unimplemented!("a new Owner enum variant was added and needs to be handled")
886 }
887 };
888 }
889 InputObjectKind::SharedMoveObject {
890 id: ObjectId::AUTHENTICATOR_STATE,
891 ..
892 } => {
893 return Err(UserInputError::InaccessibleSystemObject {
894 object_id: ObjectId::AUTHENTICATOR_STATE,
895 });
896 }
897 InputObjectKind::SharedMoveObject {
898 id, mutable: true, ..
899 } => {
900 return Err(UserInputError::MutableSharedIsInMoveAuthenticatorInput {
901 object_id: id,
902 });
903 }
904 InputObjectKind::SharedMoveObject {
905 initial_shared_version: input_initial_shared_version,
906 ..
907 } => {
908 fp_ensure!(
909 object.version() < Version::MAX_VALID_EXCL,
910 UserInputError::InvalidSequenceNumber
911 );
912
913 match object.owner {
914 Owner::Address(_) | Owner::Object(_) | Owner::Immutable => {
915 return Err(UserInputError::NotSharedObject);
917 }
918 Owner::Shared(actual_initial_shared_version) => {
919 fp_ensure!(
920 input_initial_shared_version == actual_initial_shared_version,
921 UserInputError::SharedObjectStartingVersionMismatch
922 )
923 }
924 _ => {
925 unimplemented!("a new Owner enum variant was added and needs to be handled")
926 }
927 }
928 }
929 };
930 Ok(())
931 }
932
933 fn check_move_authenticator_shared_object_declaration(
937 object_kind: &InputObjectKind,
938 ) -> UserInputResult {
939 match object_kind {
940 InputObjectKind::SharedMoveObject {
941 id: ObjectId::AUTHENTICATOR_STATE,
942 ..
943 } => Err(UserInputError::InaccessibleSystemObject {
944 object_id: ObjectId::AUTHENTICATOR_STATE,
945 }),
946 InputObjectKind::SharedMoveObject {
947 id, mutable: true, ..
948 } => Err(UserInputError::MutableSharedIsInMoveAuthenticatorInput { object_id: *id }),
949 _ => Ok(()),
950 }
951 }
952
953 pub fn checked_input_objects_union(
960 base_set: CheckedInputObjects,
961 other_set: &CheckedInputObjects,
962 ) -> IotaResult<CheckedInputObjects> {
963 let mut base_set = base_set.into_inner();
964 for other_object in other_set.inner().iter() {
965 if let Some(base_object) = base_set.find_object_id_mut(other_object.id()) {
966 assert_eq!(
968 base_object.object, other_object.object,
969 "The object read result for input objects with the same id must be equal"
970 );
971
972 if let ObjectReadResultKind::Object(_) = &other_object.object {
975 base_object
976 .input_object_kind
977 .left_union_with_checks(&other_object.input_object_kind)?;
978 }
979 } else {
980 base_set.push(other_object.clone());
981 }
982 }
983 Ok(base_set.into_checked())
984 }
985
986 #[instrument(level = "trace", skip_all)]
988 pub fn check_non_system_packages_to_be_published(
989 transaction: &Transaction,
990 protocol_config: &ProtocolConfig,
991 metrics: &Arc<BytecodeVerifierMetrics>,
992 verifier_limits_source: VerifierLimitsSource<'_>,
993 ) -> UserInputResult<()> {
994 if transaction.is_system_tx() {
996 return Ok(());
997 }
998
999 let TransactionKind::Programmable(pt) = transaction.kind() else {
1000 return Ok(());
1001 };
1002
1003 let (signing_limits, meter_config) = match verifier_limits_source {
1005 VerifierLimitsSource::NodeConfig(config) => (
1006 config.limits_for_signing(),
1007 config.meter_config_for_signing(),
1008 ),
1009 VerifierLimitsSource::ProtocolConfig => (
1010 protocol_config.verifier_signing_limits(),
1011 protocol_config.meter_config(),
1012 ),
1013 };
1014 let mut verifier = iota_execution::verifier(protocol_config, Some(signing_limits), metrics);
1015 let mut meter = verifier.meter(meter_config);
1016
1017 let shared_meter_verifier_timer = metrics
1019 .verifier_runtime_per_ptb_success_latency
1020 .start_timer();
1021
1022 let verifier_status = pt
1023 .non_system_packages_to_be_published()
1024 .try_for_each(|module_bytes| {
1025 verifier.meter_module_bytes(protocol_config, module_bytes, meter.as_mut())
1026 })
1027 .map_err(|e| UserInputError::PackageVerificationTimedout { err: e.to_string() });
1028
1029 match verifier_status {
1030 Ok(_) => {
1031 shared_meter_verifier_timer.stop_and_record();
1033 }
1034 Err(err) => {
1035 metrics
1038 .verifier_runtime_per_ptb_timeout_latency
1039 .observe(shared_meter_verifier_timer.stop_and_discard());
1040 return Err(err);
1041 }
1042 };
1043
1044 Ok(())
1045 }
1046}