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 BRIDGE_ADDRESS, IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_BRIDGE_OBJECT_ID,
18 IOTA_FRAMEWORK_ADDRESS, IOTA_FRAMEWORK_PACKAGE_ID, IOTA_RANDOMNESS_STATE_OBJECT_ID,
19 IOTA_SYSTEM_PACKAGE_ID,
20 authenticator_state::{
21 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME,
22 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME, AUTHENTICATOR_STATE_MODULE_NAME,
23 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME,
24 },
25 balance::{
26 BALANCE_CREATE_REWARDS_FUNCTION_NAME, BALANCE_DESTROY_REBATES_FUNCTION_NAME,
27 BALANCE_MODULE_NAME,
28 },
29 base_types::{
30 IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, TxContext,
31 },
32 bridge::{
33 BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER, BRIDGE_CREATE_FUNCTION_NAME,
34 BRIDGE_INIT_COMMITTEE_FUNCTION_NAME, BRIDGE_MODULE_NAME, BridgeChainId,
35 },
36 clock::{CLOCK_MODULE_NAME, CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME},
37 committee::EpochId,
38 digests::{ChainIdentifier, get_mainnet_chain_identifier, get_testnet_chain_identifier},
39 effects::TransactionEffects,
40 error::{ExecutionError, ExecutionErrorKind},
41 execution::{ExecutionResults, ExecutionResultsV1, is_certificate_denied},
42 execution_config_utils::to_binary_config,
43 execution_status::{CongestedObjects, ExecutionStatus},
44 gas::{GasCostSummary, IotaGasStatus},
45 gas_coin::GAS,
46 id::UID,
47 inner_temporary_store::InnerTemporaryStore,
48 iota_system_state::{
49 ADVANCE_EPOCH_FUNCTION_NAME, AdvanceEpochParams, IOTA_SYSTEM_MODULE_NAME,
50 },
51 messages_checkpoint::CheckpointTimestamp,
52 metrics::LimitsMetrics,
53 object::{OBJECT_START_VERSION, Object, ObjectInner},
54 programmable_transaction_builder::ProgrammableTransactionBuilder,
55 randomness_state::{RANDOMNESS_MODULE_NAME, RANDOMNESS_STATE_UPDATE_FUNCTION_NAME},
56 storage::{BackingStore, Storage},
57 transaction::{
58 Argument, AuthenticatorStateExpire, AuthenticatorStateUpdateV1, CallArg, ChangeEpoch,
59 ChangeEpochV2, CheckedInputObjects, Command, EndOfEpochTransactionKind,
60 GenesisTransaction, ObjectArg, ProgrammableTransaction, RandomnessStateUpdate,
61 TransactionKind,
62 },
63 };
64 use move_binary_format::CompiledModule;
65 use move_core_types::ident_str;
66 use move_trace_format::format::MoveTraceBuilder;
67 use move_vm_runtime::move_vm::MoveVM;
68 use tracing::{info, instrument, trace, warn};
69
70 use crate::{
71 adapter::new_move_vm,
72 execution_mode::{self, ExecutionMode},
73 gas_charger::GasCharger,
74 programmable_transactions,
75 temporary_store::TemporaryStore,
76 type_layout_resolver::TypeLayoutResolver,
77 };
78
79 #[instrument(name = "tx_execute_to_effects", level = "debug", skip_all)]
91 pub fn execute_transaction_to_effects<Mode: ExecutionMode>(
92 store: &dyn BackingStore,
93 input_objects: CheckedInputObjects,
94 gas_coins: Vec<ObjectRef>,
95 gas_status: IotaGasStatus,
96 transaction_kind: TransactionKind,
97 transaction_signer: IotaAddress,
98 transaction_digest: TransactionDigest,
99 move_vm: &Arc<MoveVM>,
100 epoch_id: &EpochId,
101 epoch_timestamp_ms: u64,
102 protocol_config: &ProtocolConfig,
103 metrics: Arc<LimitsMetrics>,
104 enable_expensive_checks: bool,
105 certificate_deny_set: &HashSet<TransactionDigest>,
106 trace_builder_opt: &mut Option<MoveTraceBuilder>,
107 ) -> (
108 InnerTemporaryStore,
109 IotaGasStatus,
110 TransactionEffects,
111 Result<Mode::ExecutionResults, ExecutionError>,
112 ) {
113 let input_objects = input_objects.into_inner();
114 let mutable_inputs = if enable_expensive_checks {
115 input_objects.mutable_inputs().keys().copied().collect()
116 } else {
117 HashSet::new()
118 };
119 let shared_object_refs = input_objects.filter_shared_objects();
120 let receiving_objects = transaction_kind.receiving_objects();
121 let mut transaction_dependencies = input_objects.transaction_dependencies();
122 let contains_deleted_input = input_objects.contains_deleted_objects();
123 let cancelled_objects = input_objects.get_cancelled_objects();
124
125 let mut temporary_store = TemporaryStore::new(
126 store,
127 input_objects,
128 receiving_objects,
129 transaction_digest,
130 protocol_config,
131 *epoch_id,
132 );
133
134 let mut gas_charger =
135 GasCharger::new(transaction_digest, gas_coins, gas_status, protocol_config);
136
137 let mut tx_ctx = TxContext::new_from_components(
138 &transaction_signer,
139 &transaction_digest,
140 epoch_id,
141 epoch_timestamp_ms,
142 );
143
144 let is_epoch_change = transaction_kind.is_end_of_epoch_tx();
145
146 let deny_cert = is_certificate_denied(&transaction_digest, certificate_deny_set);
147 let (gas_cost_summary, execution_result) = execute_transaction::<Mode>(
148 &mut temporary_store,
149 transaction_kind,
150 &mut gas_charger,
151 &mut tx_ctx,
152 move_vm,
153 protocol_config,
154 metrics,
155 enable_expensive_checks,
156 deny_cert,
157 contains_deleted_input,
158 cancelled_objects,
159 trace_builder_opt,
160 );
161
162 let status = if let Err(error) = &execution_result {
163 use ExecutionErrorKind as K;
165 match error.kind() {
166 K::InvariantViolation | K::VMInvariantViolation => {
167 #[skip_checked_arithmetic]
168 tracing::error!(
169 kind = ?error.kind(),
170 tx_digest = ?transaction_digest,
171 "INVARIANT VIOLATION! Source: {:?}",
172 error.source(),
173 );
174 }
175
176 K::IotaMoveVerificationError | K::VMVerificationOrDeserializationError => {
177 #[skip_checked_arithmetic]
178 tracing::debug!(
179 kind = ?error.kind(),
180 tx_digest = ?transaction_digest,
181 "Verification Error. Source: {:?}",
182 error.source(),
183 );
184 }
185
186 K::PublishUpgradeMissingDependency | K::PublishUpgradeDependencyDowngrade => {
187 #[skip_checked_arithmetic]
188 tracing::debug!(
189 kind = ?error.kind(),
190 tx_digest = ?transaction_digest,
191 "Publish/Upgrade Error. Source: {:?}",
192 error.source(),
193 )
194 }
195
196 _ => (),
197 };
198
199 let (status, command) = error.to_execution_status();
200 ExecutionStatus::new_failure(status, command)
201 } else {
202 ExecutionStatus::Success
203 };
204
205 #[skip_checked_arithmetic]
206 trace!(
207 tx_digest = ?transaction_digest,
208 computation_gas_cost = gas_cost_summary.computation_cost,
209 computation_gas_cost_burned = gas_cost_summary.computation_cost_burned,
210 storage_gas_cost = gas_cost_summary.storage_cost,
211 storage_gas_rebate = gas_cost_summary.storage_rebate,
212 "Finished execution of transaction with status {:?}",
213 status
214 );
215
216 transaction_dependencies.remove(&TransactionDigest::genesis_marker());
220
221 if enable_expensive_checks && !Mode::allow_arbitrary_function_calls() {
222 temporary_store
223 .check_ownership_invariants(
224 &transaction_signer,
225 &mut gas_charger,
226 &mutable_inputs,
227 is_epoch_change,
228 )
229 .unwrap()
230 } let (inner, effects) = temporary_store.into_effects(
233 shared_object_refs,
234 &transaction_digest,
235 transaction_dependencies,
236 gas_cost_summary,
237 status,
238 &mut gas_charger,
239 *epoch_id,
240 );
241
242 (
243 inner,
244 gas_charger.into_gas_status(),
245 effects,
246 execution_result,
247 )
248 }
249
250 pub fn execute_genesis_state_update(
257 store: &dyn BackingStore,
258 protocol_config: &ProtocolConfig,
259 metrics: Arc<LimitsMetrics>,
260 move_vm: &Arc<MoveVM>,
261 tx_context: &mut TxContext,
262 input_objects: CheckedInputObjects,
263 pt: ProgrammableTransaction,
264 ) -> Result<InnerTemporaryStore, ExecutionError> {
265 let input_objects = input_objects.into_inner();
266 let mut temporary_store = TemporaryStore::new(
267 store,
268 input_objects,
269 vec![],
270 tx_context.digest(),
271 protocol_config,
272 0,
273 );
274 let mut gas_charger = GasCharger::new_unmetered(tx_context.digest());
275 programmable_transactions::execution::execute::<execution_mode::Genesis>(
276 protocol_config,
277 metrics,
278 move_vm,
279 &mut temporary_store,
280 tx_context,
281 &mut gas_charger,
282 pt,
283 &mut None,
284 )?;
285 temporary_store.update_object_version_and_prev_tx();
286 Ok(temporary_store.into_inner())
287 }
288
289 #[instrument(name = "tx_execute", level = "debug", skip_all)]
298 fn execute_transaction<Mode: ExecutionMode>(
299 temporary_store: &mut TemporaryStore<'_>,
300 transaction_kind: TransactionKind,
301 gas_charger: &mut GasCharger,
302 tx_ctx: &mut TxContext,
303 move_vm: &Arc<MoveVM>,
304 protocol_config: &ProtocolConfig,
305 metrics: Arc<LimitsMetrics>,
306 enable_expensive_checks: bool,
307 deny_cert: bool,
308 contains_deleted_input: bool,
309 cancelled_objects: Option<(Vec<ObjectID>, SequenceNumber)>,
310 trace_builder_opt: &mut Option<MoveTraceBuilder>,
311 ) -> (
312 GasCostSummary,
313 Result<Mode::ExecutionResults, ExecutionError>,
314 ) {
315 gas_charger.smash_gas(temporary_store);
316
317 debug_assert!(
319 gas_charger.no_charges(),
320 "No gas charges must be applied yet"
321 );
322
323 let is_genesis_or_epoch_change_tx = matches!(transaction_kind, TransactionKind::Genesis(_))
324 || transaction_kind.is_end_of_epoch_tx();
325
326 let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary();
327
328 let result = gas_charger.charge_input_objects(temporary_store);
332 let mut result = result.and_then(|()| {
333 let mut execution_result = if deny_cert {
334 Err(ExecutionError::new(
335 ExecutionErrorKind::CertificateDenied,
336 None,
337 ))
338 } else if contains_deleted_input {
339 Err(ExecutionError::new(
340 ExecutionErrorKind::InputObjectDeleted,
341 None,
342 ))
343 } else if let Some((cancelled_objects, reason)) = cancelled_objects {
344 match reason {
345 SequenceNumber::CONGESTED => Err(ExecutionError::new(
346 ExecutionErrorKind::ExecutionCancelledDueToSharedObjectCongestion {
347 congested_objects: CongestedObjects(cancelled_objects),
348 },
349 None,
350 )),
351 SequenceNumber::RANDOMNESS_UNAVAILABLE => Err(ExecutionError::new(
352 ExecutionErrorKind::ExecutionCancelledDueToRandomnessUnavailable,
353 None,
354 )),
355 _ => panic!("invalid cancellation reason SequenceNumber: {reason}"),
356 }
357 } else {
358 execution_loop::<Mode>(
359 temporary_store,
360 transaction_kind,
361 tx_ctx,
362 move_vm,
363 gas_charger,
364 protocol_config,
365 metrics.clone(),
366 trace_builder_opt,
367 )
368 };
369
370 let meter_check = check_meter_limit(
371 temporary_store,
372 gas_charger,
373 protocol_config,
374 metrics.clone(),
375 );
376 if let Err(e) = meter_check {
377 execution_result = Err(e);
378 }
379
380 if execution_result.is_ok() {
381 let gas_check = check_written_objects_limit::<Mode>(
382 temporary_store,
383 gas_charger,
384 protocol_config,
385 metrics,
386 );
387 if let Err(e) = gas_check {
388 execution_result = Err(e);
389 }
390 }
391
392 execution_result
393 });
394
395 let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
396 temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
405
406 if let Err(e) = run_conservation_checks::<Mode>(
407 temporary_store,
408 gas_charger,
409 tx_ctx,
410 move_vm,
411 enable_expensive_checks,
412 &cost_summary,
413 is_genesis_or_epoch_change_tx,
414 advance_epoch_gas_summary,
415 ) {
416 result = Err(e);
418 }
419
420 (cost_summary, result)
421 }
422
423 #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
432 fn run_conservation_checks<Mode: ExecutionMode>(
433 temporary_store: &mut TemporaryStore<'_>,
434 gas_charger: &mut GasCharger,
435 tx_ctx: &mut TxContext,
436 move_vm: &Arc<MoveVM>,
437 enable_expensive_checks: bool,
438 cost_summary: &GasCostSummary,
439 is_genesis_or_epoch_change_tx: bool,
440 advance_epoch_gas_summary: Option<(u64, u64)>,
441 ) -> Result<(), ExecutionError> {
442 let mut result: std::result::Result<(), iota_types::error::ExecutionError> = Ok(());
443 if !is_genesis_or_epoch_change_tx && !Mode::skip_conservation_checks() {
444 let conservation_result = {
447 temporary_store
448 .check_iota_conserved(cost_summary)
449 .and_then(|()| {
450 if enable_expensive_checks {
451 let mut layout_resolver =
454 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
455 temporary_store.check_iota_conserved_expensive(
456 cost_summary,
457 advance_epoch_gas_summary,
458 &mut layout_resolver,
459 )
460 } else {
461 Ok(())
462 }
463 })
464 };
465 if let Err(conservation_err) = conservation_result {
466 result = Err(conservation_err);
470 gas_charger.reset(temporary_store);
471 gas_charger.charge_gas(temporary_store, &mut result);
472 if let Err(recovery_err) = {
474 temporary_store
475 .check_iota_conserved(cost_summary)
476 .and_then(|()| {
477 if enable_expensive_checks {
478 let mut layout_resolver =
481 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
482 temporary_store.check_iota_conserved_expensive(
483 cost_summary,
484 advance_epoch_gas_summary,
485 &mut layout_resolver,
486 )
487 } else {
488 Ok(())
489 }
490 })
491 } {
492 panic!(
496 "IOTA conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
497 tx_ctx.digest(),
498 recovery_err,
499 gas_charger.summary()
500 )
501 }
502 }
503 } result
507 }
508
509 #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
514 fn check_meter_limit(
515 temporary_store: &mut TemporaryStore<'_>,
516 gas_charger: &mut GasCharger,
517 protocol_config: &ProtocolConfig,
518 metrics: Arc<LimitsMetrics>,
519 ) -> Result<(), ExecutionError> {
520 let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
521
522 match check_limit_by_meter!(
527 !gas_charger.is_unmetered(),
528 effects_estimated_size,
529 protocol_config.max_serialized_tx_effects_size_bytes(),
530 protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
531 metrics.excessive_estimated_effects_size
532 ) {
533 LimitThresholdCrossed::None => Ok(()),
534 LimitThresholdCrossed::Soft(_, limit) => {
535 warn!(
536 effects_estimated_size = effects_estimated_size,
537 soft_limit = limit,
538 "Estimated transaction effects size crossed soft limit",
539 );
540 Ok(())
541 }
542 LimitThresholdCrossed::Hard(_, lim) => Err(ExecutionError::new_with_source(
543 ExecutionErrorKind::EffectsTooLarge {
544 current_size: effects_estimated_size as u64,
545 max_size: lim as u64,
546 },
547 "Transaction effects are too large",
548 )),
549 }
550 }
551
552 #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
557 fn check_written_objects_limit<Mode: ExecutionMode>(
558 temporary_store: &mut TemporaryStore<'_>,
559 gas_charger: &mut GasCharger,
560 protocol_config: &ProtocolConfig,
561 metrics: Arc<LimitsMetrics>,
562 ) -> Result<(), ExecutionError> {
563 if let (Some(normal_lim), Some(system_lim)) = (
564 protocol_config.max_size_written_objects_as_option(),
565 protocol_config.max_size_written_objects_system_tx_as_option(),
566 ) {
567 let written_objects_size = temporary_store.written_objects_size();
568
569 match check_limit_by_meter!(
570 !gas_charger.is_unmetered(),
571 written_objects_size,
572 normal_lim,
573 system_lim,
574 metrics.excessive_written_objects_size
575 ) {
576 LimitThresholdCrossed::None => (),
577 LimitThresholdCrossed::Soft(_, limit) => {
578 warn!(
579 written_objects_size = written_objects_size,
580 soft_limit = limit,
581 "Written objects size crossed soft limit",
582 )
583 }
584 LimitThresholdCrossed::Hard(_, lim) => {
585 return Err(ExecutionError::new_with_source(
586 ExecutionErrorKind::WrittenObjectsTooLarge {
587 current_size: written_objects_size as u64,
588 max_size: lim as u64,
589 },
590 "Written objects size crossed hard limit",
591 ));
592 }
593 };
594 }
595
596 Ok(())
597 }
598
599 #[instrument(level = "debug", skip_all)]
606 fn execution_loop<Mode: ExecutionMode>(
607 temporary_store: &mut TemporaryStore<'_>,
608 transaction_kind: TransactionKind,
609 tx_ctx: &mut TxContext,
610 move_vm: &Arc<MoveVM>,
611 gas_charger: &mut GasCharger,
612 protocol_config: &ProtocolConfig,
613 metrics: Arc<LimitsMetrics>,
614 trace_builder_opt: &mut Option<MoveTraceBuilder>,
615 ) -> Result<Mode::ExecutionResults, ExecutionError> {
616 let result = match transaction_kind {
617 TransactionKind::Genesis(GenesisTransaction { objects, events }) => {
618 if tx_ctx.epoch() != 0 {
619 panic!("BUG: Genesis Transactions can only be executed in epoch 0");
620 }
621
622 for genesis_object in objects {
623 match genesis_object {
624 iota_types::transaction::GenesisObject::RawObject { data, owner } => {
625 let object = ObjectInner {
626 data,
627 owner,
628 previous_transaction: tx_ctx.digest(),
629 storage_rebate: 0,
630 };
631 temporary_store.create_object(object.into());
632 }
633 }
634 }
635
636 temporary_store.record_execution_results(ExecutionResults::V1(
637 ExecutionResultsV1 {
638 user_events: events,
639 ..Default::default()
640 },
641 ));
642
643 Ok(Mode::empty_results())
644 }
645 TransactionKind::ConsensusCommitPrologueV1(prologue) => {
646 setup_consensus_commit(
647 prologue.commit_timestamp_ms,
648 temporary_store,
649 tx_ctx,
650 move_vm,
651 gas_charger,
652 protocol_config,
653 metrics,
654 trace_builder_opt,
655 )
656 .expect("ConsensusCommitPrologueV1 cannot fail");
657 Ok(Mode::empty_results())
658 }
659 TransactionKind::ProgrammableTransaction(pt) => {
660 programmable_transactions::execution::execute::<Mode>(
661 protocol_config,
662 metrics,
663 move_vm,
664 temporary_store,
665 tx_ctx,
666 gas_charger,
667 pt,
668 trace_builder_opt,
669 )
670 }
671 TransactionKind::EndOfEpochTransaction(txns) => {
672 let mut builder = ProgrammableTransactionBuilder::new();
673 let len = txns.len();
674 for (i, tx) in txns.into_iter().enumerate() {
675 match tx {
676 EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
677 assert_eq!(i, len - 1);
678 advance_epoch_v1(
679 builder,
680 change_epoch,
681 temporary_store,
682 tx_ctx,
683 move_vm,
684 gas_charger,
685 protocol_config,
686 metrics,
687 trace_builder_opt,
688 )?;
689 return Ok(Mode::empty_results());
690 }
691 EndOfEpochTransactionKind::ChangeEpochV2(change_epoch_v2) => {
692 assert_eq!(i, len - 1);
693 advance_epoch_v2(
694 builder,
695 change_epoch_v2,
696 temporary_store,
697 tx_ctx,
698 move_vm,
699 gas_charger,
700 protocol_config,
701 metrics,
702 trace_builder_opt,
703 )?;
704 return Ok(Mode::empty_results());
705 }
706 EndOfEpochTransactionKind::AuthenticatorStateCreate => {
707 assert!(protocol_config.enable_jwk_consensus_updates());
708 builder = setup_authenticator_state_create(builder);
709 }
710 EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
711 assert!(protocol_config.enable_jwk_consensus_updates());
712
713 builder = setup_authenticator_state_expire(builder, expire);
716 }
717 EndOfEpochTransactionKind::BridgeStateCreate(chain_id) => {
718 assert!(protocol_config.enable_bridge());
719 builder = setup_bridge_create(builder, chain_id)
720 }
721 EndOfEpochTransactionKind::BridgeCommitteeInit(bridge_shared_version) => {
722 assert!(protocol_config.enable_bridge());
723 assert!(protocol_config.should_try_to_finalize_bridge_committee());
724 builder = setup_bridge_committee_update(builder, bridge_shared_version)
725 }
726 }
727 }
728 unreachable!(
729 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
730 )
731 }
732 TransactionKind::AuthenticatorStateUpdateV1(auth_state_update) => {
733 setup_authenticator_state_update(
734 auth_state_update,
735 temporary_store,
736 tx_ctx,
737 move_vm,
738 gas_charger,
739 protocol_config,
740 metrics,
741 trace_builder_opt,
742 )?;
743 Ok(Mode::empty_results())
744 }
745 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
746 setup_randomness_state_update(
747 randomness_state_update,
748 temporary_store,
749 tx_ctx,
750 move_vm,
751 gas_charger,
752 protocol_config,
753 metrics,
754 trace_builder_opt,
755 )?;
756 Ok(Mode::empty_results())
757 }
758 }?;
759 temporary_store.check_execution_results_consistency()?;
760 Ok(result)
761 }
762
763 fn mint_epoch_rewards_in_pt(
772 builder: &mut ProgrammableTransactionBuilder,
773 params: &AdvanceEpochParams,
774 ) -> (Argument, Argument) {
775 let storage_charge_arg = builder
777 .input(CallArg::Pure(
778 bcs::to_bytes(¶ms.storage_charge).unwrap(),
779 ))
780 .unwrap();
781 let storage_charges = builder.programmable_move_call(
782 IOTA_FRAMEWORK_PACKAGE_ID,
783 BALANCE_MODULE_NAME.to_owned(),
784 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
785 vec![GAS::type_tag()],
786 vec![storage_charge_arg],
787 );
788
789 let computation_charge_arg = builder
791 .input(CallArg::Pure(
792 bcs::to_bytes(¶ms.computation_charge).unwrap(),
793 ))
794 .unwrap();
795 let computation_charges = builder.programmable_move_call(
796 IOTA_FRAMEWORK_PACKAGE_ID,
797 BALANCE_MODULE_NAME.to_owned(),
798 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
799 vec![GAS::type_tag()],
800 vec![computation_charge_arg],
801 );
802 (storage_charges, computation_charges)
803 }
804
805 pub fn construct_advance_epoch_pt_impl(
813 mut builder: ProgrammableTransactionBuilder,
814 params: &AdvanceEpochParams,
815 call_arg_vec: Vec<CallArg>,
816 ) -> Result<ProgrammableTransaction, ExecutionError> {
817 let (storage_charges, computation_charges) = mint_epoch_rewards_in_pt(&mut builder, params);
819 let mut arguments = vec![
820 builder
821 .pure(params.validator_subsidy)
822 .expect("bcs encoding a u64 should not fail"),
823 storage_charges,
824 computation_charges,
825 ];
826
827 let call_arg_arguments = call_arg_vec
828 .into_iter()
829 .map(|a| builder.input(a))
830 .collect::<Result<_, _>>();
831
832 assert_invariant!(
833 call_arg_arguments.is_ok(),
834 "Unable to generate args for advance_epoch transaction!"
835 );
836
837 arguments.append(&mut call_arg_arguments.unwrap());
838
839 info!("Call arguments to advance_epoch transaction: {:?}", params);
840
841 let storage_rebates = builder.programmable_move_call(
842 IOTA_SYSTEM_PACKAGE_ID,
843 IOTA_SYSTEM_MODULE_NAME.to_owned(),
844 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
845 vec![],
846 arguments,
847 );
848
849 builder.programmable_move_call(
851 IOTA_FRAMEWORK_PACKAGE_ID,
852 BALANCE_MODULE_NAME.to_owned(),
853 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
854 vec![GAS::type_tag()],
855 vec![storage_rebates],
856 );
857 Ok(builder.finish())
858 }
859
860 pub fn construct_advance_epoch_pt_v1(
861 builder: ProgrammableTransactionBuilder,
862 params: &AdvanceEpochParams,
863 ) -> Result<ProgrammableTransaction, ExecutionError> {
864 let call_arg_vec = vec![
869 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()), ];
877 construct_advance_epoch_pt_impl(builder, params, call_arg_vec)
878 }
879
880 pub fn construct_advance_epoch_pt_v2(
881 builder: ProgrammableTransactionBuilder,
882 params: &AdvanceEpochParams,
883 ) -> Result<ProgrammableTransaction, ExecutionError> {
884 let call_arg_vec = vec![
889 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()), ];
899 construct_advance_epoch_pt_impl(builder, params, call_arg_vec)
900 }
901
902 fn advance_epoch_impl(
909 advance_epoch_pt: ProgrammableTransaction,
910 params: AdvanceEpochParams,
911 system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
912 temporary_store: &mut TemporaryStore<'_>,
913 tx_ctx: &mut TxContext,
914 move_vm: &Arc<MoveVM>,
915 gas_charger: &mut GasCharger,
916 protocol_config: &ProtocolConfig,
917 metrics: Arc<LimitsMetrics>,
918 trace_builder_opt: &mut Option<MoveTraceBuilder>,
919 ) -> Result<(), ExecutionError> {
920 let result = programmable_transactions::execution::execute::<execution_mode::System>(
921 protocol_config,
922 metrics.clone(),
923 move_vm,
924 temporary_store,
925 tx_ctx,
926 gas_charger,
927 advance_epoch_pt,
928 trace_builder_opt,
929 );
930
931 #[cfg(msim)]
932 let result = maybe_modify_result(result, params.epoch);
933
934 if result.is_err() {
935 tracing::error!(
936 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx params: {:?}",
937 result.as_ref().err(),
938 temporary_store.objects(),
939 params,
940 );
941 temporary_store.drop_writes();
942 gas_charger.reset_storage_cost_and_rebate();
944
945 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
946 }
947
948 let new_vm = new_move_vm(
949 all_natives(true, protocol_config),
950 protocol_config,
951 None,
953 )
954 .expect("Failed to create new MoveVM");
955 process_system_packages(
956 system_packages,
957 temporary_store,
958 tx_ctx,
959 &new_vm,
960 gas_charger,
961 protocol_config,
962 metrics,
963 trace_builder_opt,
964 );
965
966 Ok(())
967 }
968
969 fn advance_epoch_v1(
973 builder: ProgrammableTransactionBuilder,
974 change_epoch: ChangeEpoch,
975 temporary_store: &mut TemporaryStore<'_>,
976 tx_ctx: &mut TxContext,
977 move_vm: &Arc<MoveVM>,
978 gas_charger: &mut GasCharger,
979 protocol_config: &ProtocolConfig,
980 metrics: Arc<LimitsMetrics>,
981 trace_builder_opt: &mut Option<MoveTraceBuilder>,
982 ) -> Result<(), ExecutionError> {
983 let params = AdvanceEpochParams {
984 epoch: change_epoch.epoch,
985 next_protocol_version: change_epoch.protocol_version,
986 validator_subsidy: protocol_config.validator_target_reward(),
987 storage_charge: change_epoch.storage_charge,
988 computation_charge: change_epoch.computation_charge,
989 computation_charge_burned: change_epoch.computation_charge,
991 storage_rebate: change_epoch.storage_rebate,
992 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
993 reward_slashing_rate: protocol_config.reward_slashing_rate(),
994 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
995 max_committee_members_count: 0,
998 };
999 let advance_epoch_pt = construct_advance_epoch_pt_v1(builder, ¶ms)?;
1000 advance_epoch_impl(
1001 advance_epoch_pt,
1002 params,
1003 change_epoch.system_packages,
1004 temporary_store,
1005 tx_ctx,
1006 move_vm,
1007 gas_charger,
1008 protocol_config,
1009 metrics,
1010 trace_builder_opt,
1011 )
1012 }
1013
1014 fn advance_epoch_v2(
1018 builder: ProgrammableTransactionBuilder,
1019 change_epoch_v2: ChangeEpochV2,
1020 temporary_store: &mut TemporaryStore<'_>,
1021 tx_ctx: &mut TxContext,
1022 move_vm: &Arc<MoveVM>,
1023 gas_charger: &mut GasCharger,
1024 protocol_config: &ProtocolConfig,
1025 metrics: Arc<LimitsMetrics>,
1026 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1027 ) -> Result<(), ExecutionError> {
1028 let params = AdvanceEpochParams {
1029 epoch: change_epoch_v2.epoch,
1030 next_protocol_version: change_epoch_v2.protocol_version,
1031 validator_subsidy: protocol_config.validator_target_reward(),
1032 storage_charge: change_epoch_v2.storage_charge,
1033 computation_charge: change_epoch_v2.computation_charge,
1034 computation_charge_burned: change_epoch_v2.computation_charge_burned,
1035 storage_rebate: change_epoch_v2.storage_rebate,
1036 non_refundable_storage_fee: change_epoch_v2.non_refundable_storage_fee,
1037 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1038 epoch_start_timestamp_ms: change_epoch_v2.epoch_start_timestamp_ms,
1039 max_committee_members_count: protocol_config.max_committee_members_count(),
1040 };
1041 let advance_epoch_pt = construct_advance_epoch_pt_v2(builder, ¶ms)?;
1042 advance_epoch_impl(
1043 advance_epoch_pt,
1044 params,
1045 change_epoch_v2.system_packages,
1046 temporary_store,
1047 tx_ctx,
1048 move_vm,
1049 gas_charger,
1050 protocol_config,
1051 metrics,
1052 trace_builder_opt,
1053 )
1054 }
1055
1056 fn process_system_packages(
1057 system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
1058 temporary_store: &mut TemporaryStore<'_>,
1059 tx_ctx: &mut TxContext,
1060 move_vm: &MoveVM,
1061 gas_charger: &mut GasCharger,
1062 protocol_config: &ProtocolConfig,
1063 metrics: Arc<LimitsMetrics>,
1064 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1065 ) {
1066 let binary_config = to_binary_config(protocol_config);
1067 for (version, modules, dependencies) in system_packages.into_iter() {
1068 let deserialized_modules: Vec<_> = modules
1069 .iter()
1070 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1071 .collect();
1072
1073 if version == OBJECT_START_VERSION {
1074 let package_id = deserialized_modules.first().unwrap().address();
1075 info!("adding new system package {package_id}");
1076
1077 let publish_pt = {
1078 let mut b = ProgrammableTransactionBuilder::new();
1079 b.command(Command::Publish(modules, dependencies));
1080 b.finish()
1081 };
1082
1083 programmable_transactions::execution::execute::<execution_mode::System>(
1084 protocol_config,
1085 metrics.clone(),
1086 move_vm,
1087 temporary_store,
1088 tx_ctx,
1089 gas_charger,
1090 publish_pt,
1091 trace_builder_opt,
1092 )
1093 .expect("System Package Publish must succeed");
1094 } else {
1095 let mut new_package = Object::new_system_package(
1096 &deserialized_modules,
1097 version,
1098 dependencies,
1099 tx_ctx.digest(),
1100 );
1101
1102 info!(
1103 "upgraded system package {:?}",
1104 new_package.compute_object_reference()
1105 );
1106
1107 new_package
1110 .data
1111 .try_as_package_mut()
1112 .unwrap()
1113 .decrement_version();
1114
1115 temporary_store.upgrade_system_package(new_package);
1117 }
1118 }
1119 }
1120
1121 fn setup_consensus_commit(
1127 consensus_commit_timestamp_ms: CheckpointTimestamp,
1128 temporary_store: &mut TemporaryStore<'_>,
1129 tx_ctx: &mut TxContext,
1130 move_vm: &Arc<MoveVM>,
1131 gas_charger: &mut GasCharger,
1132 protocol_config: &ProtocolConfig,
1133 metrics: Arc<LimitsMetrics>,
1134 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1135 ) -> Result<(), ExecutionError> {
1136 let pt = {
1137 let mut builder = ProgrammableTransactionBuilder::new();
1138 let res = builder.move_call(
1139 IOTA_FRAMEWORK_ADDRESS.into(),
1140 CLOCK_MODULE_NAME.to_owned(),
1141 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1142 vec![],
1143 vec![
1144 CallArg::CLOCK_MUT,
1145 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1146 ],
1147 );
1148 assert_invariant!(
1149 res.is_ok(),
1150 "Unable to generate consensus_commit_prologue transaction!"
1151 );
1152 builder.finish()
1153 };
1154 programmable_transactions::execution::execute::<execution_mode::System>(
1155 protocol_config,
1156 metrics,
1157 move_vm,
1158 temporary_store,
1159 tx_ctx,
1160 gas_charger,
1161 pt,
1162 trace_builder_opt,
1163 )
1164 }
1165
1166 fn setup_authenticator_state_create(
1170 mut builder: ProgrammableTransactionBuilder,
1171 ) -> ProgrammableTransactionBuilder {
1172 builder
1173 .move_call(
1174 IOTA_FRAMEWORK_ADDRESS.into(),
1175 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1176 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1177 vec![],
1178 vec![],
1179 )
1180 .expect("Unable to generate authenticator_state_create transaction!");
1181 builder
1182 }
1183
1184 fn setup_bridge_create(
1186 mut builder: ProgrammableTransactionBuilder,
1187 chain_id: ChainIdentifier,
1188 ) -> ProgrammableTransactionBuilder {
1189 let bridge_uid = builder
1190 .input(CallArg::Pure(
1191 UID::new(IOTA_BRIDGE_OBJECT_ID).to_bcs_bytes(),
1192 ))
1193 .expect("Unable to create Bridge object UID!");
1194
1195 let bridge_chain_id = if chain_id == get_mainnet_chain_identifier() {
1196 BridgeChainId::IotaMainnet as u8
1197 } else if chain_id == get_testnet_chain_identifier() {
1198 BridgeChainId::IotaTestnet as u8
1199 } else {
1200 BridgeChainId::IotaCustom as u8
1202 };
1203
1204 let bridge_chain_id = builder.pure(bridge_chain_id).unwrap();
1205 builder.programmable_move_call(
1206 BRIDGE_ADDRESS.into(),
1207 BRIDGE_MODULE_NAME.to_owned(),
1208 BRIDGE_CREATE_FUNCTION_NAME.to_owned(),
1209 vec![],
1210 vec![bridge_uid, bridge_chain_id],
1211 );
1212 builder
1213 }
1214
1215 fn setup_bridge_committee_update(
1218 mut builder: ProgrammableTransactionBuilder,
1219 bridge_shared_version: SequenceNumber,
1220 ) -> ProgrammableTransactionBuilder {
1221 let bridge = builder
1222 .obj(ObjectArg::SharedObject {
1223 id: IOTA_BRIDGE_OBJECT_ID,
1224 initial_shared_version: bridge_shared_version,
1225 mutable: true,
1226 })
1227 .expect("Unable to create Bridge object arg!");
1228 let system_state = builder
1229 .obj(ObjectArg::IOTA_SYSTEM_MUT)
1230 .expect("Unable to create System State object arg!");
1231
1232 let voting_power = builder.programmable_move_call(
1233 IOTA_SYSTEM_PACKAGE_ID,
1234 IOTA_SYSTEM_MODULE_NAME.to_owned(),
1235 ident_str!("validator_voting_powers").to_owned(),
1236 vec![],
1237 vec![system_state],
1238 );
1239
1240 let min_stake_participation_percentage = builder
1243 .input(CallArg::Pure(
1244 bcs::to_bytes(&BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER).unwrap(),
1245 ))
1246 .unwrap();
1247
1248 builder.programmable_move_call(
1249 BRIDGE_ADDRESS.into(),
1250 BRIDGE_MODULE_NAME.to_owned(),
1251 BRIDGE_INIT_COMMITTEE_FUNCTION_NAME.to_owned(),
1252 vec![],
1253 vec![bridge, voting_power, min_stake_participation_percentage],
1254 );
1255 builder
1256 }
1257
1258 fn setup_authenticator_state_update(
1265 update: AuthenticatorStateUpdateV1,
1266 temporary_store: &mut TemporaryStore<'_>,
1267 tx_ctx: &mut TxContext,
1268 move_vm: &Arc<MoveVM>,
1269 gas_charger: &mut GasCharger,
1270 protocol_config: &ProtocolConfig,
1271 metrics: Arc<LimitsMetrics>,
1272 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1273 ) -> Result<(), ExecutionError> {
1274 let pt = {
1275 let mut builder = ProgrammableTransactionBuilder::new();
1276 let res = builder.move_call(
1277 IOTA_FRAMEWORK_ADDRESS.into(),
1278 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1279 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1280 vec![],
1281 vec![
1282 CallArg::Object(ObjectArg::SharedObject {
1283 id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1284 initial_shared_version: update.authenticator_obj_initial_shared_version,
1285 mutable: true,
1286 }),
1287 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1288 ],
1289 );
1290 assert_invariant!(
1291 res.is_ok(),
1292 "Unable to generate authenticator_state_update transaction!"
1293 );
1294 builder.finish()
1295 };
1296 programmable_transactions::execution::execute::<execution_mode::System>(
1297 protocol_config,
1298 metrics,
1299 move_vm,
1300 temporary_store,
1301 tx_ctx,
1302 gas_charger,
1303 pt,
1304 trace_builder_opt,
1305 )
1306 }
1307
1308 fn setup_authenticator_state_expire(
1313 mut builder: ProgrammableTransactionBuilder,
1314 expire: AuthenticatorStateExpire,
1315 ) -> ProgrammableTransactionBuilder {
1316 builder
1317 .move_call(
1318 IOTA_FRAMEWORK_ADDRESS.into(),
1319 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1320 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1321 vec![],
1322 vec![
1323 CallArg::Object(ObjectArg::SharedObject {
1324 id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1325 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1326 mutable: true,
1327 }),
1328 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1329 ],
1330 )
1331 .expect("Unable to generate authenticator_state_expire transaction!");
1332 builder
1333 }
1334
1335 fn setup_randomness_state_update(
1341 update: RandomnessStateUpdate,
1342 temporary_store: &mut TemporaryStore<'_>,
1343 tx_ctx: &mut TxContext,
1344 move_vm: &Arc<MoveVM>,
1345 gas_charger: &mut GasCharger,
1346 protocol_config: &ProtocolConfig,
1347 metrics: Arc<LimitsMetrics>,
1348 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1349 ) -> Result<(), ExecutionError> {
1350 let pt = {
1351 let mut builder = ProgrammableTransactionBuilder::new();
1352 let res = builder.move_call(
1353 IOTA_FRAMEWORK_ADDRESS.into(),
1354 RANDOMNESS_MODULE_NAME.to_owned(),
1355 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1356 vec![],
1357 vec![
1358 CallArg::Object(ObjectArg::SharedObject {
1359 id: IOTA_RANDOMNESS_STATE_OBJECT_ID,
1360 initial_shared_version: update.randomness_obj_initial_shared_version,
1361 mutable: true,
1362 }),
1363 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1364 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1365 ],
1366 );
1367 assert_invariant!(
1368 res.is_ok(),
1369 "Unable to generate randomness_state_update transaction!"
1370 );
1371 builder.finish()
1372 };
1373 programmable_transactions::execution::execute::<execution_mode::System>(
1374 protocol_config,
1375 metrics,
1376 move_vm,
1377 temporary_store,
1378 tx_ctx,
1379 gas_charger,
1380 pt,
1381 trace_builder_opt,
1382 )
1383 }
1384}