1pub use checked::*;
6
7#[iota_macros::with_checked_arithmetic]
8mod checked {
9
10 use std::{collections::HashSet, sync::Arc};
11
12 use iota_move_natives::all_natives;
13 use iota_protocol_config::{LimitThresholdCrossed, ProtocolConfig, check_limit_by_meter};
14 #[cfg(msim)]
15 use iota_types::iota_system_state::advance_epoch_result_injection::maybe_modify_result;
16 use iota_types::{
17 IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_FRAMEWORK_ADDRESS, IOTA_FRAMEWORK_PACKAGE_ID,
18 IOTA_RANDOMNESS_STATE_OBJECT_ID, IOTA_SYSTEM_PACKAGE_ID,
19 authenticator_state::{
20 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME,
21 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME, AUTHENTICATOR_STATE_MODULE_NAME,
22 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME,
23 },
24 balance::{
25 BALANCE_CREATE_REWARDS_FUNCTION_NAME, BALANCE_DESTROY_REBATES_FUNCTION_NAME,
26 BALANCE_MODULE_NAME,
27 },
28 base_types::{
29 IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, TxContext,
30 },
31 clock::{CLOCK_MODULE_NAME, CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME},
32 committee::EpochId,
33 effects::TransactionEffects,
34 error::{ExecutionError, ExecutionErrorKind},
35 execution::{ExecutionResults, ExecutionResultsV1, is_certificate_denied},
36 execution_config_utils::to_binary_config,
37 execution_status::{CongestedObjects, ExecutionStatus},
38 gas::{GasCostSummary, IotaGasStatus},
39 gas_coin::GAS,
40 inner_temporary_store::InnerTemporaryStore,
41 iota_system_state::{
42 ADVANCE_EPOCH_FUNCTION_NAME, AdvanceEpochParams, IOTA_SYSTEM_MODULE_NAME,
43 },
44 messages_checkpoint::CheckpointTimestamp,
45 metrics::LimitsMetrics,
46 object::{OBJECT_START_VERSION, Object, ObjectInner},
47 programmable_transaction_builder::ProgrammableTransactionBuilder,
48 randomness_state::{RANDOMNESS_MODULE_NAME, RANDOMNESS_STATE_UPDATE_FUNCTION_NAME},
49 storage::{BackingStore, Storage},
50 transaction::{
51 Argument, AuthenticatorStateExpire, AuthenticatorStateUpdateV1, CallArg, ChangeEpoch,
52 ChangeEpochV2, ChangeEpochV3, CheckedInputObjects, Command, EndOfEpochTransactionKind,
53 GenesisTransaction, ObjectArg, ProgrammableTransaction, RandomnessStateUpdate,
54 TransactionKind,
55 },
56 };
57 use move_binary_format::CompiledModule;
58 use move_trace_format::format::MoveTraceBuilder;
59 use move_vm_runtime::move_vm::MoveVM;
60 use tracing::{info, instrument, trace, warn};
61
62 use crate::{
63 adapter::new_move_vm,
64 execution_mode::{self, ExecutionMode},
65 gas_charger::GasCharger,
66 programmable_transactions,
67 temporary_store::TemporaryStore,
68 type_layout_resolver::TypeLayoutResolver,
69 };
70
71 #[instrument(name = "tx_execute_to_effects", level = "debug", skip_all)]
83 pub fn execute_transaction_to_effects<Mode: ExecutionMode>(
84 store: &dyn BackingStore,
85 input_objects: CheckedInputObjects,
86 gas_coins: Vec<ObjectRef>,
87 gas_status: IotaGasStatus,
88 transaction_kind: TransactionKind,
89 transaction_signer: IotaAddress,
90 transaction_digest: TransactionDigest,
91 move_vm: &Arc<MoveVM>,
92 epoch_id: &EpochId,
93 epoch_timestamp_ms: u64,
94 protocol_config: &ProtocolConfig,
95 metrics: Arc<LimitsMetrics>,
96 enable_expensive_checks: bool,
97 certificate_deny_set: &HashSet<TransactionDigest>,
98 trace_builder_opt: &mut Option<MoveTraceBuilder>,
99 ) -> (
100 InnerTemporaryStore,
101 IotaGasStatus,
102 TransactionEffects,
103 Result<Mode::ExecutionResults, ExecutionError>,
104 ) {
105 let input_objects = input_objects.into_inner();
106 let mutable_inputs = if enable_expensive_checks {
107 input_objects.mutable_inputs().keys().copied().collect()
108 } else {
109 HashSet::new()
110 };
111 let shared_object_refs = input_objects.filter_shared_objects();
112 let receiving_objects = transaction_kind.receiving_objects();
113 let mut transaction_dependencies = input_objects.transaction_dependencies();
114 let contains_deleted_input = input_objects.contains_deleted_objects();
115 let cancelled_objects = input_objects.get_cancelled_objects();
116
117 let mut temporary_store = TemporaryStore::new(
118 store,
119 input_objects,
120 receiving_objects,
121 transaction_digest,
122 protocol_config,
123 *epoch_id,
124 );
125
126 let mut gas_charger =
127 GasCharger::new(transaction_digest, gas_coins, gas_status, protocol_config);
128
129 let mut tx_ctx = TxContext::new_from_components(
130 &transaction_signer,
131 &transaction_digest,
132 epoch_id,
133 epoch_timestamp_ms,
134 );
135
136 let is_epoch_change = transaction_kind.is_end_of_epoch_tx();
137
138 let deny_cert = is_certificate_denied(&transaction_digest, certificate_deny_set);
139 let (gas_cost_summary, execution_result) = execute_transaction::<Mode>(
140 &mut temporary_store,
141 transaction_kind,
142 &mut gas_charger,
143 &mut tx_ctx,
144 move_vm,
145 protocol_config,
146 metrics,
147 enable_expensive_checks,
148 deny_cert,
149 contains_deleted_input,
150 cancelled_objects,
151 trace_builder_opt,
152 );
153
154 let status = if let Err(error) = &execution_result {
155 use ExecutionErrorKind as K;
157 match error.kind() {
158 K::InvariantViolation | K::VMInvariantViolation => {
159 #[skip_checked_arithmetic]
160 tracing::error!(
161 kind = ?error.kind(),
162 tx_digest = ?transaction_digest,
163 "INVARIANT VIOLATION! Source: {:?}",
164 error.source(),
165 );
166 }
167
168 K::IotaMoveVerificationError | K::VMVerificationOrDeserializationError => {
169 #[skip_checked_arithmetic]
170 tracing::debug!(
171 kind = ?error.kind(),
172 tx_digest = ?transaction_digest,
173 "Verification Error. Source: {:?}",
174 error.source(),
175 );
176 }
177
178 K::PublishUpgradeMissingDependency | K::PublishUpgradeDependencyDowngrade => {
179 #[skip_checked_arithmetic]
180 tracing::debug!(
181 kind = ?error.kind(),
182 tx_digest = ?transaction_digest,
183 "Publish/Upgrade Error. Source: {:?}",
184 error.source(),
185 )
186 }
187
188 _ => (),
189 };
190
191 let (status, command) = error.to_execution_status();
192 ExecutionStatus::new_failure(status, command)
193 } else {
194 ExecutionStatus::Success
195 };
196
197 #[skip_checked_arithmetic]
198 trace!(
199 tx_digest = ?transaction_digest,
200 computation_gas_cost = gas_cost_summary.computation_cost,
201 computation_gas_cost_burned = gas_cost_summary.computation_cost_burned,
202 storage_gas_cost = gas_cost_summary.storage_cost,
203 storage_gas_rebate = gas_cost_summary.storage_rebate,
204 "Finished execution of transaction with status {:?}",
205 status
206 );
207
208 transaction_dependencies.remove(&TransactionDigest::genesis_marker());
212
213 if enable_expensive_checks && !Mode::allow_arbitrary_function_calls() {
214 temporary_store
215 .check_ownership_invariants(
216 &transaction_signer,
217 &mut gas_charger,
218 &mutable_inputs,
219 is_epoch_change,
220 )
221 .unwrap()
222 } let (inner, effects) = temporary_store.into_effects(
225 shared_object_refs,
226 &transaction_digest,
227 transaction_dependencies,
228 gas_cost_summary,
229 status,
230 &mut gas_charger,
231 *epoch_id,
232 );
233
234 (
235 inner,
236 gas_charger.into_gas_status(),
237 effects,
238 execution_result,
239 )
240 }
241
242 pub fn execute_genesis_state_update(
249 store: &dyn BackingStore,
250 protocol_config: &ProtocolConfig,
251 metrics: Arc<LimitsMetrics>,
252 move_vm: &Arc<MoveVM>,
253 tx_context: &mut TxContext,
254 input_objects: CheckedInputObjects,
255 pt: ProgrammableTransaction,
256 ) -> Result<InnerTemporaryStore, ExecutionError> {
257 let input_objects = input_objects.into_inner();
258 let mut temporary_store = TemporaryStore::new(
259 store,
260 input_objects,
261 vec![],
262 tx_context.digest(),
263 protocol_config,
264 0,
265 );
266 let mut gas_charger = GasCharger::new_unmetered(tx_context.digest());
267 programmable_transactions::execution::execute::<execution_mode::Genesis>(
268 protocol_config,
269 metrics,
270 move_vm,
271 &mut temporary_store,
272 tx_context,
273 &mut gas_charger,
274 pt,
275 &mut None,
276 )?;
277 temporary_store.update_object_version_and_prev_tx();
278 Ok(temporary_store.into_inner())
279 }
280
281 #[instrument(name = "tx_execute", level = "debug", skip_all)]
290 fn execute_transaction<Mode: ExecutionMode>(
291 temporary_store: &mut TemporaryStore<'_>,
292 transaction_kind: TransactionKind,
293 gas_charger: &mut GasCharger,
294 tx_ctx: &mut TxContext,
295 move_vm: &Arc<MoveVM>,
296 protocol_config: &ProtocolConfig,
297 metrics: Arc<LimitsMetrics>,
298 enable_expensive_checks: bool,
299 deny_cert: bool,
300 contains_deleted_input: bool,
301 cancelled_objects: Option<(Vec<ObjectID>, SequenceNumber)>,
302 trace_builder_opt: &mut Option<MoveTraceBuilder>,
303 ) -> (
304 GasCostSummary,
305 Result<Mode::ExecutionResults, ExecutionError>,
306 ) {
307 gas_charger.smash_gas(temporary_store);
308
309 debug_assert!(
311 gas_charger.no_charges(),
312 "No gas charges must be applied yet"
313 );
314
315 let is_genesis_or_epoch_change_tx = matches!(transaction_kind, TransactionKind::Genesis(_))
316 || transaction_kind.is_end_of_epoch_tx();
317
318 let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary();
319
320 let result = gas_charger.charge_input_objects(temporary_store);
324 let mut result = result.and_then(|()| {
325 let mut execution_result = if deny_cert {
326 Err(ExecutionError::new(
327 ExecutionErrorKind::CertificateDenied,
328 None,
329 ))
330 } else if contains_deleted_input {
331 Err(ExecutionError::new(
332 ExecutionErrorKind::InputObjectDeleted,
333 None,
334 ))
335 } else if let Some((cancelled_objects, reason)) = cancelled_objects {
336 match reason {
337 version if version.is_congested() => Err(ExecutionError::new(
338 if protocol_config.congestion_control_gas_price_feedback_mechanism() {
339 ExecutionErrorKind::ExecutionCancelledDueToSharedObjectCongestionV2 {
340 congested_objects: CongestedObjects(cancelled_objects),
341 suggested_gas_price: version
342 .get_congested_version_suggested_gas_price(),
343 }
344 } else {
345 ExecutionErrorKind::ExecutionCancelledDueToSharedObjectCongestion {
350 congested_objects: CongestedObjects(cancelled_objects),
351 }
352 },
353 None,
354 )),
355 SequenceNumber::RANDOMNESS_UNAVAILABLE => Err(ExecutionError::new(
356 ExecutionErrorKind::ExecutionCancelledDueToRandomnessUnavailable,
357 None,
358 )),
359 _ => panic!("invalid cancellation reason SequenceNumber: {reason}"),
360 }
361 } else {
362 execution_loop::<Mode>(
363 temporary_store,
364 transaction_kind,
365 tx_ctx,
366 move_vm,
367 gas_charger,
368 protocol_config,
369 metrics.clone(),
370 trace_builder_opt,
371 )
372 };
373
374 let meter_check = check_meter_limit(
375 temporary_store,
376 gas_charger,
377 protocol_config,
378 metrics.clone(),
379 );
380 if let Err(e) = meter_check {
381 execution_result = Err(e);
382 }
383
384 if execution_result.is_ok() {
385 let gas_check = check_written_objects_limit::<Mode>(
386 temporary_store,
387 gas_charger,
388 protocol_config,
389 metrics,
390 );
391 if let Err(e) = gas_check {
392 execution_result = Err(e);
393 }
394 }
395
396 execution_result
397 });
398
399 let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
400 temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
409
410 if let Err(e) = run_conservation_checks::<Mode>(
411 temporary_store,
412 gas_charger,
413 tx_ctx,
414 move_vm,
415 enable_expensive_checks,
416 &cost_summary,
417 is_genesis_or_epoch_change_tx,
418 advance_epoch_gas_summary,
419 ) {
420 result = Err(e);
422 }
423
424 (cost_summary, result)
425 }
426
427 #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
436 fn run_conservation_checks<Mode: ExecutionMode>(
437 temporary_store: &mut TemporaryStore<'_>,
438 gas_charger: &mut GasCharger,
439 tx_ctx: &mut TxContext,
440 move_vm: &Arc<MoveVM>,
441 enable_expensive_checks: bool,
442 cost_summary: &GasCostSummary,
443 is_genesis_or_epoch_change_tx: bool,
444 advance_epoch_gas_summary: Option<(u64, u64)>,
445 ) -> Result<(), ExecutionError> {
446 let mut result: std::result::Result<(), iota_types::error::ExecutionError> = Ok(());
447 if !is_genesis_or_epoch_change_tx && !Mode::skip_conservation_checks() {
448 let conservation_result = {
451 temporary_store
452 .check_iota_conserved(cost_summary)
453 .and_then(|()| {
454 if enable_expensive_checks {
455 let mut layout_resolver =
458 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
459 temporary_store.check_iota_conserved_expensive(
460 cost_summary,
461 advance_epoch_gas_summary,
462 &mut layout_resolver,
463 )
464 } else {
465 Ok(())
466 }
467 })
468 };
469 if let Err(conservation_err) = conservation_result {
470 result = Err(conservation_err);
474 gas_charger.reset(temporary_store);
475 gas_charger.charge_gas(temporary_store, &mut result);
476 if let Err(recovery_err) = {
478 temporary_store
479 .check_iota_conserved(cost_summary)
480 .and_then(|()| {
481 if enable_expensive_checks {
482 let mut layout_resolver =
485 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
486 temporary_store.check_iota_conserved_expensive(
487 cost_summary,
488 advance_epoch_gas_summary,
489 &mut layout_resolver,
490 )
491 } else {
492 Ok(())
493 }
494 })
495 } {
496 panic!(
500 "IOTA conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
501 tx_ctx.digest(),
502 recovery_err,
503 gas_charger.summary()
504 )
505 }
506 }
507 } result
511 }
512
513 #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
518 fn check_meter_limit(
519 temporary_store: &mut TemporaryStore<'_>,
520 gas_charger: &mut GasCharger,
521 protocol_config: &ProtocolConfig,
522 metrics: Arc<LimitsMetrics>,
523 ) -> Result<(), ExecutionError> {
524 let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
525
526 match check_limit_by_meter!(
531 !gas_charger.is_unmetered(),
532 effects_estimated_size,
533 protocol_config.max_serialized_tx_effects_size_bytes(),
534 protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
535 metrics.excessive_estimated_effects_size
536 ) {
537 LimitThresholdCrossed::None => Ok(()),
538 LimitThresholdCrossed::Soft(_, limit) => {
539 warn!(
540 effects_estimated_size = effects_estimated_size,
541 soft_limit = limit,
542 "Estimated transaction effects size crossed soft limit",
543 );
544 Ok(())
545 }
546 LimitThresholdCrossed::Hard(_, lim) => Err(ExecutionError::new_with_source(
547 ExecutionErrorKind::EffectsTooLarge {
548 current_size: effects_estimated_size as u64,
549 max_size: lim as u64,
550 },
551 "Transaction effects are too large",
552 )),
553 }
554 }
555
556 #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
561 fn check_written_objects_limit<Mode: ExecutionMode>(
562 temporary_store: &mut TemporaryStore<'_>,
563 gas_charger: &mut GasCharger,
564 protocol_config: &ProtocolConfig,
565 metrics: Arc<LimitsMetrics>,
566 ) -> Result<(), ExecutionError> {
567 if let (Some(normal_lim), Some(system_lim)) = (
568 protocol_config.max_size_written_objects_as_option(),
569 protocol_config.max_size_written_objects_system_tx_as_option(),
570 ) {
571 let written_objects_size = temporary_store.written_objects_size();
572
573 match check_limit_by_meter!(
574 !gas_charger.is_unmetered(),
575 written_objects_size,
576 normal_lim,
577 system_lim,
578 metrics.excessive_written_objects_size
579 ) {
580 LimitThresholdCrossed::None => (),
581 LimitThresholdCrossed::Soft(_, limit) => {
582 warn!(
583 written_objects_size = written_objects_size,
584 soft_limit = limit,
585 "Written objects size crossed soft limit",
586 )
587 }
588 LimitThresholdCrossed::Hard(_, lim) => {
589 return Err(ExecutionError::new_with_source(
590 ExecutionErrorKind::WrittenObjectsTooLarge {
591 current_size: written_objects_size as u64,
592 max_size: lim as u64,
593 },
594 "Written objects size crossed hard limit",
595 ));
596 }
597 };
598 }
599
600 Ok(())
601 }
602
603 #[instrument(level = "debug", skip_all)]
610 fn execution_loop<Mode: ExecutionMode>(
611 temporary_store: &mut TemporaryStore<'_>,
612 transaction_kind: TransactionKind,
613 tx_ctx: &mut TxContext,
614 move_vm: &Arc<MoveVM>,
615 gas_charger: &mut GasCharger,
616 protocol_config: &ProtocolConfig,
617 metrics: Arc<LimitsMetrics>,
618 trace_builder_opt: &mut Option<MoveTraceBuilder>,
619 ) -> Result<Mode::ExecutionResults, ExecutionError> {
620 let result = match transaction_kind {
621 TransactionKind::Genesis(GenesisTransaction { objects, events }) => {
622 if tx_ctx.epoch() != 0 {
623 panic!("BUG: Genesis Transactions can only be executed in epoch 0");
624 }
625
626 for genesis_object in objects {
627 match genesis_object {
628 iota_types::transaction::GenesisObject::RawObject { data, owner } => {
629 let object = ObjectInner {
630 data,
631 owner,
632 previous_transaction: tx_ctx.digest(),
633 storage_rebate: 0,
634 };
635 temporary_store.create_object(object.into());
636 }
637 }
638 }
639
640 temporary_store.record_execution_results(ExecutionResults::V1(
641 ExecutionResultsV1 {
642 user_events: events,
643 ..Default::default()
644 },
645 ));
646
647 Ok(Mode::empty_results())
648 }
649 TransactionKind::ConsensusCommitPrologueV1(prologue) => {
650 setup_consensus_commit(
651 prologue.commit_timestamp_ms,
652 temporary_store,
653 tx_ctx,
654 move_vm,
655 gas_charger,
656 protocol_config,
657 metrics,
658 trace_builder_opt,
659 )
660 .expect("ConsensusCommitPrologueV1 cannot fail");
661 Ok(Mode::empty_results())
662 }
663 TransactionKind::ProgrammableTransaction(pt) => {
664 programmable_transactions::execution::execute::<Mode>(
665 protocol_config,
666 metrics,
667 move_vm,
668 temporary_store,
669 tx_ctx,
670 gas_charger,
671 pt,
672 trace_builder_opt,
673 )
674 }
675 TransactionKind::EndOfEpochTransaction(txns) => {
676 let mut builder = ProgrammableTransactionBuilder::new();
677 let len = txns.len();
678 for (i, tx) in txns.into_iter().enumerate() {
679 match tx {
680 EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
681 assert_eq!(i, len - 1);
682 advance_epoch_v1(
683 builder,
684 change_epoch,
685 temporary_store,
686 tx_ctx,
687 move_vm,
688 gas_charger,
689 protocol_config,
690 metrics,
691 trace_builder_opt,
692 )?;
693 return Ok(Mode::empty_results());
694 }
695 EndOfEpochTransactionKind::ChangeEpochV2(change_epoch_v2) => {
696 assert_eq!(i, len - 1);
697 advance_epoch_v2(
698 builder,
699 change_epoch_v2,
700 temporary_store,
701 tx_ctx,
702 move_vm,
703 gas_charger,
704 protocol_config,
705 metrics,
706 trace_builder_opt,
707 )?;
708 return Ok(Mode::empty_results());
709 }
710 EndOfEpochTransactionKind::ChangeEpochV3(change_epoch_v3) => {
711 assert_eq!(i, len - 1);
712 advance_epoch_v3(
713 builder,
714 change_epoch_v3,
715 temporary_store,
716 tx_ctx,
717 move_vm,
718 gas_charger,
719 protocol_config,
720 metrics,
721 trace_builder_opt,
722 )?;
723 return Ok(Mode::empty_results());
724 }
725 EndOfEpochTransactionKind::AuthenticatorStateCreate => {
726 assert!(protocol_config.enable_jwk_consensus_updates());
727 builder = setup_authenticator_state_create(builder);
728 }
729 EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
730 assert!(protocol_config.enable_jwk_consensus_updates());
731
732 builder = setup_authenticator_state_expire(builder, expire);
735 }
736 }
737 }
738 unreachable!(
739 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
740 )
741 }
742 TransactionKind::AuthenticatorStateUpdateV1(auth_state_update) => {
743 setup_authenticator_state_update(
744 auth_state_update,
745 temporary_store,
746 tx_ctx,
747 move_vm,
748 gas_charger,
749 protocol_config,
750 metrics,
751 trace_builder_opt,
752 )?;
753 Ok(Mode::empty_results())
754 }
755 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
756 setup_randomness_state_update(
757 randomness_state_update,
758 temporary_store,
759 tx_ctx,
760 move_vm,
761 gas_charger,
762 protocol_config,
763 metrics,
764 trace_builder_opt,
765 )?;
766 Ok(Mode::empty_results())
767 }
768 }?;
769 temporary_store.check_execution_results_consistency()?;
770 Ok(result)
771 }
772
773 fn mint_epoch_rewards_in_pt(
782 builder: &mut ProgrammableTransactionBuilder,
783 params: &AdvanceEpochParams,
784 ) -> (Argument, Argument) {
785 let storage_charge_arg = builder
787 .input(CallArg::Pure(
788 bcs::to_bytes(¶ms.storage_charge).unwrap(),
789 ))
790 .unwrap();
791 let storage_charges = builder.programmable_move_call(
792 IOTA_FRAMEWORK_PACKAGE_ID,
793 BALANCE_MODULE_NAME.to_owned(),
794 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
795 vec![GAS::type_tag()],
796 vec![storage_charge_arg],
797 );
798
799 let computation_charge_arg = builder
801 .input(CallArg::Pure(
802 bcs::to_bytes(¶ms.computation_charge).unwrap(),
803 ))
804 .unwrap();
805 let computation_charges = builder.programmable_move_call(
806 IOTA_FRAMEWORK_PACKAGE_ID,
807 BALANCE_MODULE_NAME.to_owned(),
808 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
809 vec![GAS::type_tag()],
810 vec![computation_charge_arg],
811 );
812 (storage_charges, computation_charges)
813 }
814
815 pub fn construct_advance_epoch_pt_impl(
823 mut builder: ProgrammableTransactionBuilder,
824 params: &AdvanceEpochParams,
825 call_arg_vec: Vec<CallArg>,
826 ) -> Result<ProgrammableTransaction, ExecutionError> {
827 let (storage_charges, computation_charges) = mint_epoch_rewards_in_pt(&mut builder, params);
829 let mut arguments = vec![
830 builder
831 .pure(params.validator_subsidy)
832 .expect("bcs encoding a u64 should not fail"),
833 storage_charges,
834 computation_charges,
835 ];
836
837 let call_arg_arguments = call_arg_vec
838 .into_iter()
839 .map(|a| builder.input(a))
840 .collect::<Result<_, _>>();
841
842 assert_invariant!(
843 call_arg_arguments.is_ok(),
844 "Unable to generate args for advance_epoch transaction!"
845 );
846
847 arguments.append(&mut call_arg_arguments.unwrap());
848
849 info!("Call arguments to advance_epoch transaction: {:?}", params);
850
851 let storage_rebates = builder.programmable_move_call(
852 IOTA_SYSTEM_PACKAGE_ID,
853 IOTA_SYSTEM_MODULE_NAME.to_owned(),
854 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
855 vec![],
856 arguments,
857 );
858
859 builder.programmable_move_call(
861 IOTA_FRAMEWORK_PACKAGE_ID,
862 BALANCE_MODULE_NAME.to_owned(),
863 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
864 vec![GAS::type_tag()],
865 vec![storage_rebates],
866 );
867 Ok(builder.finish())
868 }
869
870 pub fn construct_advance_epoch_pt_v1(
871 builder: ProgrammableTransactionBuilder,
872 params: &AdvanceEpochParams,
873 ) -> Result<ProgrammableTransaction, ExecutionError> {
874 let call_arg_vec = vec![
879 CallArg::IOTA_SYSTEM_MUT, CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()), ];
887 construct_advance_epoch_pt_impl(builder, params, call_arg_vec)
888 }
889
890 pub fn construct_advance_epoch_pt_v2(
891 builder: ProgrammableTransactionBuilder,
892 params: &AdvanceEpochParams,
893 ) -> Result<ProgrammableTransaction, ExecutionError> {
894 let call_arg_vec = vec![
899 CallArg::Pure(bcs::to_bytes(¶ms.computation_charge_burned).unwrap()), CallArg::IOTA_SYSTEM_MUT, CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.max_committee_members_count).unwrap()), ];
909 construct_advance_epoch_pt_impl(builder, params, call_arg_vec)
910 }
911
912 pub fn construct_advance_epoch_pt_v3(
913 builder: ProgrammableTransactionBuilder,
914 params: &AdvanceEpochParams,
915 ) -> Result<ProgrammableTransaction, ExecutionError> {
916 let call_arg_vec = vec![
922 CallArg::Pure(bcs::to_bytes(¶ms.computation_charge_burned).unwrap()), CallArg::IOTA_SYSTEM_MUT, CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.max_committee_members_count).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.eligible_active_validators).unwrap()), ];
933 construct_advance_epoch_pt_impl(builder, params, call_arg_vec)
934 }
935
936 fn advance_epoch_impl(
943 advance_epoch_pt: ProgrammableTransaction,
944 params: AdvanceEpochParams,
945 system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
946 temporary_store: &mut TemporaryStore<'_>,
947 tx_ctx: &mut TxContext,
948 move_vm: &Arc<MoveVM>,
949 gas_charger: &mut GasCharger,
950 protocol_config: &ProtocolConfig,
951 metrics: Arc<LimitsMetrics>,
952 trace_builder_opt: &mut Option<MoveTraceBuilder>,
953 ) -> Result<(), ExecutionError> {
954 let result = programmable_transactions::execution::execute::<execution_mode::System>(
955 protocol_config,
956 metrics.clone(),
957 move_vm,
958 temporary_store,
959 tx_ctx,
960 gas_charger,
961 advance_epoch_pt,
962 trace_builder_opt,
963 );
964
965 #[cfg(msim)]
966 let result = maybe_modify_result(result, params.epoch);
967
968 if result.is_err() {
969 tracing::error!(
970 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx params: {:?}",
971 result.as_ref().err(),
972 temporary_store.objects(),
973 params,
974 );
975 temporary_store.drop_writes();
976 gas_charger.reset_storage_cost_and_rebate();
978
979 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
980 }
981
982 let new_vm = new_move_vm(
983 all_natives(true, protocol_config),
984 protocol_config,
985 None,
987 )
988 .expect("Failed to create new MoveVM");
989 process_system_packages(
990 system_packages,
991 temporary_store,
992 tx_ctx,
993 &new_vm,
994 gas_charger,
995 protocol_config,
996 metrics,
997 trace_builder_opt,
998 );
999
1000 Ok(())
1001 }
1002
1003 fn advance_epoch_v1(
1007 builder: ProgrammableTransactionBuilder,
1008 change_epoch: ChangeEpoch,
1009 temporary_store: &mut TemporaryStore<'_>,
1010 tx_ctx: &mut TxContext,
1011 move_vm: &Arc<MoveVM>,
1012 gas_charger: &mut GasCharger,
1013 protocol_config: &ProtocolConfig,
1014 metrics: Arc<LimitsMetrics>,
1015 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1016 ) -> Result<(), ExecutionError> {
1017 let params = AdvanceEpochParams {
1018 epoch: change_epoch.epoch,
1019 next_protocol_version: change_epoch.protocol_version,
1020 validator_subsidy: protocol_config.validator_target_reward(),
1021 storage_charge: change_epoch.storage_charge,
1022 computation_charge: change_epoch.computation_charge,
1023 computation_charge_burned: change_epoch.computation_charge,
1025 storage_rebate: change_epoch.storage_rebate,
1026 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
1027 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1028 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
1029 max_committee_members_count: 0,
1032 eligible_active_validators: vec![],
1033 };
1034 let advance_epoch_pt = construct_advance_epoch_pt_v1(builder, ¶ms)?;
1035 advance_epoch_impl(
1036 advance_epoch_pt,
1037 params,
1038 change_epoch.system_packages,
1039 temporary_store,
1040 tx_ctx,
1041 move_vm,
1042 gas_charger,
1043 protocol_config,
1044 metrics,
1045 trace_builder_opt,
1046 )
1047 }
1048
1049 fn advance_epoch_v2(
1053 builder: ProgrammableTransactionBuilder,
1054 change_epoch_v2: ChangeEpochV2,
1055 temporary_store: &mut TemporaryStore<'_>,
1056 tx_ctx: &mut TxContext,
1057 move_vm: &Arc<MoveVM>,
1058 gas_charger: &mut GasCharger,
1059 protocol_config: &ProtocolConfig,
1060 metrics: Arc<LimitsMetrics>,
1061 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1062 ) -> Result<(), ExecutionError> {
1063 let params = AdvanceEpochParams {
1064 epoch: change_epoch_v2.epoch,
1065 next_protocol_version: change_epoch_v2.protocol_version,
1066 validator_subsidy: protocol_config.validator_target_reward(),
1067 storage_charge: change_epoch_v2.storage_charge,
1068 computation_charge: change_epoch_v2.computation_charge,
1069 computation_charge_burned: change_epoch_v2.computation_charge_burned,
1070 storage_rebate: change_epoch_v2.storage_rebate,
1071 non_refundable_storage_fee: change_epoch_v2.non_refundable_storage_fee,
1072 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1073 epoch_start_timestamp_ms: change_epoch_v2.epoch_start_timestamp_ms,
1074 max_committee_members_count: protocol_config.max_committee_members_count(),
1075 eligible_active_validators: vec![],
1078 };
1079 let advance_epoch_pt = construct_advance_epoch_pt_v2(builder, ¶ms)?;
1080 advance_epoch_impl(
1081 advance_epoch_pt,
1082 params,
1083 change_epoch_v2.system_packages,
1084 temporary_store,
1085 tx_ctx,
1086 move_vm,
1087 gas_charger,
1088 protocol_config,
1089 metrics,
1090 trace_builder_opt,
1091 )
1092 }
1093
1094 fn advance_epoch_v3(
1098 builder: ProgrammableTransactionBuilder,
1099 change_epoch_v3: ChangeEpochV3,
1100 temporary_store: &mut TemporaryStore<'_>,
1101 tx_ctx: &mut TxContext,
1102 move_vm: &Arc<MoveVM>,
1103 gas_charger: &mut GasCharger,
1104 protocol_config: &ProtocolConfig,
1105 metrics: Arc<LimitsMetrics>,
1106 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1107 ) -> Result<(), ExecutionError> {
1108 let params = AdvanceEpochParams {
1109 epoch: change_epoch_v3.epoch,
1110 next_protocol_version: change_epoch_v3.protocol_version,
1111 validator_subsidy: protocol_config.validator_target_reward(),
1112 storage_charge: change_epoch_v3.storage_charge,
1113 computation_charge: change_epoch_v3.computation_charge,
1114 computation_charge_burned: change_epoch_v3.computation_charge_burned,
1115 storage_rebate: change_epoch_v3.storage_rebate,
1116 non_refundable_storage_fee: change_epoch_v3.non_refundable_storage_fee,
1117 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1118 epoch_start_timestamp_ms: change_epoch_v3.epoch_start_timestamp_ms,
1119 max_committee_members_count: protocol_config.max_committee_members_count(),
1120 eligible_active_validators: change_epoch_v3.eligible_active_validators,
1121 };
1122 let advance_epoch_pt = construct_advance_epoch_pt_v3(builder, ¶ms)?;
1123 advance_epoch_impl(
1124 advance_epoch_pt,
1125 params,
1126 change_epoch_v3.system_packages,
1127 temporary_store,
1128 tx_ctx,
1129 move_vm,
1130 gas_charger,
1131 protocol_config,
1132 metrics,
1133 trace_builder_opt,
1134 )
1135 }
1136
1137 fn process_system_packages(
1138 system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
1139 temporary_store: &mut TemporaryStore<'_>,
1140 tx_ctx: &mut TxContext,
1141 move_vm: &MoveVM,
1142 gas_charger: &mut GasCharger,
1143 protocol_config: &ProtocolConfig,
1144 metrics: Arc<LimitsMetrics>,
1145 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1146 ) {
1147 let binary_config = to_binary_config(protocol_config);
1148 for (version, modules, dependencies) in system_packages.into_iter() {
1149 let deserialized_modules: Vec<_> = modules
1150 .iter()
1151 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1152 .collect();
1153
1154 if version == OBJECT_START_VERSION {
1155 let package_id = deserialized_modules.first().unwrap().address();
1156 info!("adding new system package {package_id}");
1157
1158 let publish_pt = {
1159 let mut b = ProgrammableTransactionBuilder::new();
1160 b.command(Command::Publish(modules, dependencies));
1161 b.finish()
1162 };
1163
1164 programmable_transactions::execution::execute::<execution_mode::System>(
1165 protocol_config,
1166 metrics.clone(),
1167 move_vm,
1168 temporary_store,
1169 tx_ctx,
1170 gas_charger,
1171 publish_pt,
1172 trace_builder_opt,
1173 )
1174 .expect("System Package Publish must succeed");
1175 } else {
1176 let mut new_package = Object::new_system_package(
1177 &deserialized_modules,
1178 version,
1179 dependencies,
1180 tx_ctx.digest(),
1181 );
1182
1183 info!(
1184 "upgraded system package {:?}",
1185 new_package.compute_object_reference()
1186 );
1187
1188 new_package
1191 .data
1192 .try_as_package_mut()
1193 .unwrap()
1194 .decrement_version();
1195
1196 temporary_store.upgrade_system_package(new_package);
1198 }
1199 }
1200 }
1201
1202 fn setup_consensus_commit(
1208 consensus_commit_timestamp_ms: CheckpointTimestamp,
1209 temporary_store: &mut TemporaryStore<'_>,
1210 tx_ctx: &mut TxContext,
1211 move_vm: &Arc<MoveVM>,
1212 gas_charger: &mut GasCharger,
1213 protocol_config: &ProtocolConfig,
1214 metrics: Arc<LimitsMetrics>,
1215 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1216 ) -> Result<(), ExecutionError> {
1217 let pt = {
1218 let mut builder = ProgrammableTransactionBuilder::new();
1219 let res = builder.move_call(
1220 IOTA_FRAMEWORK_ADDRESS.into(),
1221 CLOCK_MODULE_NAME.to_owned(),
1222 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1223 vec![],
1224 vec![
1225 CallArg::CLOCK_MUT,
1226 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1227 ],
1228 );
1229 assert_invariant!(
1230 res.is_ok(),
1231 "Unable to generate consensus_commit_prologue transaction!"
1232 );
1233 builder.finish()
1234 };
1235 programmable_transactions::execution::execute::<execution_mode::System>(
1236 protocol_config,
1237 metrics,
1238 move_vm,
1239 temporary_store,
1240 tx_ctx,
1241 gas_charger,
1242 pt,
1243 trace_builder_opt,
1244 )
1245 }
1246
1247 fn setup_authenticator_state_create(
1251 mut builder: ProgrammableTransactionBuilder,
1252 ) -> ProgrammableTransactionBuilder {
1253 builder
1254 .move_call(
1255 IOTA_FRAMEWORK_ADDRESS.into(),
1256 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1257 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1258 vec![],
1259 vec![],
1260 )
1261 .expect("Unable to generate authenticator_state_create transaction!");
1262 builder
1263 }
1264
1265 fn setup_authenticator_state_update(
1272 update: AuthenticatorStateUpdateV1,
1273 temporary_store: &mut TemporaryStore<'_>,
1274 tx_ctx: &mut TxContext,
1275 move_vm: &Arc<MoveVM>,
1276 gas_charger: &mut GasCharger,
1277 protocol_config: &ProtocolConfig,
1278 metrics: Arc<LimitsMetrics>,
1279 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1280 ) -> Result<(), ExecutionError> {
1281 let pt = {
1282 let mut builder = ProgrammableTransactionBuilder::new();
1283 let res = builder.move_call(
1284 IOTA_FRAMEWORK_ADDRESS.into(),
1285 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1286 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1287 vec![],
1288 vec![
1289 CallArg::Object(ObjectArg::SharedObject {
1290 id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1291 initial_shared_version: update.authenticator_obj_initial_shared_version,
1292 mutable: true,
1293 }),
1294 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1295 ],
1296 );
1297 assert_invariant!(
1298 res.is_ok(),
1299 "Unable to generate authenticator_state_update transaction!"
1300 );
1301 builder.finish()
1302 };
1303 programmable_transactions::execution::execute::<execution_mode::System>(
1304 protocol_config,
1305 metrics,
1306 move_vm,
1307 temporary_store,
1308 tx_ctx,
1309 gas_charger,
1310 pt,
1311 trace_builder_opt,
1312 )
1313 }
1314
1315 fn setup_authenticator_state_expire(
1320 mut builder: ProgrammableTransactionBuilder,
1321 expire: AuthenticatorStateExpire,
1322 ) -> ProgrammableTransactionBuilder {
1323 builder
1324 .move_call(
1325 IOTA_FRAMEWORK_ADDRESS.into(),
1326 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1327 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1328 vec![],
1329 vec![
1330 CallArg::Object(ObjectArg::SharedObject {
1331 id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1332 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1333 mutable: true,
1334 }),
1335 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1336 ],
1337 )
1338 .expect("Unable to generate authenticator_state_expire transaction!");
1339 builder
1340 }
1341
1342 fn setup_randomness_state_update(
1348 update: RandomnessStateUpdate,
1349 temporary_store: &mut TemporaryStore<'_>,
1350 tx_ctx: &mut TxContext,
1351 move_vm: &Arc<MoveVM>,
1352 gas_charger: &mut GasCharger,
1353 protocol_config: &ProtocolConfig,
1354 metrics: Arc<LimitsMetrics>,
1355 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1356 ) -> Result<(), ExecutionError> {
1357 let pt = {
1358 let mut builder = ProgrammableTransactionBuilder::new();
1359 let res = builder.move_call(
1360 IOTA_FRAMEWORK_ADDRESS.into(),
1361 RANDOMNESS_MODULE_NAME.to_owned(),
1362 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1363 vec![],
1364 vec![
1365 CallArg::Object(ObjectArg::SharedObject {
1366 id: IOTA_RANDOMNESS_STATE_OBJECT_ID,
1367 initial_shared_version: update.randomness_obj_initial_shared_version,
1368 mutable: true,
1369 }),
1370 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1371 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1372 ],
1373 );
1374 assert_invariant!(
1375 res.is_ok(),
1376 "Unable to generate randomness_state_update transaction!"
1377 );
1378 builder.finish()
1379 };
1380 programmable_transactions::execution::execute::<execution_mode::System>(
1381 protocol_config,
1382 metrics,
1383 move_vm,
1384 temporary_store,
1385 tx_ctx,
1386 gas_charger,
1387 pt,
1388 trace_builder_opt,
1389 )
1390 }
1391}