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, 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 SequenceNumber::CONGESTED => Err(ExecutionError::new(
338 ExecutionErrorKind::ExecutionCancelledDueToSharedObjectCongestion {
339 congested_objects: CongestedObjects(cancelled_objects),
340 },
341 None,
342 )),
343 SequenceNumber::RANDOMNESS_UNAVAILABLE => Err(ExecutionError::new(
344 ExecutionErrorKind::ExecutionCancelledDueToRandomnessUnavailable,
345 None,
346 )),
347 _ => panic!("invalid cancellation reason SequenceNumber: {reason}"),
348 }
349 } else {
350 execution_loop::<Mode>(
351 temporary_store,
352 transaction_kind,
353 tx_ctx,
354 move_vm,
355 gas_charger,
356 protocol_config,
357 metrics.clone(),
358 trace_builder_opt,
359 )
360 };
361
362 let meter_check = check_meter_limit(
363 temporary_store,
364 gas_charger,
365 protocol_config,
366 metrics.clone(),
367 );
368 if let Err(e) = meter_check {
369 execution_result = Err(e);
370 }
371
372 if execution_result.is_ok() {
373 let gas_check = check_written_objects_limit::<Mode>(
374 temporary_store,
375 gas_charger,
376 protocol_config,
377 metrics,
378 );
379 if let Err(e) = gas_check {
380 execution_result = Err(e);
381 }
382 }
383
384 execution_result
385 });
386
387 let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
388 temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
397
398 if let Err(e) = run_conservation_checks::<Mode>(
399 temporary_store,
400 gas_charger,
401 tx_ctx,
402 move_vm,
403 enable_expensive_checks,
404 &cost_summary,
405 is_genesis_or_epoch_change_tx,
406 advance_epoch_gas_summary,
407 ) {
408 result = Err(e);
410 }
411
412 (cost_summary, result)
413 }
414
415 #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
424 fn run_conservation_checks<Mode: ExecutionMode>(
425 temporary_store: &mut TemporaryStore<'_>,
426 gas_charger: &mut GasCharger,
427 tx_ctx: &mut TxContext,
428 move_vm: &Arc<MoveVM>,
429 enable_expensive_checks: bool,
430 cost_summary: &GasCostSummary,
431 is_genesis_or_epoch_change_tx: bool,
432 advance_epoch_gas_summary: Option<(u64, u64)>,
433 ) -> Result<(), ExecutionError> {
434 let mut result: std::result::Result<(), iota_types::error::ExecutionError> = Ok(());
435 if !is_genesis_or_epoch_change_tx && !Mode::skip_conservation_checks() {
436 let conservation_result = {
439 temporary_store
440 .check_iota_conserved(cost_summary)
441 .and_then(|()| {
442 if enable_expensive_checks {
443 let mut layout_resolver =
446 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
447 temporary_store.check_iota_conserved_expensive(
448 cost_summary,
449 advance_epoch_gas_summary,
450 &mut layout_resolver,
451 )
452 } else {
453 Ok(())
454 }
455 })
456 };
457 if let Err(conservation_err) = conservation_result {
458 result = Err(conservation_err);
462 gas_charger.reset(temporary_store);
463 gas_charger.charge_gas(temporary_store, &mut result);
464 if let Err(recovery_err) = {
466 temporary_store
467 .check_iota_conserved(cost_summary)
468 .and_then(|()| {
469 if enable_expensive_checks {
470 let mut layout_resolver =
473 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
474 temporary_store.check_iota_conserved_expensive(
475 cost_summary,
476 advance_epoch_gas_summary,
477 &mut layout_resolver,
478 )
479 } else {
480 Ok(())
481 }
482 })
483 } {
484 panic!(
488 "IOTA conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
489 tx_ctx.digest(),
490 recovery_err,
491 gas_charger.summary()
492 )
493 }
494 }
495 } result
499 }
500
501 #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
506 fn check_meter_limit(
507 temporary_store: &mut TemporaryStore<'_>,
508 gas_charger: &mut GasCharger,
509 protocol_config: &ProtocolConfig,
510 metrics: Arc<LimitsMetrics>,
511 ) -> Result<(), ExecutionError> {
512 let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
513
514 match check_limit_by_meter!(
519 !gas_charger.is_unmetered(),
520 effects_estimated_size,
521 protocol_config.max_serialized_tx_effects_size_bytes(),
522 protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
523 metrics.excessive_estimated_effects_size
524 ) {
525 LimitThresholdCrossed::None => Ok(()),
526 LimitThresholdCrossed::Soft(_, limit) => {
527 warn!(
528 effects_estimated_size = effects_estimated_size,
529 soft_limit = limit,
530 "Estimated transaction effects size crossed soft limit",
531 );
532 Ok(())
533 }
534 LimitThresholdCrossed::Hard(_, lim) => Err(ExecutionError::new_with_source(
535 ExecutionErrorKind::EffectsTooLarge {
536 current_size: effects_estimated_size as u64,
537 max_size: lim as u64,
538 },
539 "Transaction effects are too large",
540 )),
541 }
542 }
543
544 #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
549 fn check_written_objects_limit<Mode: ExecutionMode>(
550 temporary_store: &mut TemporaryStore<'_>,
551 gas_charger: &mut GasCharger,
552 protocol_config: &ProtocolConfig,
553 metrics: Arc<LimitsMetrics>,
554 ) -> Result<(), ExecutionError> {
555 if let (Some(normal_lim), Some(system_lim)) = (
556 protocol_config.max_size_written_objects_as_option(),
557 protocol_config.max_size_written_objects_system_tx_as_option(),
558 ) {
559 let written_objects_size = temporary_store.written_objects_size();
560
561 match check_limit_by_meter!(
562 !gas_charger.is_unmetered(),
563 written_objects_size,
564 normal_lim,
565 system_lim,
566 metrics.excessive_written_objects_size
567 ) {
568 LimitThresholdCrossed::None => (),
569 LimitThresholdCrossed::Soft(_, limit) => {
570 warn!(
571 written_objects_size = written_objects_size,
572 soft_limit = limit,
573 "Written objects size crossed soft limit",
574 )
575 }
576 LimitThresholdCrossed::Hard(_, lim) => {
577 return Err(ExecutionError::new_with_source(
578 ExecutionErrorKind::WrittenObjectsTooLarge {
579 current_size: written_objects_size as u64,
580 max_size: lim as u64,
581 },
582 "Written objects size crossed hard limit",
583 ));
584 }
585 };
586 }
587
588 Ok(())
589 }
590
591 #[instrument(level = "debug", skip_all)]
598 fn execution_loop<Mode: ExecutionMode>(
599 temporary_store: &mut TemporaryStore<'_>,
600 transaction_kind: TransactionKind,
601 tx_ctx: &mut TxContext,
602 move_vm: &Arc<MoveVM>,
603 gas_charger: &mut GasCharger,
604 protocol_config: &ProtocolConfig,
605 metrics: Arc<LimitsMetrics>,
606 trace_builder_opt: &mut Option<MoveTraceBuilder>,
607 ) -> Result<Mode::ExecutionResults, ExecutionError> {
608 let result = match transaction_kind {
609 TransactionKind::Genesis(GenesisTransaction { objects, events }) => {
610 if tx_ctx.epoch() != 0 {
611 panic!("BUG: Genesis Transactions can only be executed in epoch 0");
612 }
613
614 for genesis_object in objects {
615 match genesis_object {
616 iota_types::transaction::GenesisObject::RawObject { data, owner } => {
617 let object = ObjectInner {
618 data,
619 owner,
620 previous_transaction: tx_ctx.digest(),
621 storage_rebate: 0,
622 };
623 temporary_store.create_object(object.into());
624 }
625 }
626 }
627
628 temporary_store.record_execution_results(ExecutionResults::V1(
629 ExecutionResultsV1 {
630 user_events: events,
631 ..Default::default()
632 },
633 ));
634
635 Ok(Mode::empty_results())
636 }
637 TransactionKind::ConsensusCommitPrologueV1(prologue) => {
638 setup_consensus_commit(
639 prologue.commit_timestamp_ms,
640 temporary_store,
641 tx_ctx,
642 move_vm,
643 gas_charger,
644 protocol_config,
645 metrics,
646 trace_builder_opt,
647 )
648 .expect("ConsensusCommitPrologueV1 cannot fail");
649 Ok(Mode::empty_results())
650 }
651 TransactionKind::ProgrammableTransaction(pt) => {
652 programmable_transactions::execution::execute::<Mode>(
653 protocol_config,
654 metrics,
655 move_vm,
656 temporary_store,
657 tx_ctx,
658 gas_charger,
659 pt,
660 trace_builder_opt,
661 )
662 }
663 TransactionKind::EndOfEpochTransaction(txns) => {
664 let mut builder = ProgrammableTransactionBuilder::new();
665 let len = txns.len();
666 for (i, tx) in txns.into_iter().enumerate() {
667 match tx {
668 EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
669 assert_eq!(i, len - 1);
670 advance_epoch_v1(
671 builder,
672 change_epoch,
673 temporary_store,
674 tx_ctx,
675 move_vm,
676 gas_charger,
677 protocol_config,
678 metrics,
679 trace_builder_opt,
680 )?;
681 return Ok(Mode::empty_results());
682 }
683 EndOfEpochTransactionKind::ChangeEpochV2(change_epoch_v2) => {
684 assert_eq!(i, len - 1);
685 advance_epoch_v2(
686 builder,
687 change_epoch_v2,
688 temporary_store,
689 tx_ctx,
690 move_vm,
691 gas_charger,
692 protocol_config,
693 metrics,
694 trace_builder_opt,
695 )?;
696 return Ok(Mode::empty_results());
697 }
698 EndOfEpochTransactionKind::AuthenticatorStateCreate => {
699 assert!(protocol_config.enable_jwk_consensus_updates());
700 builder = setup_authenticator_state_create(builder);
701 }
702 EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
703 assert!(protocol_config.enable_jwk_consensus_updates());
704
705 builder = setup_authenticator_state_expire(builder, expire);
708 }
709 }
710 }
711 unreachable!(
712 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
713 )
714 }
715 TransactionKind::AuthenticatorStateUpdateV1(auth_state_update) => {
716 setup_authenticator_state_update(
717 auth_state_update,
718 temporary_store,
719 tx_ctx,
720 move_vm,
721 gas_charger,
722 protocol_config,
723 metrics,
724 trace_builder_opt,
725 )?;
726 Ok(Mode::empty_results())
727 }
728 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
729 setup_randomness_state_update(
730 randomness_state_update,
731 temporary_store,
732 tx_ctx,
733 move_vm,
734 gas_charger,
735 protocol_config,
736 metrics,
737 trace_builder_opt,
738 )?;
739 Ok(Mode::empty_results())
740 }
741 }?;
742 temporary_store.check_execution_results_consistency()?;
743 Ok(result)
744 }
745
746 fn mint_epoch_rewards_in_pt(
755 builder: &mut ProgrammableTransactionBuilder,
756 params: &AdvanceEpochParams,
757 ) -> (Argument, Argument) {
758 let storage_charge_arg = builder
760 .input(CallArg::Pure(
761 bcs::to_bytes(¶ms.storage_charge).unwrap(),
762 ))
763 .unwrap();
764 let storage_charges = builder.programmable_move_call(
765 IOTA_FRAMEWORK_PACKAGE_ID,
766 BALANCE_MODULE_NAME.to_owned(),
767 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
768 vec![GAS::type_tag()],
769 vec![storage_charge_arg],
770 );
771
772 let computation_charge_arg = builder
774 .input(CallArg::Pure(
775 bcs::to_bytes(¶ms.computation_charge).unwrap(),
776 ))
777 .unwrap();
778 let computation_charges = builder.programmable_move_call(
779 IOTA_FRAMEWORK_PACKAGE_ID,
780 BALANCE_MODULE_NAME.to_owned(),
781 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
782 vec![GAS::type_tag()],
783 vec![computation_charge_arg],
784 );
785 (storage_charges, computation_charges)
786 }
787
788 pub fn construct_advance_epoch_pt_impl(
796 mut builder: ProgrammableTransactionBuilder,
797 params: &AdvanceEpochParams,
798 call_arg_vec: Vec<CallArg>,
799 ) -> Result<ProgrammableTransaction, ExecutionError> {
800 let (storage_charges, computation_charges) = mint_epoch_rewards_in_pt(&mut builder, params);
802 let mut arguments = vec![
803 builder
804 .pure(params.validator_subsidy)
805 .expect("bcs encoding a u64 should not fail"),
806 storage_charges,
807 computation_charges,
808 ];
809
810 let call_arg_arguments = call_arg_vec
811 .into_iter()
812 .map(|a| builder.input(a))
813 .collect::<Result<_, _>>();
814
815 assert_invariant!(
816 call_arg_arguments.is_ok(),
817 "Unable to generate args for advance_epoch transaction!"
818 );
819
820 arguments.append(&mut call_arg_arguments.unwrap());
821
822 info!("Call arguments to advance_epoch transaction: {:?}", params);
823
824 let storage_rebates = builder.programmable_move_call(
825 IOTA_SYSTEM_PACKAGE_ID,
826 IOTA_SYSTEM_MODULE_NAME.to_owned(),
827 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
828 vec![],
829 arguments,
830 );
831
832 builder.programmable_move_call(
834 IOTA_FRAMEWORK_PACKAGE_ID,
835 BALANCE_MODULE_NAME.to_owned(),
836 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
837 vec![GAS::type_tag()],
838 vec![storage_rebates],
839 );
840 Ok(builder.finish())
841 }
842
843 pub fn construct_advance_epoch_pt_v1(
844 builder: ProgrammableTransactionBuilder,
845 params: &AdvanceEpochParams,
846 ) -> Result<ProgrammableTransaction, ExecutionError> {
847 let call_arg_vec = vec![
852 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()), ];
860 construct_advance_epoch_pt_impl(builder, params, call_arg_vec)
861 }
862
863 pub fn construct_advance_epoch_pt_v2(
864 builder: ProgrammableTransactionBuilder,
865 params: &AdvanceEpochParams,
866 ) -> Result<ProgrammableTransaction, ExecutionError> {
867 let call_arg_vec = vec![
872 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()), ];
882 construct_advance_epoch_pt_impl(builder, params, call_arg_vec)
883 }
884
885 fn advance_epoch_impl(
892 advance_epoch_pt: ProgrammableTransaction,
893 params: AdvanceEpochParams,
894 system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
895 temporary_store: &mut TemporaryStore<'_>,
896 tx_ctx: &mut TxContext,
897 move_vm: &Arc<MoveVM>,
898 gas_charger: &mut GasCharger,
899 protocol_config: &ProtocolConfig,
900 metrics: Arc<LimitsMetrics>,
901 trace_builder_opt: &mut Option<MoveTraceBuilder>,
902 ) -> Result<(), ExecutionError> {
903 let result = programmable_transactions::execution::execute::<execution_mode::System>(
904 protocol_config,
905 metrics.clone(),
906 move_vm,
907 temporary_store,
908 tx_ctx,
909 gas_charger,
910 advance_epoch_pt,
911 trace_builder_opt,
912 );
913
914 #[cfg(msim)]
915 let result = maybe_modify_result(result, params.epoch);
916
917 if result.is_err() {
918 tracing::error!(
919 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx params: {:?}",
920 result.as_ref().err(),
921 temporary_store.objects(),
922 params,
923 );
924 temporary_store.drop_writes();
925 gas_charger.reset_storage_cost_and_rebate();
927
928 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
929 }
930
931 let new_vm = new_move_vm(
932 all_natives(true, protocol_config),
933 protocol_config,
934 None,
936 )
937 .expect("Failed to create new MoveVM");
938 process_system_packages(
939 system_packages,
940 temporary_store,
941 tx_ctx,
942 &new_vm,
943 gas_charger,
944 protocol_config,
945 metrics,
946 trace_builder_opt,
947 );
948
949 Ok(())
950 }
951
952 fn advance_epoch_v1(
956 builder: ProgrammableTransactionBuilder,
957 change_epoch: ChangeEpoch,
958 temporary_store: &mut TemporaryStore<'_>,
959 tx_ctx: &mut TxContext,
960 move_vm: &Arc<MoveVM>,
961 gas_charger: &mut GasCharger,
962 protocol_config: &ProtocolConfig,
963 metrics: Arc<LimitsMetrics>,
964 trace_builder_opt: &mut Option<MoveTraceBuilder>,
965 ) -> Result<(), ExecutionError> {
966 let params = AdvanceEpochParams {
967 epoch: change_epoch.epoch,
968 next_protocol_version: change_epoch.protocol_version,
969 validator_subsidy: protocol_config.validator_target_reward(),
970 storage_charge: change_epoch.storage_charge,
971 computation_charge: change_epoch.computation_charge,
972 computation_charge_burned: change_epoch.computation_charge,
974 storage_rebate: change_epoch.storage_rebate,
975 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
976 reward_slashing_rate: protocol_config.reward_slashing_rate(),
977 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
978 max_committee_members_count: 0,
981 };
982 let advance_epoch_pt = construct_advance_epoch_pt_v1(builder, ¶ms)?;
983 advance_epoch_impl(
984 advance_epoch_pt,
985 params,
986 change_epoch.system_packages,
987 temporary_store,
988 tx_ctx,
989 move_vm,
990 gas_charger,
991 protocol_config,
992 metrics,
993 trace_builder_opt,
994 )
995 }
996
997 fn advance_epoch_v2(
1001 builder: ProgrammableTransactionBuilder,
1002 change_epoch_v2: ChangeEpochV2,
1003 temporary_store: &mut TemporaryStore<'_>,
1004 tx_ctx: &mut TxContext,
1005 move_vm: &Arc<MoveVM>,
1006 gas_charger: &mut GasCharger,
1007 protocol_config: &ProtocolConfig,
1008 metrics: Arc<LimitsMetrics>,
1009 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1010 ) -> Result<(), ExecutionError> {
1011 let params = AdvanceEpochParams {
1012 epoch: change_epoch_v2.epoch,
1013 next_protocol_version: change_epoch_v2.protocol_version,
1014 validator_subsidy: protocol_config.validator_target_reward(),
1015 storage_charge: change_epoch_v2.storage_charge,
1016 computation_charge: change_epoch_v2.computation_charge,
1017 computation_charge_burned: change_epoch_v2.computation_charge_burned,
1018 storage_rebate: change_epoch_v2.storage_rebate,
1019 non_refundable_storage_fee: change_epoch_v2.non_refundable_storage_fee,
1020 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1021 epoch_start_timestamp_ms: change_epoch_v2.epoch_start_timestamp_ms,
1022 max_committee_members_count: protocol_config.max_committee_members_count(),
1023 };
1024 let advance_epoch_pt = construct_advance_epoch_pt_v2(builder, ¶ms)?;
1025 advance_epoch_impl(
1026 advance_epoch_pt,
1027 params,
1028 change_epoch_v2.system_packages,
1029 temporary_store,
1030 tx_ctx,
1031 move_vm,
1032 gas_charger,
1033 protocol_config,
1034 metrics,
1035 trace_builder_opt,
1036 )
1037 }
1038
1039 fn process_system_packages(
1040 system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
1041 temporary_store: &mut TemporaryStore<'_>,
1042 tx_ctx: &mut TxContext,
1043 move_vm: &MoveVM,
1044 gas_charger: &mut GasCharger,
1045 protocol_config: &ProtocolConfig,
1046 metrics: Arc<LimitsMetrics>,
1047 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1048 ) {
1049 let binary_config = to_binary_config(protocol_config);
1050 for (version, modules, dependencies) in system_packages.into_iter() {
1051 let deserialized_modules: Vec<_> = modules
1052 .iter()
1053 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1054 .collect();
1055
1056 if version == OBJECT_START_VERSION {
1057 let package_id = deserialized_modules.first().unwrap().address();
1058 info!("adding new system package {package_id}");
1059
1060 let publish_pt = {
1061 let mut b = ProgrammableTransactionBuilder::new();
1062 b.command(Command::Publish(modules, dependencies));
1063 b.finish()
1064 };
1065
1066 programmable_transactions::execution::execute::<execution_mode::System>(
1067 protocol_config,
1068 metrics.clone(),
1069 move_vm,
1070 temporary_store,
1071 tx_ctx,
1072 gas_charger,
1073 publish_pt,
1074 trace_builder_opt,
1075 )
1076 .expect("System Package Publish must succeed");
1077 } else {
1078 let mut new_package = Object::new_system_package(
1079 &deserialized_modules,
1080 version,
1081 dependencies,
1082 tx_ctx.digest(),
1083 );
1084
1085 info!(
1086 "upgraded system package {:?}",
1087 new_package.compute_object_reference()
1088 );
1089
1090 new_package
1093 .data
1094 .try_as_package_mut()
1095 .unwrap()
1096 .decrement_version();
1097
1098 temporary_store.upgrade_system_package(new_package);
1100 }
1101 }
1102 }
1103
1104 fn setup_consensus_commit(
1110 consensus_commit_timestamp_ms: CheckpointTimestamp,
1111 temporary_store: &mut TemporaryStore<'_>,
1112 tx_ctx: &mut TxContext,
1113 move_vm: &Arc<MoveVM>,
1114 gas_charger: &mut GasCharger,
1115 protocol_config: &ProtocolConfig,
1116 metrics: Arc<LimitsMetrics>,
1117 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1118 ) -> Result<(), ExecutionError> {
1119 let pt = {
1120 let mut builder = ProgrammableTransactionBuilder::new();
1121 let res = builder.move_call(
1122 IOTA_FRAMEWORK_ADDRESS.into(),
1123 CLOCK_MODULE_NAME.to_owned(),
1124 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1125 vec![],
1126 vec![
1127 CallArg::CLOCK_MUT,
1128 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1129 ],
1130 );
1131 assert_invariant!(
1132 res.is_ok(),
1133 "Unable to generate consensus_commit_prologue transaction!"
1134 );
1135 builder.finish()
1136 };
1137 programmable_transactions::execution::execute::<execution_mode::System>(
1138 protocol_config,
1139 metrics,
1140 move_vm,
1141 temporary_store,
1142 tx_ctx,
1143 gas_charger,
1144 pt,
1145 trace_builder_opt,
1146 )
1147 }
1148
1149 fn setup_authenticator_state_create(
1153 mut builder: ProgrammableTransactionBuilder,
1154 ) -> ProgrammableTransactionBuilder {
1155 builder
1156 .move_call(
1157 IOTA_FRAMEWORK_ADDRESS.into(),
1158 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1159 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1160 vec![],
1161 vec![],
1162 )
1163 .expect("Unable to generate authenticator_state_create transaction!");
1164 builder
1165 }
1166
1167 fn setup_authenticator_state_update(
1174 update: AuthenticatorStateUpdateV1,
1175 temporary_store: &mut TemporaryStore<'_>,
1176 tx_ctx: &mut TxContext,
1177 move_vm: &Arc<MoveVM>,
1178 gas_charger: &mut GasCharger,
1179 protocol_config: &ProtocolConfig,
1180 metrics: Arc<LimitsMetrics>,
1181 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1182 ) -> Result<(), ExecutionError> {
1183 let pt = {
1184 let mut builder = ProgrammableTransactionBuilder::new();
1185 let res = builder.move_call(
1186 IOTA_FRAMEWORK_ADDRESS.into(),
1187 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1188 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1189 vec![],
1190 vec![
1191 CallArg::Object(ObjectArg::SharedObject {
1192 id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1193 initial_shared_version: update.authenticator_obj_initial_shared_version,
1194 mutable: true,
1195 }),
1196 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1197 ],
1198 );
1199 assert_invariant!(
1200 res.is_ok(),
1201 "Unable to generate authenticator_state_update transaction!"
1202 );
1203 builder.finish()
1204 };
1205 programmable_transactions::execution::execute::<execution_mode::System>(
1206 protocol_config,
1207 metrics,
1208 move_vm,
1209 temporary_store,
1210 tx_ctx,
1211 gas_charger,
1212 pt,
1213 trace_builder_opt,
1214 )
1215 }
1216
1217 fn setup_authenticator_state_expire(
1222 mut builder: ProgrammableTransactionBuilder,
1223 expire: AuthenticatorStateExpire,
1224 ) -> ProgrammableTransactionBuilder {
1225 builder
1226 .move_call(
1227 IOTA_FRAMEWORK_ADDRESS.into(),
1228 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1229 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1230 vec![],
1231 vec![
1232 CallArg::Object(ObjectArg::SharedObject {
1233 id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1234 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1235 mutable: true,
1236 }),
1237 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1238 ],
1239 )
1240 .expect("Unable to generate authenticator_state_expire transaction!");
1241 builder
1242 }
1243
1244 fn setup_randomness_state_update(
1250 update: RandomnessStateUpdate,
1251 temporary_store: &mut TemporaryStore<'_>,
1252 tx_ctx: &mut TxContext,
1253 move_vm: &Arc<MoveVM>,
1254 gas_charger: &mut GasCharger,
1255 protocol_config: &ProtocolConfig,
1256 metrics: Arc<LimitsMetrics>,
1257 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1258 ) -> Result<(), ExecutionError> {
1259 let pt = {
1260 let mut builder = ProgrammableTransactionBuilder::new();
1261 let res = builder.move_call(
1262 IOTA_FRAMEWORK_ADDRESS.into(),
1263 RANDOMNESS_MODULE_NAME.to_owned(),
1264 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1265 vec![],
1266 vec![
1267 CallArg::Object(ObjectArg::SharedObject {
1268 id: IOTA_RANDOMNESS_STATE_OBJECT_ID,
1269 initial_shared_version: update.randomness_obj_initial_shared_version,
1270 mutable: true,
1271 }),
1272 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1273 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1274 ],
1275 );
1276 assert_invariant!(
1277 res.is_ok(),
1278 "Unable to generate randomness_state_update transaction!"
1279 );
1280 builder.finish()
1281 };
1282 programmable_transactions::execution::execute::<execution_mode::System>(
1283 protocol_config,
1284 metrics,
1285 move_vm,
1286 temporary_store,
1287 tx_ctx,
1288 gas_charger,
1289 pt,
1290 trace_builder_opt,
1291 )
1292 }
1293}