1use std::{
7 collections::{BTreeMap, HashMap, HashSet},
8 fs,
9 fs::File,
10 io::Write,
11 path::{Path, PathBuf},
12 pin::Pin,
13 sync::{Arc, atomic::Ordering},
14 time::{Duration, SystemTime, UNIX_EPOCH},
15 vec,
16};
17
18use anyhow::bail;
19use arc_swap::{ArcSwap, Guard};
20use async_trait::async_trait;
21use authority_per_epoch_store::TxLockGuard;
22pub use authority_store::{AuthorityStore, ResolverWrapper, UpdateType};
23use fastcrypto::{
24 encoding::{Base58, Encoding},
25 hash::MultisetHash,
26};
27use iota_common::{debug_fatal, fatal};
28use iota_config::{
29 NodeConfig,
30 genesis::Genesis,
31 node::{
32 AuthorityOverloadConfig, DBCheckpointConfig, ExpensiveSafetyCheckConfig,
33 StateDebugDumpConfig,
34 },
35};
36use iota_framework::{BuiltInFramework, SystemPackage as FrameworkSystemPackage};
37use iota_json_rpc_types::{
38 DevInspectResults, DryRunTransactionBlockResponse, EventFilter, IotaEvent, IotaMoveValue,
39 IotaObjectDataFilter, IotaTransactionBlockData, IotaTransactionBlockEffects,
40 IotaTransactionBlockEvents, TransactionFilter,
41};
42use iota_macros::{fail_point, fail_point_async, fail_point_if};
43use iota_metrics::{
44 TX_TYPE_SHARED_OBJ_TX, TX_TYPE_SINGLE_WRITER_TX, monitored_scope, spawn_monitored_task,
45};
46use iota_sdk_types::{
47 Address, CheckpointContentsDigest, CheckpointDigest, Digest, EndOfEpochTransactionKind,
48 ExecutionStatus, GasPayment, MoveAuthenticator, MoveStruct, ObjectDigest, ObjectId,
49 ObjectReference, Owner, RandomnessRound, StructTag, SystemPackage, TransactionDigest,
50 TransactionEffectsDigest, TransactionExpiration, TransactionKind, TypeTag, Version,
51 checkpoint::{CheckpointCommitment, CheckpointContents, CheckpointSummary},
52 crypto::{Intent, IntentAppId, IntentMessage, IntentScope, IntentVersion},
53 gas::GasCostSummary,
54};
55use iota_storage::{
56 key_value_store::{
57 KVStoreTransactionData, TransactionKeyValueStore, TransactionKeyValueStoreTrait,
58 },
59 key_value_store_metrics::KeyValueStoreMetrics,
60};
61#[cfg(msim)]
62use iota_types::committee::CommitteeTrait;
63use iota_types::{
64 account_abstraction::authenticator_function::{
65 AuthenticatorFunctionRef, AuthenticatorFunctionRefForExecution,
66 authenticator_function_ref_v1_from_dynamic_field_object,
67 derive_authenticator_function_ref_v1_dynamic_field_id, extract_auth_fun_refs,
68 },
69 auth_context::AuthContextData,
70 base_types::{AuthorityName, ConciseableName, ObjectInfo, ObjectType, VersionNumber},
71 committee::{Committee, EpochId, ProtocolVersion},
72 crypto::{AuthorityPublicKey, AuthoritySignInfo, AuthoritySignature, Signer},
73 deny_list_v1::check_coin_deny_list_v1,
74 deny_rule_governance::DenyRuleConfig,
75 digests::ChainIdentifier,
76 dynamic_field::{DynamicFieldInfo, DynamicFieldName, visitor as DFV},
77 effects::{
78 InputSharedObject, SignedTransactionEffects, TransactionEffects, TransactionEffectsAPI,
79 TransactionEffectsExt, TransactionEvents, VerifiedSignedTransactionEffects,
80 },
81 error::{ExecutionError, IotaError, IotaResult, UserInputError},
82 event::{EventID, SystemEpochInfoEvent},
83 executable_transaction::VerifiedExecutableTransaction,
84 execution_config_utils::to_binary_config,
85 fp_ensure,
86 gas::IotaGasStatus,
87 gas_coin::{SIMULATION_GAS_COIN_VALUE, mock_simulation_gas_coin},
88 inner_temporary_store::{
89 InnerTemporaryStore, ObjectMap, PackageStoreWithFallback, TemporaryModuleResolver, TxCoins,
90 WrittenObjects,
91 },
92 iota_sdk_types_conversions::type_tag_core_to_sdk,
93 iota_system_state::{
94 IotaSystemState, IotaSystemStateTrait,
95 epoch_start_iota_system_state::EpochStartSystemStateTrait, get_iota_system_state,
96 },
97 layout_resolver::{LayoutResolver, into_struct_layout},
98 message_envelope::Message,
99 messages_checkpoint::{
100 CertifiedCheckpointSummary, CheckpointContentsExt, CheckpointRequest, CheckpointResponse,
101 CheckpointSequenceNumber, CheckpointSummaryResponse, CheckpointTimestamp,
102 ECMHLiveObjectSetDigest, VerifiedCheckpoint,
103 },
104 messages_consensus::AuthorityCapabilitiesV1,
105 messages_grpc::{
106 HandleTransactionResponse, LayoutGenerationOption, ObjectInfoRequest,
107 ObjectInfoRequestKind, ObjectInfoResponse, TransactionInfoRequest, TransactionInfoResponse,
108 TransactionStatus,
109 },
110 metrics::{BytecodeVerifierMetrics, LimitsMetrics},
111 move_authenticator::MoveAuthenticatorExt,
112 object::{
113 MoveStructExt, OBJECT_START_VERSION, Object, ObjectRead, PastObjectRead,
114 bounded_visitor::BoundedVisitor,
115 },
116 storage::{
117 BackingPackageStore, BackingStore, ObjectKey, ObjectOrTombstone, ObjectStore, WriteKind,
118 },
119 supported_protocol_versions::{
120 ProtocolConfig, SupportedProtocolVersions, SupportedProtocolVersionsWithHashes,
121 },
122 traffic_control::{PolicyConfig, RemoteFirewallConfig, TrafficControlReconfigParams},
123 transaction::*,
124 transaction_executor::{SimulateTransactionResult, VmChecks},
125};
126use itertools::Itertools;
127use move_binary_format::{CompiledModule, binary_config::BinaryConfig};
128use move_core_types::{
129 account_address::AccountAddress, annotated_value::MoveStructLayout, language_storage::ModuleId,
130};
131use parking_lot::Mutex;
132use prometheus_filtered::{
133 Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, MetricLevel,
134 Registry, register_histogram_vec_with_registry, register_histogram_with_registry,
135 register_int_counter_vec_with_registry, register_int_counter_with_registry,
136 register_int_gauge_vec_with_registry, register_int_gauge_with_registry,
137};
138use serde::{Deserialize, Serialize, de::DeserializeOwned};
139use tap::TapFallible;
140use tokio::{
141 sync::{RwLock, mpsc, mpsc::unbounded_channel, oneshot},
142 task::JoinHandle,
143};
144use tracing::{debug, error, info, instrument, trace, warn};
145use typed_store::TypedStoreError;
146
147use self::{
148 authority_store::ExecutionLockWriteGuard, authority_store_pruner::AuthorityStorePruningMetrics,
149};
150#[cfg(msim)]
151pub use crate::checkpoints::checkpoint_executor::utils::{
152 CheckpointTimeoutConfig, init_checkpoint_timeout_config,
153};
154use crate::{
155 authority::{
156 authority_per_epoch_store::{AuthorityPerEpochStore, TxGuard},
157 authority_per_epoch_store_pruner::AuthorityPerEpochStorePruner,
158 authority_store::{ExecutionLockReadGuard, ObjectLockStatus},
159 authority_store_pruner::{AuthorityStorePruner, EPOCH_DURATION_MS_FOR_TESTING},
160 authority_store_tables::AuthorityPrunerTables,
161 epoch_start_configuration::{EpochStartConfigTrait, EpochStartConfiguration},
162 },
163 authority_client::NetworkAuthorityClient,
164 checkpoint_progress_tracker::CheckpointProgressTracker,
165 checkpoints::CheckpointStore,
166 congestion_tracker::CongestionTracker,
167 consensus_adapter::ConsensusAdapter,
168 epoch::committee_store::CommitteeStore,
169 execution_cache::{
170 CheckpointCache, ExecutionCacheCommit, ExecutionCacheReconfigAPI,
171 ExecutionCacheTraitPointers, ExecutionCacheWrite, ObjectCacheRead, StateSyncAPI,
172 TransactionCacheRead,
173 },
174 execution_driver::execution_process,
175 global_state_hasher::{GlobalStateHashStore, GlobalStateHasher},
176 grpc_indexes::{GRPC_INDEXES_DIR, GrpcIndexesStore},
177 jsonrpc_index::{CoinInfo, IndexStore, ObjectIndexChanges},
178 metrics::{LatencyObserver, RateTracker},
179 module_cache_metrics::ResolverMetrics,
180 overload_monitor::{
181 AuthorityOverloadInfo, compute_graduated_load_shedding_percentage,
182 overload_monitor_accept_tx,
183 },
184 stake_aggregator::StakeAggregator,
185 subscription_handler::SubscriptionHandler,
186 traffic_controller::{TrafficController, metrics::TrafficControllerMetrics},
187 transaction_input_loader::TransactionInputLoader,
188 transaction_manager::TransactionManager,
189 transaction_outputs::TransactionOutputs,
190 validator_tx_finalizer::ValidatorTxFinalizer,
191 verify_indexes::verify_indexes,
192};
193
194#[cfg(test)]
195#[path = "unit_tests/authority_tests.rs"]
196pub mod authority_tests;
197
198#[cfg(test)]
199#[path = "unit_tests/transaction_tests.rs"]
200pub mod transaction_tests;
201
202#[cfg(test)]
203#[path = "unit_tests/batch_transaction_tests.rs"]
204mod batch_transaction_tests;
205
206#[cfg(test)]
207#[path = "unit_tests/move_integration_tests.rs"]
208pub mod move_integration_tests;
209
210#[cfg(test)]
211#[path = "unit_tests/gas_tests.rs"]
212mod gas_tests;
213
214#[cfg(test)]
215#[path = "unit_tests/batch_verification_tests.rs"]
216mod batch_verification_tests;
217
218#[cfg(test)]
219#[path = "unit_tests/coin_deny_list_tests.rs"]
220mod coin_deny_list_tests;
221
222#[cfg(test)]
223#[path = "unit_tests/auth_unit_test_utils.rs"]
224pub mod auth_unit_test_utils;
225
226#[cfg(any(test, feature = "test-utils"))]
227pub mod authority_test_utils;
228
229pub mod authority_per_epoch_store;
230pub mod authority_per_epoch_store_pruner;
231
232pub mod authority_store_pruner;
233pub mod authority_store_tables;
234pub mod authority_store_types;
235pub mod epoch_start_configuration;
236pub mod shared_object_congestion_tracker;
237pub mod shared_object_version_manager;
238pub mod suggested_gas_price_calculator;
239#[cfg(any(test, feature = "test-utils"))]
240pub mod test_authority_builder;
241pub mod transaction_deferral;
242
243pub(crate) mod authority_store;
244pub mod backpressure;
245pub(crate) mod dropped_tx_status_cache;
246
247pub struct AuthorityMetrics {
249 tx_orders: IntCounter,
250 total_certs: IntCounter,
251 total_cert_attempts: IntCounter,
252 total_effects: IntCounter,
253 pub shared_obj_tx: IntCounter,
254 sponsored_tx: IntCounter,
255 tx_already_processed: IntCounter,
256 num_input_objs: Histogram,
257 num_shared_objects: Histogram,
258 batch_size: Histogram,
259
260 authority_state_handle_transaction_latency: Histogram,
261
262 execute_certificate_latency_single_writer: Histogram,
263 execute_certificate_latency_shared_object: Histogram,
264
265 internal_execution_latency: Histogram,
266 execution_load_input_objects_latency: Histogram,
267 prepare_certificate_latency: Histogram,
268 commit_certificate_latency: Histogram,
269 db_checkpoint_latency: Histogram,
270
271 pub(crate) transaction_manager_num_enqueued_certificates: IntCounterVec,
272 pub(crate) transaction_manager_num_missing_objects: IntGauge,
273 pub(crate) transaction_manager_num_pending_certificates: IntGauge,
274 pub(crate) transaction_manager_num_executing_certificates: IntGauge,
275 pub(crate) transaction_manager_num_ready: IntGauge,
276 pub(crate) transaction_manager_object_cache_size: IntGauge,
277 pub(crate) transaction_manager_object_cache_hits: IntCounter,
278 pub(crate) transaction_manager_object_cache_misses: IntCounter,
279 pub(crate) transaction_manager_object_cache_evictions: IntCounter,
280 pub(crate) transaction_manager_package_cache_size: IntGauge,
281 pub(crate) transaction_manager_package_cache_hits: IntCounter,
282 pub(crate) transaction_manager_package_cache_misses: IntCounter,
283 pub(crate) transaction_manager_package_cache_evictions: IntCounter,
284 pub(crate) transaction_manager_transaction_queue_age_s: Histogram,
285
286 pub(crate) execution_driver_executed_transactions: IntCounter,
287 pub(crate) execution_driver_dispatch_queue: IntGauge,
288 pub(crate) execution_queueing_delay_s: Histogram,
289 pub(crate) prepare_cert_gas_latency_ratio: Histogram,
290 pub(crate) execution_gas_latency_ratio: Histogram,
291
292 pub(crate) skipped_consensus_txns: IntCounter,
293 pub(crate) skipped_consensus_txns_cache_hit: IntCounter,
294
295 pub(crate) authority_overload_status: IntGauge,
296 pub(crate) consensus_queue_load_shedding_percentage: IntGauge,
298 pub(crate) local_post_consensus_load_shedding_percentage: IntGauge,
302
303 pub(crate) transaction_overload_sources: IntCounterVec,
304
305 post_processing_total_events_emitted: IntCounter,
307 post_processing_total_tx_indexed: IntCounter,
308 post_processing_total_tx_had_event_processed: IntCounter,
309 post_processing_total_failures: IntCounter,
310
311 pub consensus_handler_processed: IntCounterVec,
313 pub consensus_handler_transaction_sizes: HistogramVec,
314 pub consensus_handler_num_low_scoring_authorities: IntGauge,
315 pub consensus_handler_scores: IntGaugeVec,
316 pub consensus_handler_deferred_transactions: IntCounter,
317 pub consensus_handler_congested_transactions: IntCounter,
318 pub consensus_handler_cancelled_transactions: IntCounter,
319 pub consensus_handler_validation_dropped_transactions: IntCounter,
323 pub consensus_handler_load_shedding_dropped_transactions: IntCounter,
327 pub consensus_handler_load_shedding_percentage: IntGauge,
333 pub consensus_handler_max_object_costs: IntGaugeVec,
334 pub consensus_committed_subdags: IntCounterVec,
335 pub consensus_committed_messages: IntGaugeVec,
336 pub consensus_committed_user_transactions: IntGaugeVec,
337 pub consensus_handler_leader_round: IntGauge,
338 pub consensus_calculated_throughput: IntGauge,
339 pub consensus_calculated_throughput_profile: IntGauge,
340
341 pub validator_scoreboard_scores: IntGaugeVec,
342 pub invalid_misbehavior_reports_by_authority: IntGaugeVec,
343
344 pub limits_metrics: Arc<LimitsMetrics>,
345
346 pub bytecode_verifier_metrics: Arc<BytecodeVerifierMetrics>,
348
349 pub multisig_sig_count: IntCounter,
351
352 pub execution_queueing_latency: LatencyObserver,
355
356 pub txn_ready_rate_tracker: Arc<Mutex<RateTracker>>,
363
364 pub execution_rate_tracker: Arc<Mutex<RateTracker>>,
367}
368
369const POSITIVE_INT_BUCKETS: &[f64] = &[
371 1., 2., 5., 7., 10., 20., 50., 70., 100., 200., 500., 700., 1000., 2000., 5000., 7000., 10000.,
372 20000., 50000., 70000., 100000., 200000., 500000., 700000., 1000000., 2000000., 5000000.,
373 7000000., 10000000.,
374];
375
376const LATENCY_SEC_BUCKETS: &[f64] = &[
377 0.0005, 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1., 2., 3., 4., 5., 6., 7., 8., 9.,
378 10., 20., 30., 60., 90.,
379];
380
381const LOW_LATENCY_SEC_BUCKETS: &[f64] = &[
383 0.00001, 0.00002, 0.00005, 0.0001, 0.0002, 0.0005, 0.001, 0.002, 0.005, 0.01, 0.02, 0.05, 0.1,
384 0.2, 0.5, 1., 2., 5., 10., 20., 50., 100.,
385];
386
387const GAS_LATENCY_RATIO_BUCKETS: &[f64] = &[
388 10.0, 50.0, 100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0,
389 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0, 50000.0, 100000.0, 1000000.0,
390];
391
392impl AuthorityMetrics {
393 pub fn new(registry: &prometheus_filtered::Registry) -> AuthorityMetrics {
394 let execute_certificate_latency = register_histogram_vec_with_registry!(
395 "authority_state_execute_certificate_latency",
396 "Latency of executing certificates, including waiting for inputs",
397 &["tx_type"],
398 LATENCY_SEC_BUCKETS.to_vec(),
399 registry;
400 MetricLevel::Info,
401 )
402 .unwrap();
403
404 let execute_certificate_latency_single_writer =
405 execute_certificate_latency.with_label_values(&[TX_TYPE_SINGLE_WRITER_TX]);
406 let execute_certificate_latency_shared_object =
407 execute_certificate_latency.with_label_values(&[TX_TYPE_SHARED_OBJ_TX]);
408
409 Self {
410 tx_orders: register_int_counter_with_registry!(
411 "total_transaction_orders",
412 "Total number of transaction orders",
413 registry;
414 MetricLevel::Warn,
415 )
416 .unwrap(),
417 total_certs: register_int_counter_with_registry!(
418 "total_transaction_certificates",
419 "Total number of transaction certificates handled",
420 registry;
421 MetricLevel::Warn,
422 )
423 .unwrap(),
424 total_cert_attempts: register_int_counter_with_registry!(
425 "total_handle_certificate_attempts",
426 "Number of calls to handle_certificate",
427 registry,
428 )
429 .unwrap(),
430 total_effects: register_int_counter_with_registry!(
432 "total_transaction_effects",
433 "Total number of transaction effects produced",
434 registry;
435 MetricLevel::Warn,
436 )
437 .unwrap(),
438
439 shared_obj_tx: register_int_counter_with_registry!(
440 "num_shared_obj_tx",
441 "Number of transactions involving shared objects",
442 registry;
443 MetricLevel::Warn,
444 )
445 .unwrap(),
446
447 sponsored_tx: register_int_counter_with_registry!(
448 "num_sponsored_tx",
449 "Number of sponsored transactions",
450 registry,
451 )
452 .unwrap(),
453
454 tx_already_processed: register_int_counter_with_registry!(
455 "num_tx_already_processed",
456 "Number of transaction orders already processed previously",
457 registry,
458 )
459 .unwrap(),
460 num_input_objs: register_histogram_with_registry!(
461 "num_input_objects",
462 "Distribution of number of input TX objects per TX",
463 POSITIVE_INT_BUCKETS.to_vec(),
464 registry;
465 MetricLevel::Warn,
466 )
467 .unwrap(),
468 num_shared_objects: register_histogram_with_registry!(
469 "num_shared_objects",
470 "Number of shared input objects per TX",
471 POSITIVE_INT_BUCKETS.to_vec(),
472 registry,
473 )
474 .unwrap(),
475 batch_size: register_histogram_with_registry!(
476 "batch_size",
477 "Distribution of size of transaction batch",
478 POSITIVE_INT_BUCKETS.to_vec(),
479 registry,
480 )
481 .unwrap(),
482 authority_state_handle_transaction_latency: register_histogram_with_registry!(
483 "authority_state_handle_transaction_latency",
484 "Latency of handling transactions",
485 LATENCY_SEC_BUCKETS.to_vec(),
486 registry,
487 )
488 .unwrap(),
489 execute_certificate_latency_single_writer,
490 execute_certificate_latency_shared_object,
491 internal_execution_latency: register_histogram_with_registry!(
492 "authority_state_internal_execution_latency",
493 "Latency of actual certificate executions",
494 LATENCY_SEC_BUCKETS.to_vec(),
495 registry,
496 )
497 .unwrap(),
498 execution_load_input_objects_latency: register_histogram_with_registry!(
499 "authority_state_execution_load_input_objects_latency",
500 "Latency of loading input objects for execution",
501 LOW_LATENCY_SEC_BUCKETS.to_vec(),
502 registry,
503 )
504 .unwrap(),
505 prepare_certificate_latency: register_histogram_with_registry!(
506 "authority_state_prepare_certificate_latency",
507 "Latency of executing certificates, before committing the results",
508 LATENCY_SEC_BUCKETS.to_vec(),
509 registry,
510 )
511 .unwrap(),
512 commit_certificate_latency: register_histogram_with_registry!(
513 "authority_state_commit_certificate_latency",
514 "Latency of committing certificate execution results",
515 LATENCY_SEC_BUCKETS.to_vec(),
516 registry,
517 )
518 .unwrap(),
519 db_checkpoint_latency: register_histogram_with_registry!(
520 "db_checkpoint_latency",
521 "Latency of checkpointing dbs",
522 LATENCY_SEC_BUCKETS.to_vec(),
523 registry,
524 ).unwrap(),
525 transaction_manager_num_enqueued_certificates: register_int_counter_vec_with_registry!(
526 "transaction_manager_num_enqueued_certificates",
527 "Current number of certificates enqueued to TransactionManager",
528 &["result"],
529 registry,
530 )
531 .unwrap(),
532 transaction_manager_num_missing_objects: register_int_gauge_with_registry!(
533 "transaction_manager_num_missing_objects",
534 "Current number of missing objects in TransactionManager",
535 registry,
536 )
537 .unwrap(),
538 transaction_manager_num_pending_certificates: register_int_gauge_with_registry!(
539 "transaction_manager_num_pending_certificates",
540 "Number of certificates pending in TransactionManager, with at least 1 missing input object",
541 registry;
542 MetricLevel::Warn,
543 )
544 .unwrap(),
545 transaction_manager_num_executing_certificates: register_int_gauge_with_registry!(
546 "transaction_manager_num_executing_certificates",
547 "Number of executing certificates, including queued and actually running certificates",
548 registry;
549 MetricLevel::Warn,
550 )
551 .unwrap(),
552 transaction_manager_num_ready: register_int_gauge_with_registry!(
553 "transaction_manager_num_ready",
554 "Number of ready transactions in TransactionManager",
555 registry,
556 )
557 .unwrap(),
558 transaction_manager_object_cache_size: register_int_gauge_with_registry!(
559 "transaction_manager_object_cache_size",
560 "Current size of object-availability cache in TransactionManager",
561 registry,
562 )
563 .unwrap(),
564 transaction_manager_object_cache_hits: register_int_counter_with_registry!(
565 "transaction_manager_object_cache_hits",
566 "Number of object-availability cache hits in TransactionManager",
567 registry,
568 )
569 .unwrap(),
570 authority_overload_status: register_int_gauge_with_registry!(
571 "authority_overload_status",
572 "Whether authority is current experiencing overload and enters load shedding mode.",
573 registry;
574 MetricLevel::Warn,)
575 .unwrap(),
576 local_post_consensus_load_shedding_percentage: register_int_gauge_with_registry!(
577 "authority_load_shedding_percentage",
578 "This authority's locally computed load shedding percentage. In the P-COOL flow this is the value broadcast to peers, not necessarily the rate enforced (see consensus_handler_load_shedding_percentage).",
579 registry;
580 MetricLevel::Info,)
581 .unwrap(),
582 consensus_queue_load_shedding_percentage: register_int_gauge_with_registry!(
583 "consensus_queue_load_shedding_percentage",
584 "Percentage of transactions shed due to consensus queue length. Separate admission-control signal, not an input to authority_load_shedding_percentage.",
585 registry)
586 .unwrap(),
587 transaction_manager_object_cache_misses: register_int_counter_with_registry!(
588 "transaction_manager_object_cache_misses",
589 "Number of object-availability cache misses in TransactionManager",
590 registry,
591 )
592 .unwrap(),
593 transaction_manager_object_cache_evictions: register_int_counter_with_registry!(
594 "transaction_manager_object_cache_evictions",
595 "Number of object-availability cache evictions in TransactionManager",
596 registry,
597 )
598 .unwrap(),
599 transaction_manager_package_cache_size: register_int_gauge_with_registry!(
600 "transaction_manager_package_cache_size",
601 "Current size of package-availability cache in TransactionManager",
602 registry,
603 )
604 .unwrap(),
605 transaction_manager_package_cache_hits: register_int_counter_with_registry!(
606 "transaction_manager_package_cache_hits",
607 "Number of package-availability cache hits in TransactionManager",
608 registry,
609 )
610 .unwrap(),
611 transaction_manager_package_cache_misses: register_int_counter_with_registry!(
612 "transaction_manager_package_cache_misses",
613 "Number of package-availability cache misses in TransactionManager",
614 registry,
615 )
616 .unwrap(),
617 transaction_manager_package_cache_evictions: register_int_counter_with_registry!(
618 "transaction_manager_package_cache_evictions",
619 "Number of package-availability cache evictions in TransactionManager",
620 registry,
621 )
622 .unwrap(),
623 transaction_manager_transaction_queue_age_s: register_histogram_with_registry!(
624 "transaction_manager_transaction_queue_age_s",
625 "Time spent in waiting for transaction in the queue",
626 LATENCY_SEC_BUCKETS.to_vec(),
627 registry;
628 MetricLevel::Warn,
629 )
630 .unwrap(),
631 transaction_overload_sources: register_int_counter_vec_with_registry!(
632 "transaction_overload_sources",
633 "Number of times each source indicates transaction overload.",
634 &["source"],
635 registry)
636 .unwrap(),
637 execution_driver_executed_transactions: register_int_counter_with_registry!(
638 "execution_driver_executed_transactions",
639 "Cumulative number of transaction executed by execution driver",
640 registry;
641 MetricLevel::Warn,
642 )
643 .unwrap(),
644 execution_driver_dispatch_queue: register_int_gauge_with_registry!(
645 "execution_driver_dispatch_queue",
646 "Number of transaction pending in execution driver dispatch queue",
647 registry,
648 )
649 .unwrap(),
650 execution_queueing_delay_s: register_histogram_with_registry!(
651 "execution_queueing_delay_s",
652 "Queueing delay between a transaction is ready for execution until it starts executing.",
653 LATENCY_SEC_BUCKETS.to_vec(),
654 registry
655 )
656 .unwrap(),
657 prepare_cert_gas_latency_ratio: register_histogram_with_registry!(
658 "prepare_cert_gas_latency_ratio",
659 "The ratio of computation gas divided by VM execution latency.",
660 GAS_LATENCY_RATIO_BUCKETS.to_vec(),
661 registry
662 )
663 .unwrap(),
664 execution_gas_latency_ratio: register_histogram_with_registry!(
665 "execution_gas_latency_ratio",
666 "The ratio of computation gas divided by certificate execution latency, include committing certificate.",
667 GAS_LATENCY_RATIO_BUCKETS.to_vec(),
668 registry
669 )
670 .unwrap(),
671 skipped_consensus_txns: register_int_counter_with_registry!(
672 "skipped_consensus_txns",
673 "Total number of consensus transactions skipped",
674 registry,
675 )
676 .unwrap(),
677 skipped_consensus_txns_cache_hit: register_int_counter_with_registry!(
678 "skipped_consensus_txns_cache_hit",
679 "Total number of consensus transactions skipped because of local cache hit",
680 registry,
681 )
682 .unwrap(),
683 post_processing_total_events_emitted: register_int_counter_with_registry!(
684 "post_processing_total_events_emitted",
685 "Total number of events emitted in post processing",
686 registry,
687 )
688 .unwrap(),
689 post_processing_total_tx_indexed: register_int_counter_with_registry!(
690 "post_processing_total_tx_indexed",
691 "Total number of txes indexed in post processing",
692 registry,
693 )
694 .unwrap(),
695 post_processing_total_tx_had_event_processed: register_int_counter_with_registry!(
696 "post_processing_total_tx_had_event_processed",
697 "Total number of txes finished event processing in post processing",
698 registry,
699 )
700 .unwrap(),
701 post_processing_total_failures: register_int_counter_with_registry!(
702 "post_processing_total_failures",
703 "Total number of failure in post processing",
704 registry,
705 )
706 .unwrap(),
707 consensus_handler_processed: register_int_counter_vec_with_registry!(
708 "consensus_handler_processed",
709 "Number of transactions processed by consensus handler",
710 &["class"],
711 registry
712 ).unwrap(),
713 consensus_handler_transaction_sizes: register_histogram_vec_with_registry!(
714 "consensus_handler_transaction_sizes",
715 "Sizes of each type of transactions processed by consensus handler",
716 &["class"],
717 POSITIVE_INT_BUCKETS.to_vec(),
718 registry;
719 MetricLevel::Warn,
720 ).unwrap(),
721 consensus_handler_num_low_scoring_authorities: register_int_gauge_with_registry!(
722 "consensus_handler_num_low_scoring_authorities",
723 "Number of low scoring authorities based on reputation scores from consensus",
724 registry
725 ).unwrap(),
726 consensus_handler_scores: register_int_gauge_vec_with_registry!(
727 "consensus_handler_scores",
728 "scores from consensus for each authority",
729 &["authority"],
730 registry,
731 ).unwrap(),
732 validator_scoreboard_scores: register_int_gauge_vec_with_registry!(
733 "validator_scoreboard_scores",
734 "Per-authority validator scores published by the local Scoreboard after each consensus commit. Range [0, MAX_SCORE].",
735 &["authority"],
736 registry;
737 MetricLevel::Warn,
738 ).unwrap(),
739 invalid_misbehavior_reports_by_authority: register_int_gauge_vec_with_registry!(
740 "invalid_misbehavior_reports_by_authority",
741 "Cumulative count of invalid misbehavior reports received from each reporting authority in the current epoch. Bumped when a `MisbehaviorReport` consensus transaction fails sender/authority match or payload validation. Snapshot republished after each consensus commit.",
742 &["authority"],
743 registry;
744 MetricLevel::Warn,
745 ).unwrap(),
746 consensus_handler_deferred_transactions: register_int_counter_with_registry!(
747 "consensus_handler_deferred_transactions",
748 "Number of transactions deferred by consensus handler",
749 registry,
750 ).unwrap(),
751 consensus_handler_congested_transactions: register_int_counter_with_registry!(
752 "consensus_handler_congested_transactions",
753 "Number of transactions deferred by consensus handler due to congestion",
754 registry,
755 ).unwrap(),
756 consensus_handler_cancelled_transactions: register_int_counter_with_registry!(
757 "consensus_handler_cancelled_transactions",
758 "Number of transactions cancelled by consensus handler",
759 registry,
760 ).unwrap(),
761 consensus_handler_validation_dropped_transactions: register_int_counter_with_registry!(
762 "consensus_handler_validation_dropped_transactions",
763 "Number of UserTransactionV1 transactions dropped by post-consensus validation",
764 registry,
765 ).unwrap(),
766 consensus_handler_load_shedding_dropped_transactions: register_int_counter_with_registry!(
767 "consensus_handler_load_shedding_dropped_transactions",
768 "Number of user transactions dropped by post-consensus load shedding, based on the quorum load shedding percentage",
769 registry,
770 ).unwrap(),
771 consensus_handler_load_shedding_percentage: register_int_gauge_with_registry!(
772 "consensus_handler_load_shedding_percentage",
773 "Stake-weighted quorum (2f+1) load shedding percentage enforced on user transactions in the most recent consensus commit. 0 when the P-COOL flow is disabled.",
774 registry,
775 ).unwrap(),
776 consensus_handler_max_object_costs: register_int_gauge_vec_with_registry!(
777 "consensus_handler_max_congestion_control_object_costs",
778 "Max object costs for congestion control in the current consensus commit",
779 &["commit_type"],
780 registry,
781 ).unwrap(),
782 consensus_committed_subdags: register_int_counter_vec_with_registry!(
783 "consensus_committed_subdags",
784 "Number of committed subdags, sliced by leader",
785 &["authority"],
786 registry,
787 ).unwrap(),
788 consensus_committed_messages: register_int_gauge_vec_with_registry!(
789 "consensus_committed_messages",
790 "Total number of committed consensus messages, sliced by author",
791 &["authority"],
792 registry;
793 MetricLevel::Warn,
794 ).unwrap(),
795 consensus_committed_user_transactions: register_int_gauge_vec_with_registry!(
796 "consensus_committed_user_transactions",
797 "Number of committed user transactions, sliced by submitter",
798 &["authority"],
799 registry,
800 ).unwrap(),
801 consensus_handler_leader_round: register_int_gauge_with_registry!(
802 "consensus_handler_leader_round",
803 "The leader round of the current consensus output being processed in the consensus handler",
804 registry;
805 MetricLevel::Warn,
806 ).unwrap(),
807 limits_metrics: Arc::new(LimitsMetrics::new(registry)),
808 bytecode_verifier_metrics: Arc::new(BytecodeVerifierMetrics::new(registry)),
809 multisig_sig_count: register_int_counter_with_registry!(
810 "multisig_sig_count",
811 "Count of multisig signatures",
812 registry,
813 )
814 .unwrap(),
815 consensus_calculated_throughput: register_int_gauge_with_registry!(
816 "consensus_calculated_throughput",
817 "The calculated throughput from consensus output. Result is calculated based on unique transactions.",
818 registry,
819 ).unwrap(),
820 consensus_calculated_throughput_profile: register_int_gauge_with_registry!(
821 "consensus_calculated_throughput_profile",
822 "The current active calculated throughput profile",
823 registry
824 ).unwrap(),
825 execution_queueing_latency: LatencyObserver::new(),
826 txn_ready_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
827 execution_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
828 }
829 }
830
831 pub fn reset_on_reconfigure(&self) {
835 self.consensus_committed_messages.reset();
836 self.consensus_handler_scores.reset();
837 self.validator_scoreboard_scores.reset();
838 self.invalid_misbehavior_reports_by_authority.reset();
839 self.consensus_committed_user_transactions.reset();
840 }
841}
842
843pub type StableSyncAuthoritySigner = Pin<Arc<dyn Signer<AuthoritySignature> + Send + Sync>>;
850
851pub struct AuthorityState {
852 pub name: AuthorityName,
855 pub secret: StableSyncAuthoritySigner,
857
858 input_loader: TransactionInputLoader,
860 execution_cache_trait_pointers: ExecutionCacheTraitPointers,
861
862 epoch_store: ArcSwap<AuthorityPerEpochStore>,
863
864 execution_lock: RwLock<EpochId>,
870
871 pub indexes: Option<Arc<IndexStore>>,
872 pub grpc_indexes_store: Option<Arc<GrpcIndexesStore>>,
873
874 pub subscription_handler: Arc<SubscriptionHandler>,
875 pub checkpoint_store: Arc<CheckpointStore>,
876
877 committee_store: Arc<CommitteeStore>,
878
879 transaction_manager: Arc<TransactionManager>,
881
882 #[cfg_attr(not(test), expect(unused))]
884 tx_execution_shutdown: Mutex<Option<oneshot::Sender<()>>>,
885
886 pub metrics: Arc<AuthorityMetrics>,
887 pruner: AuthorityStorePruner,
890 authority_per_epoch_pruner: AuthorityPerEpochStorePruner,
891 checkpoint_progress_tracker: Option<Arc<CheckpointProgressTracker>>,
892
893 db_checkpoint_config: DBCheckpointConfig,
895
896 pub config: NodeConfig,
897
898 pub overload_info: AuthorityOverloadInfo,
900
901 pub validator_tx_finalizer: Option<Arc<ValidatorTxFinalizer<NetworkAuthorityClient>>>,
902
903 chain_identifier: ChainIdentifier,
906
907 pub(crate) congestion_tracker: Arc<CongestionTracker>,
908
909 pub traffic_controller: Option<Arc<TrafficController>>,
911}
912
913impl AuthorityState {
922 pub fn is_committee_validator(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
923 epoch_store.committee().authority_exists(&self.name)
924 }
925
926 pub fn is_active_validator(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
927 epoch_store
928 .active_validators()
929 .iter()
930 .any(|a| AuthorityName::from(a) == self.name)
931 }
932
933 pub fn is_fullnode(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
934 !self.is_committee_validator(epoch_store)
935 }
936
937 pub fn committee_store(&self) -> &Arc<CommitteeStore> {
938 &self.committee_store
939 }
940
941 pub fn clone_committee_store(&self) -> Arc<CommitteeStore> {
942 self.committee_store.clone()
943 }
944
945 pub fn overload_config(&self) -> &AuthorityOverloadConfig {
946 &self.config.authority_overload_config
947 }
948
949 pub fn get_epoch_state_commitments(
950 &self,
951 epoch: EpochId,
952 ) -> IotaResult<Option<Vec<CheckpointCommitment>>> {
953 self.checkpoint_store.get_epoch_state_commitments(epoch)
954 }
955
956 #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
989 pub(crate) async fn handle_transaction_validation_checks(
990 &self,
991 transaction: &VerifiedTransaction,
992 epoch_store: &Arc<AuthorityPerEpochStore>,
993 deny_config: &dyn DenyRuleConfig,
994 epoch_gated_coin_deny_list: bool,
995 ) -> IotaResult<Vec<ObjectReference>> {
996 let protocol_config = epoch_store.protocol_config();
997 let reference_gas_price = epoch_store.reference_gas_price();
998
999 let epoch = epoch_store.epoch();
1000
1001 let tx = transaction.data().transaction();
1002
1003 iota_transaction_checks::deny::check_transaction_for_validation(
1007 tx,
1008 transaction.signatures(),
1009 &transaction.input_objects()?,
1010 &tx.receiving_objects(),
1011 deny_config,
1012 self.get_backing_package_store().as_ref(),
1013 )?;
1014
1015 let (tx_input_objects, tx_receiving_objects, per_authenticator_inputs) =
1020 self.read_objects_for_validation(transaction, epoch)?;
1021
1022 let move_authenticators = transaction.move_authenticators();
1023
1024 let (gas_status, tx_checked_input_objects, per_authenticator_checked_inputs) = self
1030 .check_transaction_inputs_for_validation(
1031 protocol_config,
1032 reference_gas_price,
1033 tx,
1034 tx_input_objects,
1035 &tx_receiving_objects,
1036 &move_authenticators,
1037 per_authenticator_inputs,
1038 )?;
1039
1040 let per_authenticator_checked_input_objects = per_authenticator_checked_inputs
1043 .iter()
1044 .map(|i| &i.0)
1045 .collect();
1046
1047 check_coin_deny_list_v1(
1051 tx.sender(),
1052 &tx_checked_input_objects,
1053 &tx_receiving_objects,
1054 &per_authenticator_checked_input_objects,
1055 &self.get_object_store(),
1056 epoch_gated_coin_deny_list.then_some(epoch),
1057 )?;
1058
1059 let (kind, signer, gas_data) = tx.execution_parts();
1060
1061 let (sender_authenticator_function_ref, sponsor_authenticator_function_ref) =
1062 extract_auth_fun_refs(signer, gas_data.owner, |address| {
1063 move_authenticators
1064 .iter()
1065 .zip(per_authenticator_checked_inputs.iter())
1066 .find(|(move_authenticator, _)| move_authenticator.address() == address)
1067 .map(|(_, (_, auth_fun_ref))| auth_fun_ref.clone())
1068 });
1069
1070 let pre_consensus_move_authenticators =
1075 pre_consensus_move_authenticators(transaction, protocol_config);
1076 let (move_authenticators, per_authenticator_checked_inputs): (Vec<_>, Vec<_>) =
1077 move_authenticators
1078 .into_iter()
1079 .zip(per_authenticator_checked_inputs)
1080 .filter(|(a, _)| pre_consensus_move_authenticators.contains(a))
1081 .unzip();
1082 let per_authenticator_checked_input_objects: Vec<_> = per_authenticator_checked_inputs
1083 .iter()
1084 .map(|i| &i.0)
1085 .collect();
1086
1087 if !move_authenticators.is_empty() {
1090 let aggregated_authenticator_input_objects =
1091 iota_transaction_checks::aggregate_authenticator_input_objects(
1092 &per_authenticator_checked_input_objects,
1093 )?;
1094
1095 debug_assert_eq!(
1096 move_authenticators.len(),
1097 per_authenticator_checked_inputs.len(),
1098 "Move authenticators amount must match the number of checked authenticator inputs"
1099 );
1100
1101 let move_authenticators = move_authenticators
1102 .into_iter()
1103 .zip(per_authenticator_checked_inputs)
1104 .map(
1105 |(
1106 move_authenticator,
1107 (authenticator_checked_input_objects, authenticator_function_ref),
1108 )| {
1109 (
1110 move_authenticator.to_owned(),
1111 authenticator_function_ref,
1112 authenticator_checked_input_objects,
1113 )
1114 },
1115 )
1116 .collect();
1117
1118 let tx_data_bytes =
1123 bcs::to_bytes(tx).expect("TransactionData serialization cannot fail");
1124
1125 let (sender_auth_digest, sponsor_auth_digest) =
1126 transaction.data().compute_auth_digests()?;
1127
1128 let auth_context_data = AuthContextData {
1129 transaction_data_bytes: tx_data_bytes,
1130 sender_auth_digest,
1131 sponsor_auth_digest,
1132 sender_authenticator_function_ref,
1133 sponsor_authenticator_function_ref,
1134 };
1135
1136 let validation_result = epoch_store.executor().authenticate_transaction(
1138 self.get_backing_store().as_ref(),
1139 protocol_config,
1140 self.metrics.limits_metrics.clone(),
1141 &epoch_store.epoch_start_config().epoch_data().epoch_id(),
1142 epoch_store
1143 .epoch_start_config()
1144 .epoch_data()
1145 .epoch_start_timestamp(),
1146 gas_data,
1147 gas_status,
1148 move_authenticators,
1149 aggregated_authenticator_input_objects,
1150 kind,
1151 signer,
1152 transaction.digest().to_owned(),
1153 auth_context_data,
1154 &mut None,
1155 );
1156
1157 if let Err(validation_error) = validation_result {
1158 return Err(IotaError::MoveAuthenticatorExecutionFailure {
1159 error: validation_error.to_string(),
1160 });
1161 }
1162 }
1163
1164 Ok(tx_checked_input_objects.inner().filter_owned_objects())
1165 }
1166
1167 async fn handle_transaction_impl(
1171 &self,
1172 transaction: VerifiedTransaction,
1173 epoch_store: &Arc<AuthorityPerEpochStore>,
1174 ) -> IotaResult<VerifiedSignedTransaction> {
1175 let _execution_lock = self.execution_lock_for_signing()?;
1177
1178 let owned_objects = self
1179 .handle_transaction_validation_checks(
1180 &transaction,
1181 epoch_store,
1182 &self.config.transaction_deny_config,
1183 false,
1188 )
1189 .await?;
1190
1191 let epoch = epoch_store.epoch();
1192 let signed_transaction =
1193 VerifiedSignedTransaction::new(epoch, transaction, self.name, &*self.secret);
1194
1195 self.get_cache_writer().try_acquire_transaction_locks(
1200 epoch_store,
1201 &owned_objects,
1202 signed_transaction.clone(),
1203 )?;
1204
1205 Ok(signed_transaction)
1206 }
1207
1208 #[instrument(name = "handle_transaction", level = "trace", skip_all, fields(tx_digest = ?transaction.digest(), sender = transaction.data().transaction().gas_owner().to_string()
1210 ))]
1211 pub async fn handle_transaction(
1212 &self,
1213 epoch_store: &Arc<AuthorityPerEpochStore>,
1214 transaction: VerifiedTransaction,
1215 ) -> IotaResult<HandleTransactionResponse> {
1216 let tx_digest = *transaction.digest();
1217 debug!("handle_transaction");
1218
1219 if let Some((_, status)) = self.get_transaction_status(&tx_digest, epoch_store)? {
1221 return Ok(HandleTransactionResponse { status });
1222 }
1223
1224 let _metrics_guard = self
1225 .metrics
1226 .authority_state_handle_transaction_latency
1227 .start_timer();
1228 self.metrics.tx_orders.inc();
1229
1230 let signed = self.handle_transaction_impl(transaction, epoch_store).await;
1231 match signed {
1232 Ok(s) => {
1233 if self.is_committee_validator(epoch_store) {
1234 if let Some(validator_tx_finalizer) = &self.validator_tx_finalizer {
1235 let tx = s.clone();
1236 let validator_tx_finalizer = validator_tx_finalizer.clone();
1237 let cache_reader = self.get_transaction_cache_reader().clone();
1238 let epoch_store = epoch_store.clone();
1239 spawn_monitored_task!(epoch_store.within_alive_epoch(
1240 validator_tx_finalizer.track_signed_tx(cache_reader, &epoch_store, tx)
1241 ));
1242 }
1243 }
1244 Ok(HandleTransactionResponse {
1245 status: TransactionStatus::Signed(s.into_inner().into_sig()),
1246 })
1247 }
1248 Err(err) => Ok(HandleTransactionResponse {
1252 status: self
1253 .get_transaction_status(&tx_digest, epoch_store)?
1254 .ok_or(err)?
1255 .1,
1256 }),
1257 }
1258 }
1259
1260 pub fn check_system_overload_at_signing(&self) -> bool {
1261 self.config
1262 .authority_overload_config
1263 .check_system_overload_at_signing
1264 }
1265
1266 pub fn check_system_overload_at_execution(&self) -> bool {
1267 self.config
1268 .authority_overload_config
1269 .check_system_overload_at_execution
1270 }
1271
1272 pub(crate) fn check_system_overload(
1282 &self,
1283 consensus_adapter: &Arc<ConsensusAdapter>,
1284 tx_data: &SenderSignedData,
1285 do_authority_overload_check: bool,
1286 pcool_flow_enabled: bool,
1287 ) -> IotaResult {
1288 if pcool_flow_enabled {
1289 self.check_consensus_queue_graduated_limits(consensus_adapter, tx_data)
1292 .tap_err(|_| {
1293 self.update_overload_metrics("consensus");
1294 })?;
1295
1296 consensus_adapter.check_consensus_overload().tap_err(|_| {
1303 self.update_overload_metrics("consensus");
1304 })?;
1305 } else {
1306 if do_authority_overload_check {
1307 self.check_authority_overload(tx_data).tap_err(|_| {
1308 self.update_overload_metrics("execution_queue");
1309 })?;
1310 }
1311 self.transaction_manager
1312 .check_execution_overload(self.overload_config(), tx_data)
1313 .tap_err(|_| {
1314 self.update_overload_metrics("execution_pending");
1315 })?;
1316 consensus_adapter.check_consensus_overload().tap_err(|_| {
1317 self.update_overload_metrics("consensus");
1318 })?;
1319
1320 let pending_tx_count = self
1321 .get_cache_commit()
1322 .approximate_pending_transaction_count();
1323 if pending_tx_count
1324 > self
1325 .config
1326 .execution_cache_config
1327 .writeback_cache
1328 .backpressure_threshold_for_rpc()
1329 {
1330 return Err(IotaError::ValidatorOverloadedRetryAfter {
1331 retry_after_secs: 10,
1332 });
1333 }
1334 }
1335
1336 Ok(())
1337 }
1338
1339 fn check_consensus_queue_graduated_limits(
1347 &self,
1348 consensus_adapter: &Arc<ConsensusAdapter>,
1349 tx_data: &SenderSignedData,
1350 ) -> IotaResult {
1351 let num_inflight_txs = consensus_adapter.num_inflight_transactions() as usize;
1352
1353 let shedding_pct = compute_graduated_load_shedding_percentage(
1354 num_inflight_txs,
1355 consensus_adapter.max_pending_transactions(),
1356 consensus_adapter.graduated_load_shedding_soft_limit_pct(),
1357 );
1358
1359 self.metrics
1360 .consensus_queue_load_shedding_percentage
1361 .set(shedding_pct as i64);
1362
1363 if shedding_pct == 0 {
1364 return Ok(());
1365 }
1366
1367 if shedding_pct >= 100 {
1372 return Err(IotaError::TooManyTransactionsPendingConsensus);
1373 }
1374
1375 overload_monitor_accept_tx(shedding_pct, tx_data.digest())
1376 }
1377
1378 fn check_authority_overload(&self, tx_data: &SenderSignedData) -> IotaResult {
1379 if !self.overload_info.is_overload.load(Ordering::Relaxed) {
1380 return Ok(());
1381 }
1382
1383 let load_shedding_percentage = self
1384 .overload_info
1385 .local_load_shedding_percentage
1386 .load(Ordering::Relaxed);
1387 overload_monitor_accept_tx(load_shedding_percentage, tx_data.digest())
1388 }
1389
1390 fn update_overload_metrics(&self, source: &str) {
1391 self.metrics
1392 .transaction_overload_sources
1393 .with_label_values(&[source])
1394 .inc();
1395 }
1396
1397 #[instrument(level = "trace", skip_all)]
1402 pub async fn wait_for_certificate_execution(
1403 &self,
1404 certificate: &VerifiedCertificate,
1405 epoch_store: &Arc<AuthorityPerEpochStore>,
1406 ) -> IotaResult<TransactionEffects> {
1407 let _metrics_guard = if certificate.contains_shared_object() {
1408 self.metrics
1409 .execute_certificate_latency_shared_object
1410 .start_timer()
1411 } else {
1412 self.metrics
1413 .execute_certificate_latency_single_writer
1414 .start_timer()
1415 };
1416 trace!("wait_for_certificate_execution");
1417
1418 self.metrics.total_cert_attempts.inc();
1419
1420 if !certificate.contains_shared_object() {
1421 self.enqueue_certificates_for_execution(vec![certificate.clone()], epoch_store);
1426 }
1427
1428 epoch_store
1431 .within_alive_epoch(self.notify_read_effects(certificate))
1432 .await
1433 .map_err(|_| IotaError::EpochEnded(epoch_store.epoch()))
1434 .and_then(|r| r)
1435 }
1436
1437 #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
1452 pub fn try_execute_immediately(
1453 &self,
1454 transaction: &VerifiedExecutableTransaction,
1455 expected_effects_digest: Option<TransactionEffectsDigest>,
1456 epoch_store: &Arc<AuthorityPerEpochStore>,
1457 ) -> IotaResult<(TransactionEffects, Option<ExecutionError>)> {
1458 let _scope = monitored_scope("Execution::try_execute_immediately");
1459 let _metrics_guard = self.metrics.internal_execution_latency.start_timer();
1460
1461 let tx_digest = transaction.digest();
1462
1463 let tx_guard = epoch_store.acquire_tx_guard(transaction)?;
1465
1466 if let Some(effects) = self
1469 .get_transaction_cache_reader()
1470 .try_get_executed_effects(tx_digest)?
1471 {
1472 if let Some(expected_effects_digest_inner) = expected_effects_digest {
1473 assert_eq!(
1474 effects.digest(),
1475 expected_effects_digest_inner,
1476 "Unexpected effects digest for transaction {tx_digest}"
1477 );
1478 }
1479 tx_guard.release();
1480 return Ok((effects, None));
1481 }
1482
1483 let (tx_input_objects, per_authenticator_inputs) =
1484 self.read_objects_for_execution(tx_guard.as_lock_guard(), transaction, epoch_store)?;
1485
1486 let expected_effects_digest =
1492 expected_effects_digest.or(epoch_store.get_signed_effects_digest(tx_digest)?);
1493
1494 self.process_transaction(
1495 tx_guard,
1496 transaction,
1497 tx_input_objects,
1498 per_authenticator_inputs,
1499 expected_effects_digest,
1500 epoch_store,
1501 )
1502 .tap_err(|e| info!(?tx_digest, "process_transaction failed: {e}"))
1503 .tap_ok(
1504 |(fx, _)| debug!(?tx_digest, fx_digest=?fx.digest(), "process_transaction succeeded"),
1505 )
1506 }
1507
1508 pub fn read_objects_for_execution(
1509 &self,
1510 tx_lock: &TxLockGuard,
1511 transaction: &VerifiedExecutableTransaction,
1512 epoch_store: &Arc<AuthorityPerEpochStore>,
1513 ) -> IotaResult<(InputObjects, Vec<(InputObjects, ObjectReadResult)>)> {
1514 let _scope = monitored_scope("Execution::load_input_objects");
1515 let _metrics_guard = self
1516 .metrics
1517 .execution_load_input_objects_latency
1518 .start_timer();
1519
1520 let input_objects = transaction.collect_all_input_object_kind_for_reading()?;
1521
1522 let input_objects = self.input_loader.read_objects_for_execution(
1523 epoch_store,
1524 &transaction.key(),
1525 tx_lock,
1526 &input_objects,
1527 epoch_store.epoch(),
1528 )?;
1529
1530 transaction.split_input_objects_into_groups_for_reading(input_objects)
1531 }
1532
1533 pub fn try_execute_for_test(
1537 &self,
1538 certificate: &VerifiedCertificate,
1539 ) -> IotaResult<(VerifiedSignedTransactionEffects, Option<ExecutionError>)> {
1540 let epoch_store = self.epoch_store_for_testing();
1541 let (effects, execution_error_opt) = self.try_execute_immediately(
1542 &VerifiedExecutableTransaction::new_from_certificate(certificate.clone()),
1543 None,
1544 &epoch_store,
1545 )?;
1546 let signed_effects = self.sign_effects(effects, &epoch_store)?;
1547 Ok((signed_effects, execution_error_opt))
1548 }
1549
1550 pub fn execute_for_test(
1552 &self,
1553 certificate: &VerifiedCertificate,
1554 ) -> (VerifiedSignedTransactionEffects, Option<ExecutionError>) {
1555 self.try_execute_for_test(certificate)
1556 .expect("try_execute_for_test should not fail")
1557 }
1558
1559 pub async fn notify_read_effects(
1560 &self,
1561 certificate: &VerifiedCertificate,
1562 ) -> IotaResult<TransactionEffects> {
1563 self.get_transaction_cache_reader()
1564 .try_notify_read_executed_effects(&[*certificate.digest()])
1565 .await
1566 .map(|mut r| r.pop().expect("must return correct number of effects"))
1567 }
1568
1569 fn check_owned_locks(&self, owned_object_refs: &[ObjectReference]) -> IotaResult {
1570 self.get_object_cache_reader()
1571 .try_check_owned_objects_are_live(owned_object_refs)
1572 }
1573
1574 pub(crate) fn debug_dump_transaction_state(
1579 &self,
1580 tx_digest: &TransactionDigest,
1581 effects: &TransactionEffects,
1582 expected_effects_digest: TransactionEffectsDigest,
1583 inner_temporary_store: &InnerTemporaryStore,
1584 transaction: &VerifiedExecutableTransaction,
1585 debug_dump_config: &StateDebugDumpConfig,
1586 ) -> IotaResult<PathBuf> {
1587 let dump_dir = debug_dump_config
1590 .dump_file_directory
1591 .as_ref()
1592 .cloned()
1593 .unwrap_or(std::env::temp_dir());
1594 let epoch_store = self.load_epoch_store_one_call_per_task();
1595
1596 NodeStateDump::new(
1597 tx_digest,
1598 effects,
1599 expected_effects_digest,
1600 self.get_object_store().as_ref(),
1601 &epoch_store,
1602 inner_temporary_store,
1603 transaction,
1604 )?
1605 .write_to_file(&dump_dir)
1606 .map_err(|e| IotaError::FileIO(e.to_string()))
1607 }
1608
1609 #[instrument(name = "process_certificate", level = "trace", skip_all, fields(tx_digest = ?transaction.digest(), sender = ?transaction.data().transaction().gas_owner().to_string()))]
1610 pub(crate) fn process_transaction(
1611 &self,
1612 tx_guard: TxGuard,
1613 transaction: &VerifiedExecutableTransaction,
1614 tx_input_objects: InputObjects,
1615 per_authenticator_inputs: Vec<(InputObjects, ObjectReadResult)>,
1616 expected_effects_digest: Option<TransactionEffectsDigest>,
1617 epoch_store: &Arc<AuthorityPerEpochStore>,
1618 ) -> IotaResult<(TransactionEffects, Option<ExecutionError>)> {
1619 let process_transaction_start_time = tokio::time::Instant::now();
1620 let digest = *transaction.digest();
1621
1622 let _scope = monitored_scope("Execution::process_certificate");
1623
1624 fail_point_if!("correlated-crash-process-transaction", || {
1625 if iota_simulator::random::deterministic_probability_once(digest, 0.01) {
1626 iota_simulator::task::kill_current_node(None);
1627 }
1628 });
1629
1630 let execution_guard = self.execution_lock_for_executable_transaction(transaction);
1631 let execution_guard = match execution_guard {
1637 Ok(execution_guard) => execution_guard,
1638 Err(err) => {
1639 tx_guard.release();
1640 return Err(err);
1641 }
1642 };
1643 if *execution_guard != epoch_store.epoch() {
1647 tx_guard.release();
1648 info!("The epoch of the execution_guard doesn't match the epoch store");
1649 return Err(IotaError::WrongEpoch {
1650 expected_epoch: epoch_store.epoch(),
1651 actual_epoch: *execution_guard,
1652 });
1653 }
1654
1655 let (inner_temporary_store, effects, execution_error_opt) = match self.execute_transaction(
1661 &execution_guard,
1662 transaction,
1663 tx_input_objects,
1664 per_authenticator_inputs,
1665 epoch_store,
1666 ) {
1667 Err(e) => {
1668 info!(name = ?self.name, ?digest, "Error preparing transaction: {e}");
1669 tx_guard.release();
1670 return Err(e);
1671 }
1672 Ok(res) => res,
1673 };
1674
1675 if let Some(expected_effects_digest) = expected_effects_digest {
1676 if effects.digest() != expected_effects_digest {
1677 match self.debug_dump_transaction_state(
1679 &digest,
1680 &effects,
1681 expected_effects_digest,
1682 &inner_temporary_store,
1683 transaction,
1684 &self.config.state_debug_dump_config,
1685 ) {
1686 Ok(out_path) => {
1687 info!(
1688 "Dumped node state for transaction {} to {}",
1689 digest,
1690 out_path.as_path().display().to_string()
1691 );
1692 }
1693 Err(e) => {
1694 error!("Error dumping state for transaction {}: {e}", digest);
1695 }
1696 }
1697 error!(
1698 tx_digest = ?digest,
1699 ?expected_effects_digest,
1700 actual_effects = ?effects,
1701 "fork detected!"
1702 );
1703 panic!(
1704 "Transaction {} is expected to have effects digest {}, but got {}!",
1705 digest,
1706 expected_effects_digest,
1707 effects.digest(),
1708 );
1709 }
1710 }
1711
1712 fail_point!("crash");
1713
1714 self.commit_transaction(
1715 transaction,
1716 inner_temporary_store,
1717 &effects,
1718 tx_guard,
1719 execution_guard,
1720 epoch_store,
1721 )?;
1722
1723 let elapsed = process_transaction_start_time.elapsed().as_micros() as f64;
1724 if elapsed > 0.0 {
1725 self.metrics
1726 .execution_gas_latency_ratio
1727 .observe(effects.gas_cost_summary().computation_cost as f64 / elapsed);
1728 };
1729 Ok((effects, execution_error_opt))
1730 }
1731
1732 pub async fn reconfigure_traffic_control(
1733 &self,
1734 params: TrafficControlReconfigParams,
1735 ) -> Result<TrafficControlReconfigParams, IotaError> {
1736 if let Some(traffic_controller) = self.traffic_controller.as_ref() {
1737 traffic_controller.admin_reconfigure(params).await
1738 } else {
1739 Err(IotaError::InvalidAdminRequest(
1740 "Traffic controller is not configured on this node".to_string(),
1741 ))
1742 }
1743 }
1744
1745 #[instrument(level = "trace", skip_all)]
1746 fn commit_transaction(
1747 &self,
1748 transaction: &VerifiedExecutableTransaction,
1749 inner_temporary_store: InnerTemporaryStore,
1750 effects: &TransactionEffects,
1751 tx_guard: TxGuard,
1752 _execution_guard: ExecutionLockReadGuard<'_>,
1753 epoch_store: &Arc<AuthorityPerEpochStore>,
1754 ) -> IotaResult {
1755 let _scope: Option<iota_metrics::MonitoredScopeGuard> =
1756 monitored_scope("Execution::commit_certificate");
1757 let _metrics_guard = self.metrics.commit_certificate_latency.start_timer();
1758
1759 let tx_key = transaction.key();
1760 let tx_digest = transaction.digest();
1761 let input_object_count = inner_temporary_store.input_objects.len();
1762 let shared_object_count = effects.input_shared_objects().len();
1763
1764 let output_keys = inner_temporary_store.get_output_keys(effects);
1765
1766 let _ = self
1768 .post_process_one_tx(transaction, effects, &inner_temporary_store, epoch_store)
1769 .tap_err(|e| {
1770 self.metrics.post_processing_total_failures.inc();
1771 error!(?tx_digest, "tx post processing failed: {e}");
1772 });
1773
1774 epoch_store.insert_tx_key_and_digest(&tx_key, tx_digest)?;
1778
1779 fail_point!("crash");
1781
1782 let transaction_outputs = TransactionOutputs::build_transaction_outputs(
1783 transaction.clone().into_unsigned(),
1784 effects.clone(),
1785 inner_temporary_store,
1786 );
1787 self.get_cache_writer()
1788 .try_write_transaction_outputs(epoch_store.epoch(), transaction_outputs.into())?;
1789
1790 if transaction.transaction().is_end_of_epoch_tx() {
1791 self.get_object_cache_reader()
1794 .force_reload_system_packages(&BuiltInFramework::all_package_ids());
1795 }
1796
1797 tx_guard.commit_tx();
1799
1800 self.transaction_manager
1804 .notify_commit(tx_digest, output_keys, epoch_store);
1805
1806 self.update_metrics(transaction, input_object_count, shared_object_count);
1807
1808 Ok(())
1809 }
1810
1811 fn update_metrics(
1812 &self,
1813 transaction: &VerifiedExecutableTransaction,
1814 input_object_count: usize,
1815 shared_object_count: usize,
1816 ) {
1817 if transaction.has_multisig() {
1819 self.metrics.multisig_sig_count.inc();
1820 }
1821
1822 self.metrics.total_effects.inc();
1823 self.metrics.total_certs.inc();
1824
1825 if shared_object_count > 0 {
1826 self.metrics.shared_obj_tx.inc();
1827 }
1828
1829 if transaction.is_sponsored_tx() {
1830 self.metrics.sponsored_tx.inc();
1831 }
1832
1833 self.metrics
1834 .num_input_objs
1835 .observe(input_object_count as f64);
1836 self.metrics
1837 .num_shared_objects
1838 .observe(shared_object_count as f64);
1839 self.metrics
1840 .batch_size
1841 .observe(transaction.data().transaction().kind().num_commands() as f64);
1842 }
1843
1844 #[instrument(level = "trace", skip_all)]
1856 fn execute_transaction(
1857 &self,
1858 _execution_guard: &ExecutionLockReadGuard<'_>,
1859 transaction: &VerifiedExecutableTransaction,
1860 tx_input_objects: InputObjects,
1861 per_authenticator_inputs: Vec<(InputObjects, ObjectReadResult)>,
1862 epoch_store: &Arc<AuthorityPerEpochStore>,
1863 ) -> IotaResult<(
1864 InnerTemporaryStore,
1865 TransactionEffects,
1866 Option<ExecutionError>,
1867 )> {
1868 let _scope = monitored_scope("Execution::execute_certificate");
1869 let _metrics_guard = self.metrics.prepare_certificate_latency.start_timer();
1870 let prepare_transaction_start_time = tokio::time::Instant::now();
1871
1872 let protocol_config = epoch_store.protocol_config();
1873
1874 let reference_gas_price = epoch_store.reference_gas_price();
1875
1876 let epoch_id = epoch_store.epoch_start_config().epoch_data().epoch_id();
1877 let epoch_start_timestamp = epoch_store
1878 .epoch_start_config()
1879 .epoch_data()
1880 .epoch_start_timestamp();
1881
1882 let backing_store = self.get_backing_store().as_ref();
1883
1884 let tx_digest = *transaction.digest();
1885
1886 let tx = transaction.data().transaction();
1889 tx.validity_check(protocol_config)?;
1890
1891 let (kind, signer, gas_data) = tx.execution_parts();
1892
1893 let move_authenticators = transaction.move_authenticators();
1894
1895 #[cfg_attr(not(any(msim, fail_points)), expect(unused_mut))]
1896 let (inner_temp_store, _, mut effects, execution_error_opt) = if move_authenticators
1897 .is_empty()
1898 {
1899 let (tx_gas_status, tx_checked_input_objects) =
1904 iota_transaction_checks::check_certificate_input(
1905 transaction,
1906 tx_input_objects,
1907 protocol_config,
1908 reference_gas_price,
1909 )?;
1910
1911 let owned_object_refs = tx_checked_input_objects.inner().filter_owned_objects();
1912 self.check_owned_locks(&owned_object_refs)?;
1913 epoch_store.executor().execute_transaction_to_effects(
1914 backing_store,
1915 protocol_config,
1916 self.metrics.limits_metrics.clone(),
1917 self.config
1920 .expensive_safety_check_config
1921 .enable_deep_per_tx_iota_conservation_check(),
1922 self.config.certificate_deny_config.certificate_deny_set(),
1923 &epoch_id,
1924 epoch_start_timestamp,
1925 tx_checked_input_objects,
1926 gas_data,
1927 tx_gas_status,
1928 kind,
1929 signer,
1930 tx_digest,
1931 &mut None,
1932 )
1933 } else {
1934 debug_assert_eq!(
1940 move_authenticators.len(),
1941 per_authenticator_inputs.len(),
1942 "Move authenticators amount must match the number of authenticator inputs"
1943 );
1944
1945 let per_authenticator_inputs = move_authenticators
1946 .iter()
1947 .zip(per_authenticator_inputs)
1948 .map(
1949 |(move_authenticator, (authenticator_input_objects, account_object))| {
1950 let (
1953 auth_account_object_id,
1954 auth_account_object_seq_number,
1955 auth_account_object_digest,
1956 ) = move_authenticator
1957 .object_to_authenticate_components()
1958 .expect("the object to authenticate is validated before consensus and cannot be invalid during execution");
1959
1960 let signer = move_authenticator.address();
1961
1962 let authenticator_function_ref_for_execution = self
1963 .check_move_account_for_execution(
1964 auth_account_object_id,
1965 auth_account_object_seq_number,
1966 auth_account_object_digest,
1967 account_object,
1968 &signer,
1969 );
1970
1971 (
1972 authenticator_input_objects,
1973 authenticator_function_ref_for_execution,
1974 )
1975 },
1976 )
1977 .collect::<Vec<_>>();
1978
1979 let per_authenticator_input_objects = per_authenticator_inputs
1980 .iter()
1981 .map(|(authenticator_input_objects, _)| authenticator_input_objects.clone())
1982 .collect::<Vec<_>>();
1983
1984 let tx_data_bytes =
1986 bcs::to_bytes(tx).expect("TransactionData serialization cannot fail");
1987
1988 let (sender_auth_digest, sponsor_auth_digest) =
1989 transaction.data().compute_auth_digests()?;
1990
1991 let authenticator_gas_budget = protocol_config.max_auth_gas();
1996 let (
1997 gas_status,
1998 per_authenticator_checked_input_objects,
1999 authenticator_and_tx_checked_input_objects,
2000 ) = iota_transaction_checks::check_certificate_and_move_authenticator_input(
2001 transaction,
2002 tx_input_objects,
2003 per_authenticator_input_objects,
2004 authenticator_gas_budget,
2005 protocol_config,
2006 reference_gas_price,
2007 )?;
2008
2009 debug_assert_eq!(
2010 move_authenticators.len(),
2011 per_authenticator_checked_input_objects.len(),
2012 "Move authenticators amount must match the number of checked authenticator inputs"
2013 );
2014
2015 let move_authenticators = move_authenticators
2016 .into_iter()
2017 .zip(per_authenticator_inputs)
2018 .zip(per_authenticator_checked_input_objects)
2019 .map(
2020 |(
2021 (move_authenticator, (_, authenticator_function_ref_for_execution)),
2022 authenticator_checked_input_objects,
2023 )| {
2024 (
2025 move_authenticator.to_owned(),
2026 authenticator_function_ref_for_execution,
2027 authenticator_checked_input_objects,
2028 )
2029 },
2030 )
2031 .collect::<Vec<_>>();
2032
2033 let owned_object_refs = authenticator_and_tx_checked_input_objects
2034 .inner()
2035 .filter_owned_objects();
2036 self.check_owned_locks(&owned_object_refs)?;
2037
2038 let (sender_authenticator_function_ref, sponsor_authenticator_function_ref) =
2039 extract_auth_fun_refs(signer, gas_data.owner, |address| {
2040 move_authenticators
2041 .iter()
2042 .find(|t| t.0.address() == address)
2043 .map(|t| t.1.authenticator_function_ref.clone())
2044 });
2045
2046 let auth_context_data = AuthContextData {
2047 transaction_data_bytes: tx_data_bytes,
2048 sender_auth_digest,
2049 sponsor_auth_digest,
2050 sender_authenticator_function_ref,
2051 sponsor_authenticator_function_ref,
2052 };
2053
2054 epoch_store
2055 .executor()
2056 .authenticate_then_execute_transaction_to_effects(
2057 backing_store,
2058 protocol_config,
2059 self.metrics.limits_metrics.clone(),
2060 self.config
2061 .expensive_safety_check_config
2062 .enable_deep_per_tx_iota_conservation_check(),
2063 self.config.certificate_deny_config.certificate_deny_set(),
2064 &epoch_id,
2065 epoch_start_timestamp,
2066 gas_data,
2067 gas_status,
2068 move_authenticators,
2069 authenticator_and_tx_checked_input_objects,
2070 kind,
2071 signer,
2072 tx_digest,
2073 auth_context_data,
2074 &mut None,
2075 )
2076 };
2077
2078 fail_point_if!("cp_execution_nondeterminism", || {
2079 #[cfg(msim)]
2080 self.create_fail_state(transaction, epoch_store, &mut effects);
2081 });
2082
2083 let elapsed = prepare_transaction_start_time.elapsed().as_micros() as f64;
2084 if elapsed > 0.0 {
2085 self.metrics
2086 .prepare_cert_gas_latency_ratio
2087 .observe(effects.gas_cost_summary().computation_cost as f64 / elapsed);
2088 }
2089
2090 Ok((inner_temp_store, effects, execution_error_opt.err()))
2091 }
2092
2093 pub fn prepare_transaction_for_benchmark(
2094 &self,
2095 transaction: &VerifiedExecutableTransaction,
2096 input_objects: InputObjects,
2097 epoch_store: &Arc<AuthorityPerEpochStore>,
2098 ) -> IotaResult<(
2099 InnerTemporaryStore,
2100 TransactionEffects,
2101 Option<ExecutionError>,
2102 )> {
2103 let lock = RwLock::new(epoch_store.epoch());
2104 let execution_guard = lock.try_read().unwrap();
2105
2106 self.execute_transaction(
2107 &execution_guard,
2108 transaction,
2109 input_objects,
2110 vec![],
2111 epoch_store,
2112 )
2113 }
2114
2115 #[instrument("dry_exec_tx", level = "trace", skip_all)]
2118 #[allow(clippy::type_complexity)]
2119 pub fn dry_exec_transaction(
2120 &self,
2121 transaction: TransactionData,
2122 transaction_digest: TransactionDigest,
2123 ) -> IotaResult<(
2124 DryRunTransactionBlockResponse,
2125 BTreeMap<ObjectId, (ObjectReference, Object, WriteKind)>,
2126 TransactionEffects,
2127 Option<ObjectId>,
2128 )> {
2129 let epoch_store = self.load_epoch_store_one_call_per_task();
2130 if !self.is_fullnode(&epoch_store) {
2131 return Err(IotaError::UnsupportedFeature {
2132 error: "dry-exec is only supported on fullnodes".to_string(),
2133 });
2134 }
2135
2136 if transaction.kind().is_system() {
2137 return Err(IotaError::UnsupportedFeature {
2138 error: "dry-exec does not support system transactions".to_string(),
2139 });
2140 }
2141
2142 self.dry_exec_transaction_impl(&epoch_store, transaction, transaction_digest)
2143 }
2144
2145 #[allow(clippy::type_complexity)]
2146 pub fn dry_exec_transaction_for_benchmark(
2147 &self,
2148 transaction: TransactionData,
2149 transaction_digest: TransactionDigest,
2150 ) -> IotaResult<(
2151 DryRunTransactionBlockResponse,
2152 BTreeMap<ObjectId, (ObjectReference, Object, WriteKind)>,
2153 TransactionEffects,
2154 Option<ObjectId>,
2155 )> {
2156 let epoch_store = self.load_epoch_store_one_call_per_task();
2157 self.dry_exec_transaction_impl(&epoch_store, transaction, transaction_digest)
2158 }
2159
2160 #[instrument(level = "trace", skip_all)]
2161 #[allow(clippy::type_complexity)]
2162 fn dry_exec_transaction_impl(
2163 &self,
2164 epoch_store: &AuthorityPerEpochStore,
2165 transaction: TransactionData,
2166 transaction_digest: TransactionDigest,
2167 ) -> IotaResult<(
2168 DryRunTransactionBlockResponse,
2169 BTreeMap<ObjectId, (ObjectReference, Object, WriteKind)>,
2170 TransactionEffects,
2171 Option<ObjectId>,
2172 )> {
2173 transaction.validity_check_no_gas_check(epoch_store.protocol_config())?;
2175
2176 let input_object_kinds = transaction.input_objects()?;
2177 let receiving_object_refs = transaction.receiving_objects();
2178
2179 iota_transaction_checks::deny::check_transaction_for_validation(
2180 &transaction,
2181 &[],
2182 &input_object_kinds,
2183 &receiving_object_refs,
2184 &self.config.transaction_deny_config,
2185 self.get_backing_package_store().as_ref(),
2186 )?;
2187
2188 let (input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
2189 None,
2191 &input_object_kinds,
2192 &receiving_object_refs,
2193 epoch_store.epoch(),
2194 )?;
2195
2196 let mut transaction = transaction;
2198 let reference_gas_price = epoch_store.reference_gas_price();
2199 let ((gas_status, checked_input_objects), mock_gas) = if transaction.gas().is_empty() {
2200 let sender = transaction.gas_owner();
2201 let gas_object_id = ObjectId::random();
2202 let gas_object = Object::new_move(
2203 MoveStruct::new_gas_coin(
2204 OBJECT_START_VERSION,
2205 gas_object_id,
2206 SIMULATION_GAS_COIN_VALUE,
2207 ),
2208 Owner::Address(sender),
2209 TransactionDigest::GENESIS_MARKER,
2210 );
2211 let gas_object_ref = gas_object.object_ref();
2212 transaction.gas_data_mut().objects = vec![gas_object_ref];
2214 (
2215 iota_transaction_checks::check_transaction_input_with_given_gas(
2216 epoch_store.protocol_config(),
2217 reference_gas_price,
2218 &transaction,
2219 input_objects,
2220 receiving_objects,
2221 gas_object,
2222 &self.metrics.bytecode_verifier_metrics,
2223 &self.config.verifier_signing_config,
2224 )?,
2225 Some(gas_object_id),
2226 )
2227 } else {
2228 let authenticator_gas_budget = 0;
2231
2232 (
2233 iota_transaction_checks::check_transaction_input(
2234 epoch_store.protocol_config(),
2235 reference_gas_price,
2236 &transaction,
2237 input_objects,
2238 &receiving_objects,
2239 &self.metrics.bytecode_verifier_metrics,
2240 &self.config.verifier_signing_config,
2241 authenticator_gas_budget,
2242 )?,
2243 None,
2244 )
2245 };
2246
2247 let protocol_config = epoch_store.protocol_config();
2248 let (kind, signer, gas_data) = transaction.execution_parts();
2249
2250 let silent = true;
2251 let executor = iota_execution::executor(protocol_config, silent, None)
2252 .expect("Creating an executor should not fail here");
2253
2254 let expensive_checks = false;
2255 let (inner_temp_store, _, effects, execution_error) = executor
2256 .execute_transaction_to_effects(
2257 self.get_backing_store().as_ref(),
2258 protocol_config,
2259 self.metrics.limits_metrics.clone(),
2260 expensive_checks,
2261 self.config.certificate_deny_config.certificate_deny_set(),
2262 &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2263 epoch_store
2264 .epoch_start_config()
2265 .epoch_data()
2266 .epoch_start_timestamp(),
2267 checked_input_objects,
2268 gas_data,
2269 gas_status,
2270 kind,
2271 signer,
2272 transaction_digest,
2273 &mut None,
2274 );
2275 let tx_digest = *effects.transaction_digest();
2276
2277 let module_cache =
2278 TemporaryModuleResolver::new(&inner_temp_store, epoch_store.module_cache().clone());
2279
2280 let mut layout_resolver =
2281 epoch_store
2282 .executor()
2283 .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
2284 &inner_temp_store,
2285 self.get_backing_package_store(),
2286 )));
2287 let object_changes = Vec::new();
2289
2290 let balance_changes = Vec::new();
2292
2293 let written_with_kind = effects
2294 .created()
2295 .into_iter()
2296 .map(|(oref, _)| (oref, WriteKind::Create))
2297 .chain(
2298 effects
2299 .unwrapped()
2300 .into_iter()
2301 .map(|(oref, _)| (oref, WriteKind::Unwrap)),
2302 )
2303 .chain(
2304 effects
2305 .mutated()
2306 .into_iter()
2307 .map(|(oref, _)| (oref, WriteKind::Mutate)),
2308 )
2309 .map(|(oref, kind)| {
2310 let obj = inner_temp_store.written.get(&oref.object_id).unwrap();
2311 (oref.object_id, (oref, obj.clone(), kind))
2313 })
2314 .collect();
2315
2316 let execution_error_source = execution_error
2317 .as_ref()
2318 .err()
2319 .and_then(|e| e.source().as_ref().map(|e| e.to_string()));
2320
2321 Ok((
2322 DryRunTransactionBlockResponse {
2323 suggested_gas_price: self
2325 .congestion_tracker
2326 .get_prediction_suggested_gas_price(&transaction),
2327 input: IotaTransactionBlockData::try_from_with_module_cache(
2328 transaction,
2329 &module_cache,
2330 tx_digest,
2331 )
2332 .map_err(|e| IotaError::TransactionSerialization {
2333 error: format!(
2334 "Failed to convert transaction to IotaTransactionBlockData: {e}",
2335 ),
2336 })?, effects: effects.clone().try_into()?,
2338 events: IotaTransactionBlockEvents::try_from(
2339 inner_temp_store.events.clone(),
2340 tx_digest,
2341 None,
2342 layout_resolver.as_mut(),
2343 )?,
2344 object_changes,
2345 balance_changes,
2346 execution_error_source,
2347 },
2348 written_with_kind,
2349 effects,
2350 mock_gas,
2351 ))
2352 }
2353
2354 pub fn simulate_transaction(
2355 &self,
2356 mut transaction: TransactionData,
2357 checks: VmChecks,
2358 ) -> IotaResult<SimulateTransactionResult> {
2359 if transaction.kind().is_system() {
2360 return Err(IotaError::UnsupportedFeature {
2361 error: "simulate does not support system transactions".to_string(),
2362 });
2363 }
2364
2365 let epoch_store = self.load_epoch_store_one_call_per_task();
2366 if !self.is_fullnode(&epoch_store) {
2367 return Err(IotaError::UnsupportedFeature {
2368 error: "simulate is only supported on fullnodes".to_string(),
2369 });
2370 }
2371
2372 transaction.validity_check_no_gas_check(epoch_store.protocol_config())?;
2376
2377 let input_object_kinds = transaction.input_objects()?;
2378 let receiving_object_refs = transaction.receiving_objects();
2379
2380 iota_transaction_checks::deny::check_transaction_for_validation(
2383 &transaction,
2384 &[],
2385 &input_object_kinds,
2386 &receiving_object_refs,
2387 &self.config.transaction_deny_config,
2388 self.get_backing_package_store().as_ref(),
2389 )?;
2390
2391 let (mut input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
2393 None,
2395 &input_object_kinds,
2396 &receiving_object_refs,
2397 epoch_store.epoch(),
2398 )?;
2399
2400 let mock_gas_id = if transaction.gas().is_empty() {
2402 let mock_gas_object = mock_simulation_gas_coin(transaction.gas_data().owner);
2403 let mock_gas_object_ref = mock_gas_object.object_ref();
2404 transaction.gas_data_mut().objects = vec![mock_gas_object_ref];
2405 input_objects.push(ObjectReadResult::new_from_gas_object(&mock_gas_object));
2406 Some(mock_gas_object.id())
2407 } else {
2408 None
2409 };
2410
2411 let protocol_config = epoch_store.protocol_config();
2412
2413 let authenticator_gas_budget = 0;
2416
2417 let (gas_status, checked_input_objects) = if checks.enabled() {
2420 iota_transaction_checks::check_transaction_input(
2421 protocol_config,
2422 epoch_store.reference_gas_price(),
2423 &transaction,
2424 input_objects,
2425 &receiving_objects,
2426 &self.metrics.bytecode_verifier_metrics,
2427 &self.config.verifier_signing_config,
2428 authenticator_gas_budget,
2429 )?
2430 } else {
2431 let checked_input_objects = iota_transaction_checks::check_dev_inspect_input(
2432 protocol_config,
2433 transaction.kind(),
2434 input_objects,
2435 receiving_objects,
2436 )?;
2437 let gas_status = IotaGasStatus::new(
2438 transaction.gas_budget(),
2439 transaction.gas_price(),
2440 epoch_store.reference_gas_price(),
2441 protocol_config,
2442 )?;
2443
2444 (gas_status, checked_input_objects)
2445 };
2446
2447 let executor = iota_execution::executor(
2449 protocol_config,
2450 true, None,
2452 )
2453 .expect("Creating an executor should not fail here");
2454
2455 let (kind, signer, gas_data) = transaction.execution_parts();
2457 let (inner_temp_store, _, effects, execution_result) = executor.dev_inspect_transaction(
2458 self.get_backing_store().as_ref(),
2459 protocol_config,
2460 self.metrics.limits_metrics.clone(),
2461 false, self.config.certificate_deny_config.certificate_deny_set(),
2463 &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2464 epoch_store
2465 .epoch_start_config()
2466 .epoch_data()
2467 .epoch_start_timestamp(),
2468 checked_input_objects,
2469 gas_data,
2470 gas_status,
2471 kind,
2472 signer,
2473 transaction.digest(),
2474 checks.disabled(),
2475 );
2476
2477 Ok(SimulateTransactionResult {
2480 input_objects: inner_temp_store.input_objects,
2481 output_objects: inner_temp_store.written,
2482 events: effects.events_digest().map(|_| inner_temp_store.events),
2483 effects,
2484 execution_result,
2485 suggested_gas_price: self
2486 .congestion_tracker
2487 .get_prediction_suggested_gas_price(&transaction),
2488 mock_gas_id,
2489 })
2490 }
2491
2492 #[instrument("dev_inspect_tx", level = "trace", skip_all)]
2497 pub async fn dev_inspect_transaction_block(
2498 &self,
2499 sender: Address,
2500 transaction_kind: TransactionKind,
2501 gas_price: Option<u64>,
2502 gas_budget: Option<u64>,
2503 gas_sponsor: Option<Address>,
2504 gas_objects: Option<Vec<ObjectReference>>,
2505 show_raw_txn_data_and_effects: Option<bool>,
2506 skip_checks: Option<bool>,
2507 ) -> IotaResult<DevInspectResults> {
2508 let epoch_store = self.load_epoch_store_one_call_per_task();
2509
2510 if !self.is_fullnode(&epoch_store) {
2511 return Err(IotaError::UnsupportedFeature {
2512 error: "dev-inspect is only supported on fullnodes".to_string(),
2513 });
2514 }
2515
2516 if transaction_kind.is_system() {
2517 return Err(IotaError::UnsupportedFeature {
2518 error: "system transactions are not supported".to_string(),
2519 });
2520 }
2521
2522 let show_raw_txn_data_and_effects = show_raw_txn_data_and_effects.unwrap_or(false);
2523 let skip_checks = skip_checks.unwrap_or(true);
2524 let reference_gas_price = epoch_store.reference_gas_price();
2525 let protocol_config = epoch_store.protocol_config();
2526 let max_tx_gas = protocol_config.max_tx_gas();
2527
2528 let price = gas_price.unwrap_or(reference_gas_price);
2529 let budget = gas_budget.unwrap_or(max_tx_gas);
2530 let owner = gas_sponsor.unwrap_or(sender);
2531 let payment = gas_objects.unwrap_or_default();
2534 let mut transaction = TransactionData::V1(TransactionDataV1 {
2535 kind: transaction_kind.clone(),
2536 sender,
2537 gas_payment: GasPayment {
2538 objects: payment,
2539 owner,
2540 price,
2541 budget,
2542 },
2543 expiration: TransactionExpiration::None,
2544 });
2545
2546 let raw_txn_data = if show_raw_txn_data_and_effects {
2547 bcs::to_bytes(&transaction).map_err(|_| IotaError::TransactionSerialization {
2548 error: "Failed to serialize transaction during dev inspect".to_string(),
2549 })?
2550 } else {
2551 vec![]
2552 };
2553
2554 transaction.validity_check_no_gas_check(protocol_config)?;
2555
2556 let input_object_kinds = transaction.input_objects()?;
2557 let receiving_object_refs = transaction.receiving_objects();
2558
2559 iota_transaction_checks::deny::check_transaction_for_validation(
2560 &transaction,
2561 &[],
2562 &input_object_kinds,
2563 &receiving_object_refs,
2564 &self.config.transaction_deny_config,
2565 self.get_backing_package_store().as_ref(),
2566 )?;
2567
2568 let (mut input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
2569 None,
2571 &input_object_kinds,
2572 &receiving_object_refs,
2573 epoch_store.epoch(),
2574 )?;
2575
2576 let (gas_status, checked_input_objects) = if skip_checks {
2577 if transaction.gas().is_empty() {
2582 let dummy_gas_object = Object::new_gas_with_balance_and_owner_for_testing(
2584 SIMULATION_GAS_COIN_VALUE,
2585 transaction.gas_owner(),
2586 );
2587 let gas_object_ref = dummy_gas_object.object_ref();
2588 transaction.gas_data_mut().objects = vec![gas_object_ref];
2589 input_objects.push(ObjectReadResult::new(
2590 InputObjectKind::ImmOrOwnedMoveObject(gas_object_ref),
2591 dummy_gas_object.into(),
2592 ));
2593 }
2594 let checked_input_objects = iota_transaction_checks::check_dev_inspect_input(
2595 protocol_config,
2596 &transaction_kind,
2597 input_objects,
2598 receiving_objects,
2599 )?;
2600 let gas_status = IotaGasStatus::new(
2601 max_tx_gas,
2602 transaction.gas_price(),
2603 reference_gas_price,
2604 protocol_config,
2605 )?;
2606
2607 (gas_status, checked_input_objects)
2608 } else {
2609 if transaction.gas().is_empty() {
2613 let dummy_gas_object = Object::new_gas_with_balance_and_owner_for_testing(
2615 SIMULATION_GAS_COIN_VALUE,
2616 transaction.gas_owner(),
2617 );
2618 let gas_object_ref = dummy_gas_object.object_ref();
2619 transaction.gas_data_mut().objects = vec![gas_object_ref];
2620 iota_transaction_checks::check_transaction_input_with_given_gas(
2621 epoch_store.protocol_config(),
2622 reference_gas_price,
2623 &transaction,
2624 input_objects,
2625 receiving_objects,
2626 dummy_gas_object,
2627 &self.metrics.bytecode_verifier_metrics,
2628 &self.config.verifier_signing_config,
2629 )?
2630 } else {
2631 let authenticator_gas_budget = 0;
2634
2635 iota_transaction_checks::check_transaction_input(
2636 epoch_store.protocol_config(),
2637 reference_gas_price,
2638 &transaction,
2639 input_objects,
2640 &receiving_objects,
2641 &self.metrics.bytecode_verifier_metrics,
2642 &self.config.verifier_signing_config,
2643 authenticator_gas_budget,
2644 )?
2645 }
2646 };
2647
2648 let executor = iota_execution::executor(protocol_config, true, None)
2649 .expect("Creating an executor should not fail here");
2650 let gas_data = transaction.gas_data().clone();
2651 let intent_msg = IntentMessage::new(
2652 Intent {
2653 version: IntentVersion::V0,
2654 scope: IntentScope::TransactionData,
2655 app_id: IntentAppId::Iota,
2656 },
2657 transaction,
2658 );
2659 let transaction_digest = TransactionDigest::new(intent_msg.value.digest().into_inner());
2660 let (inner_temp_store, _, effects, execution_result) = executor.dev_inspect_transaction(
2661 self.get_backing_store().as_ref(),
2662 protocol_config,
2663 self.metrics.limits_metrics.clone(),
2664 false,
2666 self.config.certificate_deny_config.certificate_deny_set(),
2667 &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2668 epoch_store
2669 .epoch_start_config()
2670 .epoch_data()
2671 .epoch_start_timestamp(),
2672 checked_input_objects,
2673 gas_data,
2674 gas_status,
2675 transaction_kind,
2676 sender,
2677 transaction_digest,
2678 skip_checks,
2679 );
2680
2681 let raw_effects = if show_raw_txn_data_and_effects {
2682 bcs::to_bytes(&effects).map_err(|_| IotaError::TransactionSerialization {
2683 error: "Failed to serialize transaction effects during dev inspect".to_string(),
2684 })?
2685 } else {
2686 vec![]
2687 };
2688
2689 let mut layout_resolver =
2690 epoch_store
2691 .executor()
2692 .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
2693 &inner_temp_store,
2694 self.get_backing_package_store(),
2695 )));
2696
2697 DevInspectResults::new(
2698 effects,
2699 inner_temp_store.events.clone(),
2700 execution_result,
2701 raw_txn_data,
2702 raw_effects,
2703 layout_resolver.as_mut(),
2704 )
2705 }
2706
2707 pub fn reference_gas_price_for_testing(&self) -> Result<u64, anyhow::Error> {
2709 let epoch_store = self.epoch_store_for_testing();
2710 Ok(epoch_store.reference_gas_price())
2711 }
2712
2713 #[instrument(level = "trace", skip_all)]
2714 pub fn try_is_tx_already_executed(&self, digest: &TransactionDigest) -> IotaResult<bool> {
2715 self.get_transaction_cache_reader()
2716 .try_is_tx_already_executed(digest)
2717 }
2718
2719 pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> bool {
2721 self.try_is_tx_already_executed(digest)
2722 .expect("storage access failed")
2723 }
2724
2725 #[instrument(level = "debug", skip_all, err)]
2727 fn index_tx(
2728 &self,
2729 indexes: &IndexStore,
2730 digest: &TransactionDigest,
2731 transaction: &VerifiedExecutableTransaction,
2733 effects: &TransactionEffects,
2734 events: &TransactionEvents,
2735 timestamp_ms: u64,
2736 tx_coins: Option<TxCoins>,
2737 written: &WrittenObjects,
2738 inner_temporary_store: &InnerTemporaryStore,
2739 epoch_store: &Arc<AuthorityPerEpochStore>,
2740 ) -> IotaResult<u64> {
2741 let changes = self
2742 .process_object_index(effects, written, inner_temporary_store, epoch_store)
2743 .tap_err(|e| warn!(tx_digest=?digest, "Failed to process object index, index_tx is skipped: {e}"))?;
2744
2745 indexes.index_tx(
2746 transaction.data().transaction().sender(),
2747 transaction
2748 .data()
2749 .transaction()
2750 .input_objects()?
2751 .iter()
2752 .map(|o| o.object_id()),
2753 effects
2754 .all_changed_objects()
2755 .into_iter()
2756 .map(|(obj_ref, owner, _kind)| (obj_ref, owner)),
2757 transaction
2758 .data()
2759 .transaction()
2760 .move_calls()
2761 .into_iter()
2762 .map(|(package, module, function)| {
2763 (*package, module.to_owned(), function.to_owned())
2764 }),
2765 events,
2766 changes,
2767 digest,
2768 timestamp_ms,
2769 tx_coins,
2770 )
2771 }
2772
2773 #[cfg(msim)]
2774 fn create_fail_state(
2775 &self,
2776 transaction: &VerifiedExecutableTransaction,
2777 epoch_store: &Arc<AuthorityPerEpochStore>,
2778 effects: &mut TransactionEffects,
2779 ) {
2780 use std::cell::RefCell;
2781
2782 use iota_types::effects::TransactionEffectsAPIForTesting;
2783 thread_local! {
2784 static FAIL_STATE: RefCell<(u64, HashSet<AuthorityName>)> = RefCell::new((0, HashSet::new()));
2785 }
2786 if !transaction.data().transaction().is_system_tx() {
2787 let committee = epoch_store.committee();
2788 let cur_stake = (**committee).weight(&self.name);
2789 if cur_stake > 0 {
2790 FAIL_STATE.with_borrow_mut(|fail_state| {
2791 if fail_state.0 < committee.validity_threshold() {
2793 fail_state.0 += cur_stake;
2794 fail_state.1.insert(self.name);
2795 }
2796
2797 if fail_state.1.contains(&self.name) {
2798 info!("cp_exec failing tx");
2799 effects.gas_cost_summary_mut_for_testing().computation_cost += 1;
2800 }
2801 });
2802 }
2803 }
2804 }
2805
2806 fn process_object_index(
2807 &self,
2808 effects: &TransactionEffects,
2809 written: &WrittenObjects,
2810 inner_temporary_store: &InnerTemporaryStore,
2811 epoch_store: &Arc<AuthorityPerEpochStore>,
2812 ) -> IotaResult<ObjectIndexChanges> {
2813 let mut layout_resolver =
2814 epoch_store
2815 .executor()
2816 .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
2817 inner_temporary_store,
2818 self.get_backing_package_store(),
2819 )));
2820
2821 let modified_at_version = effects
2822 .modified_at_versions()
2823 .into_iter()
2824 .collect::<HashMap<_, _>>();
2825
2826 let tx_digest = effects.transaction_digest();
2827 let mut deleted_owners = vec![];
2828 let mut deleted_dynamic_fields = vec![];
2829 for object_ref in effects.deleted().into_iter().chain(effects.wrapped()) {
2830 let old_version = modified_at_version.get(&object_ref.object_id).unwrap();
2831 match self.get_owner_at_version(&object_ref.object_id, *old_version).unwrap_or_else(
2834 |e| panic!("tx_digest={tx_digest}, error processing object owner index, cannot find owner for object {} at version {old_version:?}. Err: {e:?}", object_ref.object_id)
2835 ) {
2836 Owner::Address(addr) => deleted_owners.push((addr, object_ref.object_id)),
2837 Owner::Object(object_id) => {
2838 deleted_dynamic_fields.push((object_id, object_ref.object_id))
2839 }
2840 _ => {}
2841 }
2842 }
2843
2844 let mut new_owners = vec![];
2845 let mut new_dynamic_fields = vec![];
2846
2847 for (oref, owner, kind) in effects.all_changed_objects() {
2848 let id = &oref.object_id;
2849 if let WriteKind::Mutate = kind {
2852 let Some(old_version) = modified_at_version.get(id) else {
2853 panic!(
2854 "tx_digest={tx_digest}, error processing object owner index, cannot find modified at version for mutated object [{id}]."
2855 );
2856 };
2857 let Some(old_object) = self
2860 .get_object_store()
2861 .try_get_object_by_key(id, *old_version)?
2862 else {
2863 panic!(
2864 "tx_digest={tx_digest}, error processing object owner index, cannot find owner for object {id} at version {old_version:?}"
2865 );
2866 };
2867 if old_object.owner != owner {
2868 match old_object.owner {
2869 Owner::Address(addr) => {
2870 deleted_owners.push((addr, *id));
2871 }
2872 Owner::Object(object_id) => deleted_dynamic_fields.push((object_id, *id)),
2873 _ => {}
2874 }
2875 }
2876 }
2877
2878 match owner {
2879 Owner::Address(addr) => {
2880 let new_object = written.get(id).unwrap_or_else(
2883 || panic!("tx_digest={tx_digest}, error processing object owner index, written does not contain object {id}")
2884 );
2885 assert_eq!(
2886 new_object.version(),
2887 oref.version,
2888 "tx_digest={} error processing object owner index, object {} from written has mismatched version. Actual: {}, expected: {}",
2889 tx_digest,
2890 id,
2891 new_object.version(),
2892 oref.version
2893 );
2894
2895 let type_ = new_object
2896 .type_()
2897 .map(|type_| ObjectType::Struct(type_.clone()))
2898 .unwrap_or(ObjectType::Package);
2899
2900 new_owners.push((
2901 (addr, *id),
2902 ObjectInfo {
2903 object_id: *id,
2904 version: oref.version,
2905 digest: oref.digest,
2906 type_,
2907 owner,
2908 previous_transaction: *effects.transaction_digest(),
2909 },
2910 ));
2911 }
2912 Owner::Object(owner) => {
2913 let new_object = written.get(id).unwrap_or_else(
2914 || panic!("tx_digest={tx_digest}, error processing object owner index, written does not contain object {id}")
2915 );
2916 assert_eq!(
2917 new_object.version(),
2918 oref.version,
2919 "tx_digest={} error processing object owner index, object {} from written has mismatched version. Actual: {}, expected: {}",
2920 tx_digest,
2921 id,
2922 new_object.version(),
2923 oref.version
2924 );
2925
2926 let Some(df_info) = self
2927 .try_create_dynamic_field_info(new_object, written, layout_resolver.as_mut())
2928 .unwrap_or_else(|e| {
2929 error!("try_create_dynamic_field_info should not fail, {}, new_object={:?}", e, new_object);
2930 None
2931 }
2932 )
2933 else {
2934 continue;
2936 };
2937 new_dynamic_fields.push(((owner, *id), df_info))
2938 }
2939 _ => {}
2940 }
2941 }
2942
2943 Ok(ObjectIndexChanges {
2944 deleted_owners,
2945 deleted_dynamic_fields,
2946 new_owners,
2947 new_dynamic_fields,
2948 })
2949 }
2950
2951 fn try_create_dynamic_field_info(
2952 &self,
2953 o: &Object,
2954 written: &WrittenObjects,
2955 resolver: &mut dyn LayoutResolver,
2956 ) -> IotaResult<Option<DynamicFieldInfo>> {
2957 let Some(move_object) = o.data.as_opt_struct().cloned() else {
2959 return Ok(None);
2960 };
2961
2962 if !move_object.struct_tag().is_dynamic_field() {
2964 return Ok(None);
2965 }
2966
2967 let layout = match resolver.get_annotated_layout(move_object.struct_tag()) {
2968 Ok(annotated_layout) => annotated_layout.into_layout(),
2969 Err(e) => {
2970 error!(
2971 "unable to load layout for type `{:?}`: {e}",
2972 move_object.struct_tag()
2973 );
2974 return Ok(None);
2975 }
2976 };
2977
2978 let field =
2979 DFV::FieldVisitor::deserialize(move_object.contents(), &layout).map_err(|e| {
2980 IotaError::ObjectDeserialization {
2981 error: e.to_string(),
2982 }
2983 })?;
2984
2985 let type_ = field.kind;
2986 let name_type: TypeTag = type_tag_core_to_sdk(&field.name_layout.into());
2987 let bcs_name = field.name_bytes.to_owned();
2988
2989 let name_value = BoundedVisitor::deserialize_value(field.name_bytes, field.name_layout)
2990 .map_err(|e| {
2991 warn!("{e}");
2992 IotaError::ObjectDeserialization {
2993 error: e.to_string(),
2994 }
2995 })?;
2996
2997 let name = DynamicFieldName {
2998 type_: name_type,
2999 value: IotaMoveValue::from(name_value).to_json_value(),
3000 };
3001
3002 let value_metadata = field.value_metadata().map_err(|e| {
3003 warn!("{e}");
3004 IotaError::ObjectDeserialization {
3005 error: e.to_string(),
3006 }
3007 })?;
3008
3009 Ok(Some(match value_metadata {
3010 DFV::ValueMetadata::DynamicField(object_type) => DynamicFieldInfo {
3011 name,
3012 bcs_name,
3013 type_,
3014 object_type: object_type.to_canonical_string(true),
3015 object_id: o.id(),
3016 version: o.version(),
3017 digest: o.digest(),
3018 },
3019
3020 DFV::ValueMetadata::DynamicObjectField(object_id) => {
3021 let (version, digest, object_type) = if let Some(object) = written.get(&object_id) {
3026 (
3027 object.version(),
3028 object.digest(),
3029 object.data.opt_object_type().unwrap().clone(),
3030 )
3031 } else {
3032 let object = self
3034 .get_object_store()
3035 .try_get_object_by_key(&object_id, o.version())?
3036 .ok_or_else(|| UserInputError::ObjectNotFound {
3037 object_id,
3038 version: Some(o.version()),
3039 })?;
3040 let version = object.version();
3041 let digest = object.digest();
3042 let object_type = object.data.opt_object_type().unwrap().clone();
3043 (version, digest, object_type)
3044 };
3045
3046 DynamicFieldInfo {
3047 name,
3048 bcs_name,
3049 type_,
3050 object_type: object_type.to_string(),
3051 object_id,
3052 version,
3053 digest,
3054 }
3055 }
3056 }))
3057 }
3058
3059 #[instrument(level = "trace", skip_all, err)]
3060 fn post_process_one_tx(
3061 &self,
3062 transaction: &VerifiedExecutableTransaction,
3063 effects: &TransactionEffects,
3064 inner_temporary_store: &InnerTemporaryStore,
3065 epoch_store: &Arc<AuthorityPerEpochStore>,
3066 ) -> IotaResult {
3067 if self.indexes.is_none() {
3068 return Ok(());
3069 }
3070
3071 let _scope = monitored_scope("Execution::post_process_one_tx");
3072
3073 let tx_digest = transaction.digest();
3074 let timestamp_ms = Self::unixtime_now_ms();
3075 let events = &inner_temporary_store.events;
3076 let written = &inner_temporary_store.written;
3077 let tx_coins = self.fullnode_only_get_tx_coins_for_indexing(
3078 effects,
3079 inner_temporary_store,
3080 epoch_store,
3081 );
3082
3083 if let Some(indexes) = &self.indexes {
3085 let _ = self
3086 .index_tx(
3087 indexes.as_ref(),
3088 tx_digest,
3089 transaction,
3090 effects,
3091 events,
3092 timestamp_ms,
3093 tx_coins,
3094 written,
3095 inner_temporary_store,
3096 epoch_store,
3097 )
3098 .tap_ok(|_| self.metrics.post_processing_total_tx_indexed.inc())
3099 .tap_err(|e| error!(?tx_digest, "Post processing - Couldn't index tx: {e}"))
3100 .expect("Indexing tx should not fail");
3101
3102 let effects: IotaTransactionBlockEffects = effects.clone().try_into()?;
3103 let events = self.make_transaction_block_events(
3104 events.clone(),
3105 *tx_digest,
3106 timestamp_ms,
3107 epoch_store,
3108 inner_temporary_store,
3109 )?;
3110 self.subscription_handler
3112 .process_tx(transaction.data().transaction(), &effects, &events)
3113 .tap_ok(|_| {
3114 self.metrics
3115 .post_processing_total_tx_had_event_processed
3116 .inc()
3117 })
3118 .tap_err(|e| {
3119 warn!(
3120 ?tx_digest,
3121 "Post processing - Couldn't process events for tx: {}", e
3122 )
3123 })?;
3124
3125 self.metrics
3126 .post_processing_total_events_emitted
3127 .inc_by(events.data.len() as u64);
3128 };
3129 Ok(())
3130 }
3131
3132 fn make_transaction_block_events(
3133 &self,
3134 transaction_events: TransactionEvents,
3135 digest: TransactionDigest,
3136 timestamp_ms: u64,
3137 epoch_store: &Arc<AuthorityPerEpochStore>,
3138 inner_temporary_store: &InnerTemporaryStore,
3139 ) -> IotaResult<IotaTransactionBlockEvents> {
3140 let mut layout_resolver =
3141 epoch_store
3142 .executor()
3143 .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
3144 inner_temporary_store,
3145 self.get_backing_package_store(),
3146 )));
3147 IotaTransactionBlockEvents::try_from(
3148 transaction_events,
3149 digest,
3150 Some(timestamp_ms),
3151 layout_resolver.as_mut(),
3152 )
3153 }
3154
3155 pub fn unixtime_now_ms() -> u64 {
3156 let now = SystemTime::now()
3157 .duration_since(UNIX_EPOCH)
3158 .expect("Time went backwards")
3159 .as_millis();
3160 u64::try_from(now).expect("Travelling in time machine")
3161 }
3162
3163 #[instrument(level = "trace", skip_all)]
3164 pub async fn handle_transaction_info_request(
3165 &self,
3166 request: TransactionInfoRequest,
3167 ) -> IotaResult<TransactionInfoResponse> {
3168 let epoch_store = self.load_epoch_store_one_call_per_task();
3169 let (transaction, status) = self
3170 .get_transaction_status(&request.transaction_digest, &epoch_store)?
3171 .ok_or(IotaError::TransactionNotFound {
3172 digest: request.transaction_digest,
3173 })?;
3174 Ok(TransactionInfoResponse {
3175 transaction,
3176 status,
3177 })
3178 }
3179
3180 #[instrument(level = "trace", skip_all)]
3181 pub async fn handle_object_info_request(
3182 &self,
3183 request: ObjectInfoRequest,
3184 ) -> IotaResult<ObjectInfoResponse> {
3185 let epoch_store = self.load_epoch_store_one_call_per_task();
3186
3187 let requested_object_seq = match request.request_kind {
3188 ObjectInfoRequestKind::LatestObjectInfo => {
3189 self.try_get_object_or_tombstone(request.object_id)?
3190 .ok_or_else(|| {
3191 IotaError::from(UserInputError::ObjectNotFound {
3192 object_id: request.object_id,
3193 version: None,
3194 })
3195 })?
3196 .version
3197 }
3198 ObjectInfoRequestKind::PastObjectInfoDebug(seq) => seq,
3199 };
3200
3201 let object = self
3202 .get_object_store()
3203 .try_get_object_by_key(&request.object_id, requested_object_seq)?
3204 .ok_or_else(|| {
3205 IotaError::from(UserInputError::ObjectNotFound {
3206 object_id: request.object_id,
3207 version: Some(requested_object_seq),
3208 })
3209 })?;
3210
3211 let layout = if let (LayoutGenerationOption::Generate, Some(move_obj)) =
3212 (request.generate_layout, object.data.as_opt_struct())
3213 {
3214 Some(into_struct_layout(
3215 epoch_store
3216 .executor()
3217 .type_layout_resolver(Box::new(self.get_backing_package_store().as_ref()))
3218 .get_annotated_layout(move_obj.struct_tag())?,
3219 )?)
3220 } else {
3221 None
3222 };
3223
3224 let lock = if !object.is_address_owned() {
3225 None
3227 } else {
3228 self.get_transaction_lock(&object.object_ref(), &epoch_store)?
3229 .map(|s| s.into_inner())
3230 };
3231
3232 Ok(ObjectInfoResponse {
3233 object,
3234 layout,
3235 lock_for_debugging: lock,
3236 })
3237 }
3238
3239 #[instrument(level = "trace", skip_all)]
3240 pub fn handle_checkpoint_request(
3241 &self,
3242 request: &CheckpointRequest,
3243 ) -> IotaResult<CheckpointResponse> {
3244 let summary = if request.certified {
3245 let summary = match request.sequence_number {
3246 Some(seq) => self
3247 .checkpoint_store
3248 .get_checkpoint_by_sequence_number(seq)?,
3249 None => self.checkpoint_store.get_latest_certified_checkpoint()?,
3250 }
3251 .map(|v| v.into_inner());
3252 summary.map(CheckpointSummaryResponse::Certified)
3253 } else {
3254 let summary = match request.sequence_number {
3255 Some(seq) => self.checkpoint_store.get_locally_computed_checkpoint(seq)?,
3256 None => self
3257 .checkpoint_store
3258 .get_latest_locally_computed_checkpoint()?,
3259 };
3260 summary.map(CheckpointSummaryResponse::Pending)
3261 };
3262 let contents = match &summary {
3263 Some(s) => self
3264 .checkpoint_store
3265 .get_checkpoint_contents(&s.contents_digest())?,
3266 None => None,
3267 };
3268 Ok(CheckpointResponse {
3269 checkpoint: summary,
3270 contents,
3271 })
3272 }
3273
3274 fn check_protocol_version(
3275 supported_protocol_versions: SupportedProtocolVersions,
3276 current_version: ProtocolVersion,
3277 ) {
3278 info!("current protocol version is now {:?}", current_version);
3279 info!("supported versions are: {:?}", supported_protocol_versions);
3280 if !supported_protocol_versions.is_version_supported(current_version) {
3281 let msg = format!(
3282 "Unsupported protocol version. The network is at {current_version:?}, but this IotaNode only supports: {supported_protocol_versions:?}. Shutting down.",
3283 );
3284
3285 error!("{}", msg);
3286 eprintln!("{msg}");
3287
3288 #[cfg(not(msim))]
3289 std::process::exit(1);
3290
3291 #[cfg(msim)]
3292 iota_simulator::task::shutdown_current_node();
3293 }
3294 }
3295
3296 #[expect(clippy::disallowed_methods)] pub async fn new(
3298 name: AuthorityName,
3299 secret: StableSyncAuthoritySigner,
3300 supported_protocol_versions: SupportedProtocolVersions,
3301 store: Arc<AuthorityStore>,
3302 execution_cache_trait_pointers: ExecutionCacheTraitPointers,
3303 epoch_store: Arc<AuthorityPerEpochStore>,
3304 committee_store: Arc<CommitteeStore>,
3305 indexes: Option<Arc<IndexStore>>,
3306 grpc_indexes_store: Option<Arc<GrpcIndexesStore>>,
3307 checkpoint_store: Arc<CheckpointStore>,
3308 prometheus_registry: &Registry,
3309 genesis_objects: &[Object],
3310 db_checkpoint_config: &DBCheckpointConfig,
3311 config: NodeConfig,
3312 validator_tx_finalizer: Option<Arc<ValidatorTxFinalizer<NetworkAuthorityClient>>>,
3313 chain_identifier: ChainIdentifier,
3314 pruner_db: Option<Arc<AuthorityPrunerTables>>,
3315 checkpoint_progress_tracker: Option<Arc<CheckpointProgressTracker>>,
3316 policy_config: Option<PolicyConfig>,
3317 firewall_config: Option<RemoteFirewallConfig>,
3318 ) -> Arc<Self> {
3319 Self::check_protocol_version(supported_protocol_versions, epoch_store.protocol_version());
3320
3321 let metrics = Arc::new(AuthorityMetrics::new(prometheus_registry));
3322 let (tx_ready_transactions, rx_ready_transactions) = unbounded_channel();
3323 let transaction_manager = Arc::new(TransactionManager::new(
3324 execution_cache_trait_pointers.object_cache_reader.clone(),
3325 execution_cache_trait_pointers
3326 .transaction_cache_reader
3327 .clone(),
3328 &epoch_store,
3329 tx_ready_transactions,
3330 metrics.clone(),
3331 ));
3332 let (tx_execution_shutdown, rx_execution_shutdown) = oneshot::channel();
3333
3334 let authority_per_epoch_pruner = AuthorityPerEpochStorePruner::new(
3335 epoch_store.get_parent_path(),
3336 config
3337 .authority_store_pruning_config
3338 .num_latest_epoch_dbs_to_retain,
3339 )
3340 .await;
3341 let pruner = AuthorityStorePruner::new(
3342 store.perpetual_tables.clone(),
3343 checkpoint_store.clone(),
3344 grpc_indexes_store.clone(),
3345 indexes.clone(),
3346 config.authority_store_pruning_config.clone(),
3347 epoch_store.committee().authority_exists(&name),
3348 epoch_store.epoch_start_state().epoch_duration_ms(),
3349 prometheus_registry,
3350 pruner_db,
3351 checkpoint_progress_tracker.clone(),
3352 );
3353 let input_loader =
3354 TransactionInputLoader::new(execution_cache_trait_pointers.object_cache_reader.clone());
3355 let epoch = epoch_store.epoch();
3356 let rgp = epoch_store.reference_gas_price();
3357 let traffic_controller_metrics =
3358 Arc::new(TrafficControllerMetrics::new(prometheus_registry));
3359 let traffic_controller = if let Some(policy_config) = policy_config {
3360 Some(Arc::new(
3361 TrafficController::init(
3362 policy_config,
3363 traffic_controller_metrics,
3364 firewall_config.clone(),
3365 )
3366 .await,
3367 ))
3368 } else {
3369 None
3370 };
3371 let state = Arc::new(AuthorityState {
3372 name,
3373 secret,
3374 execution_lock: RwLock::new(epoch),
3375 epoch_store: ArcSwap::new(epoch_store.clone()),
3376 input_loader,
3377 execution_cache_trait_pointers,
3378 indexes,
3379 grpc_indexes_store,
3380 subscription_handler: Arc::new(SubscriptionHandler::new(prometheus_registry)),
3381 checkpoint_store,
3382 committee_store,
3383 transaction_manager,
3384 tx_execution_shutdown: Mutex::new(Some(tx_execution_shutdown)),
3385 metrics,
3386 pruner,
3387 authority_per_epoch_pruner,
3388 checkpoint_progress_tracker,
3389 db_checkpoint_config: db_checkpoint_config.clone(),
3390 config,
3391 overload_info: AuthorityOverloadInfo::default(),
3392 validator_tx_finalizer,
3393 chain_identifier,
3394 congestion_tracker: Arc::new(CongestionTracker::new(rgp)),
3395 traffic_controller,
3396 });
3397
3398 let authority_state = Arc::downgrade(&state);
3400 spawn_monitored_task!(execution_process(
3401 authority_state,
3402 rx_ready_transactions,
3403 rx_execution_shutdown,
3404 ));
3405 state
3407 .create_owner_index_if_empty(genesis_objects, &epoch_store)
3408 .expect("Error indexing genesis objects.");
3409
3410 state
3411 }
3412
3413 pub fn epoch_db_pruner(&self) -> &AuthorityPerEpochStorePruner {
3414 &self.authority_per_epoch_pruner
3415 }
3416
3417 pub fn get_object_cache_reader(&self) -> &Arc<dyn ObjectCacheRead> {
3419 &self.execution_cache_trait_pointers.object_cache_reader
3420 }
3421
3422 pub fn get_transaction_cache_reader(&self) -> &Arc<dyn TransactionCacheRead> {
3423 &self.execution_cache_trait_pointers.transaction_cache_reader
3424 }
3425
3426 pub fn get_cache_writer(&self) -> &Arc<dyn ExecutionCacheWrite> {
3427 &self.execution_cache_trait_pointers.cache_writer
3428 }
3429
3430 pub fn get_backing_store(&self) -> &Arc<dyn BackingStore + Send + Sync> {
3431 &self.execution_cache_trait_pointers.backing_store
3432 }
3433
3434 pub fn get_backing_package_store(&self) -> &Arc<dyn BackingPackageStore + Send + Sync> {
3435 &self.execution_cache_trait_pointers.backing_package_store
3436 }
3437
3438 pub fn get_object_store(&self) -> &Arc<dyn ObjectStore + Send + Sync> {
3439 &self.execution_cache_trait_pointers.object_store
3440 }
3441
3442 pub fn get_reconfig_api(&self) -> &Arc<dyn ExecutionCacheReconfigAPI> {
3443 &self.execution_cache_trait_pointers.reconfig_api
3444 }
3445
3446 pub fn get_global_state_hash_store(&self) -> &Arc<dyn GlobalStateHashStore> {
3447 &self.execution_cache_trait_pointers.global_state_hash_store
3448 }
3449
3450 pub fn get_checkpoint_cache(&self) -> &Arc<dyn CheckpointCache> {
3451 &self.execution_cache_trait_pointers.checkpoint_cache
3452 }
3453
3454 pub fn get_state_sync_store(&self) -> &Arc<dyn StateSyncAPI> {
3455 &self.execution_cache_trait_pointers.state_sync_store
3456 }
3457
3458 pub fn get_cache_commit(&self) -> &Arc<dyn ExecutionCacheCommit> {
3459 &self.execution_cache_trait_pointers.cache_commit
3460 }
3461
3462 pub fn database_for_testing(&self) -> Arc<AuthorityStore> {
3463 self.execution_cache_trait_pointers
3464 .testing_api
3465 .database_for_testing()
3466 }
3467
3468 pub async fn prune_checkpoints_for_eligible_epochs_for_testing(
3469 &self,
3470 config: NodeConfig,
3471 metrics: Arc<AuthorityStorePruningMetrics>,
3472 ) -> anyhow::Result<()> {
3473 AuthorityStorePruner::prune_checkpoints_for_eligible_epochs(
3474 &self.database_for_testing().perpetual_tables,
3475 &self.checkpoint_store,
3476 self.grpc_indexes_store.as_deref(),
3477 None,
3478 config.authority_store_pruning_config,
3479 metrics,
3480 EPOCH_DURATION_MS_FOR_TESTING,
3481 self.checkpoint_progress_tracker.as_ref(),
3482 )
3483 .await
3484 }
3485
3486 pub fn transaction_manager(&self) -> &Arc<TransactionManager> {
3487 &self.transaction_manager
3488 }
3489
3490 pub fn enqueue_transactions_for_execution(
3493 &self,
3494 transactions: Vec<VerifiedExecutableTransaction>,
3495 epoch_store: &Arc<AuthorityPerEpochStore>,
3496 ) {
3497 self.transaction_manager.enqueue(transactions, epoch_store)
3498 }
3499
3500 pub fn enqueue_certificates_for_execution(
3502 &self,
3503 certs: Vec<VerifiedCertificate>,
3504 epoch_store: &Arc<AuthorityPerEpochStore>,
3505 ) {
3506 self.transaction_manager
3507 .enqueue_certificates(certs, epoch_store)
3508 }
3509
3510 pub fn enqueue_with_expected_effects_digest(
3511 &self,
3512 transactions: Vec<(VerifiedExecutableTransaction, TransactionEffectsDigest)>,
3513 epoch_store: &AuthorityPerEpochStore,
3514 ) {
3515 self.transaction_manager
3516 .enqueue_with_expected_effects_digest(transactions, epoch_store)
3517 }
3518
3519 fn create_owner_index_if_empty(
3520 &self,
3521 genesis_objects: &[Object],
3522 epoch_store: &Arc<AuthorityPerEpochStore>,
3523 ) -> IotaResult {
3524 let Some(index_store) = &self.indexes else {
3525 return Ok(());
3526 };
3527 if !index_store.is_empty() {
3528 return Ok(());
3529 }
3530
3531 let mut new_owners = vec![];
3532 let mut new_dynamic_fields = vec![];
3533 let mut layout_resolver = epoch_store
3534 .executor()
3535 .type_layout_resolver(Box::new(self.get_backing_package_store().as_ref()));
3536 for o in genesis_objects.iter() {
3537 match o.owner {
3538 Owner::Address(addr) => {
3539 new_owners.push(((addr, o.id()), ObjectInfo::new(&o.object_ref(), o)))
3540 }
3541 Owner::Object(object_id) => {
3542 let id = o.id();
3543 let info = match self.try_create_dynamic_field_info(
3544 o,
3545 &BTreeMap::new(),
3546 layout_resolver.as_mut(),
3547 ) {
3548 Ok(Some(info)) => info,
3549 Ok(None) => continue,
3550 Err(IotaError::UserInput {
3551 error:
3552 UserInputError::ObjectNotFound {
3553 object_id: not_found_id,
3554 version,
3555 },
3556 }) => {
3557 warn!(
3558 ?not_found_id,
3559 ?version,
3560 object_owner=?object_id,
3561 field=?id,
3562 "Skipping dynamic field: referenced genesis object not found"
3563 );
3564 continue;
3565 }
3566 Err(e) => return Err(e),
3567 };
3568 new_dynamic_fields.push(((object_id, id), info));
3569 }
3570 _ => {}
3571 }
3572 }
3573
3574 index_store.insert_genesis_objects(ObjectIndexChanges {
3575 deleted_owners: vec![],
3576 deleted_dynamic_fields: vec![],
3577 new_owners,
3578 new_dynamic_fields,
3579 })
3580 }
3581
3582 pub fn execution_lock_for_executable_transaction(
3586 &self,
3587 transaction: &VerifiedExecutableTransaction,
3588 ) -> IotaResult<ExecutionLockReadGuard<'_>> {
3589 let lock = self
3590 .execution_lock
3591 .try_read()
3592 .map_err(|_| IotaError::ValidatorHaltedAtEpochEnd)?;
3593 if *lock == transaction.auth_sig().epoch() {
3594 Ok(lock)
3595 } else {
3596 Err(IotaError::WrongEpoch {
3597 expected_epoch: *lock,
3598 actual_epoch: transaction.auth_sig().epoch(),
3599 })
3600 }
3601 }
3602
3603 pub fn execution_lock_for_signing(&self) -> IotaResult<ExecutionLockReadGuard<'_>> {
3609 self.execution_lock
3610 .try_read()
3611 .map_err(|_| IotaError::ValidatorHaltedAtEpochEnd)
3612 }
3613
3614 pub async fn execution_lock_for_reconfiguration(&self) -> ExecutionLockWriteGuard<'_> {
3615 self.execution_lock.write().await
3616 }
3617
3618 #[instrument(level = "error", skip_all)]
3619 pub async fn reconfigure(
3620 &self,
3621 cur_epoch_store: &AuthorityPerEpochStore,
3622 supported_protocol_versions: SupportedProtocolVersions,
3623 new_committee: Committee,
3624 epoch_start_configuration: EpochStartConfiguration,
3625 state_hasher: Arc<GlobalStateHasher>,
3626 expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
3627 epoch_supply_change: i64,
3628 epoch_last_checkpoint: CheckpointSequenceNumber,
3629 ) -> IotaResult<Arc<AuthorityPerEpochStore>> {
3630 Self::check_protocol_version(
3631 supported_protocol_versions,
3632 epoch_start_configuration
3633 .epoch_start_state()
3634 .protocol_version(),
3635 );
3636 self.metrics.reset_on_reconfigure();
3637 self.committee_store.insert_new_committee(&new_committee)?;
3638
3639 let mut execution_lock = self.execution_lock_for_reconfiguration().await;
3641
3642 cur_epoch_store.epoch_terminated().await;
3644
3645 let highest_locally_built_checkpoint_seq = self
3646 .checkpoint_store
3647 .get_latest_locally_computed_checkpoint()?
3648 .map(|c| c.sequence_number())
3649 .unwrap_or(0);
3650
3651 assert!(
3652 epoch_last_checkpoint >= highest_locally_built_checkpoint_seq,
3653 "expected {epoch_last_checkpoint} >= {highest_locally_built_checkpoint_seq}"
3654 );
3655 if highest_locally_built_checkpoint_seq == epoch_last_checkpoint
3656 || self.is_fullnode(cur_epoch_store)
3657 {
3658 let num_shared_version_assignments = cur_epoch_store.num_shared_version_assignments();
3662 if num_shared_version_assignments > 10 {
3669 debug_fatal!(
3671 "all shared_version_assignments should have been removed \
3672 (num_shared_version_assignments: {num_shared_version_assignments})"
3673 );
3674 }
3675 }
3676
3677 self.revert_uncommitted_epoch_transactions(cur_epoch_store)
3683 .await?;
3684 self.get_reconfig_api()
3685 .clear_state_end_of_epoch(&execution_lock);
3686 self.check_system_consistency(
3687 cur_epoch_store,
3688 state_hasher,
3689 expensive_safety_check_config,
3690 epoch_supply_change,
3691 )?;
3692 self.get_reconfig_api()
3693 .try_set_epoch_start_configuration(&epoch_start_configuration)?;
3694 if let Some(checkpoint_path) = &self.db_checkpoint_config.checkpoint_path {
3695 if self
3696 .db_checkpoint_config
3697 .perform_db_checkpoints_at_epoch_end
3698 {
3699 let checkpoint_indexes = self
3700 .db_checkpoint_config
3701 .perform_index_db_checkpoints_at_epoch_end
3702 .unwrap_or(false);
3703 let current_epoch = cur_epoch_store.epoch();
3704 let epoch_checkpoint_path = checkpoint_path.join(format!("epoch_{current_epoch}"));
3705 self.checkpoint_all_dbs(
3706 &epoch_checkpoint_path,
3707 cur_epoch_store,
3708 checkpoint_indexes,
3709 )?;
3710 }
3711 }
3712
3713 let new_epoch = new_committee.epoch;
3714 let new_epoch_store = self
3715 .reopen_epoch_db(
3716 cur_epoch_store,
3717 new_committee,
3718 epoch_start_configuration,
3719 expensive_safety_check_config,
3720 epoch_last_checkpoint,
3721 )
3722 .await?;
3723 assert_eq!(new_epoch_store.epoch(), new_epoch);
3724 self.transaction_manager.reconfigure(new_epoch);
3725 *execution_lock = new_epoch;
3726 Ok(new_epoch_store)
3730 }
3731
3732 pub async fn reconfigure_for_testing(&self) {
3737 let mut execution_lock = self.execution_lock_for_reconfiguration().await;
3738 let epoch_store = self.epoch_store_for_testing().clone();
3739 let protocol_config = epoch_store.protocol_config().clone();
3740 let _guard =
3748 ProtocolConfig::apply_overrides_for_testing(move |_, _| protocol_config.clone());
3749 let new_epoch_store = epoch_store.new_at_next_epoch_for_testing(
3750 self.get_backing_package_store().clone(),
3751 &self.config.expensive_safety_check_config,
3752 self.checkpoint_store
3753 .get_epoch_last_checkpoint(epoch_store.epoch())
3754 .unwrap()
3755 .map(|c| c.sequence_number())
3756 .unwrap_or_default(),
3757 );
3758 let new_epoch = new_epoch_store.epoch();
3759 self.transaction_manager.reconfigure(new_epoch);
3760 self.epoch_store.store(new_epoch_store);
3761 epoch_store.epoch_terminated().await;
3762 *execution_lock = new_epoch;
3763 }
3764
3765 #[instrument(level = "error", skip_all)]
3766 fn check_system_consistency(
3767 &self,
3768 cur_epoch_store: &AuthorityPerEpochStore,
3769 state_hasher: Arc<GlobalStateHasher>,
3770 expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
3771 epoch_supply_change: i64,
3772 ) -> IotaResult<()> {
3773 info!(
3774 "Performing iota conservation consistency check for epoch {}",
3775 cur_epoch_store.epoch()
3776 );
3777
3778 if cfg!(debug_assertions) {
3779 cur_epoch_store.check_all_executed_transactions_in_checkpoint();
3780 }
3781
3782 self.get_reconfig_api()
3783 .try_expensive_check_iota_conservation(cur_epoch_store, Some(epoch_supply_change))?;
3784
3785 if expensive_safety_check_config.enable_state_consistency_check() {
3787 info!(
3788 "Performing state consistency check for epoch {}",
3789 cur_epoch_store.epoch()
3790 );
3791 self.expensive_check_is_consistent_state(
3792 state_hasher,
3793 cur_epoch_store,
3794 cfg!(debug_assertions), );
3796 }
3797
3798 if expensive_safety_check_config.enable_secondary_index_checks() {
3799 if let Some(indexes) = self.indexes.clone() {
3800 verify_indexes(self.get_global_state_hash_store().as_ref(), indexes)
3801 .expect("secondary indexes are inconsistent");
3802 }
3803 }
3804
3805 Ok(())
3806 }
3807
3808 fn expensive_check_is_consistent_state(
3809 &self,
3810 state_hasher: Arc<GlobalStateHasher>,
3811 cur_epoch_store: &AuthorityPerEpochStore,
3812 panic: bool,
3813 ) {
3814 let live_object_set_hash = state_hasher.digest_live_object_set();
3815
3816 let root_state_hash: ECMHLiveObjectSetDigest = self
3817 .get_global_state_hash_store()
3818 .get_root_state_hash_for_epoch(cur_epoch_store.epoch())
3819 .expect("Retrieving root state hash cannot fail")
3820 .expect("Root state hash for epoch must exist")
3821 .1
3822 .digest()
3823 .into();
3824
3825 let is_inconsistent = root_state_hash != live_object_set_hash;
3826 if is_inconsistent {
3827 if panic {
3828 panic!(
3829 "Inconsistent state detected: root state hash: {root_state_hash:?}, live object set hash: {live_object_set_hash:?}"
3830 );
3831 } else {
3832 error!(
3833 "Inconsistent state detected: root state hash: {:?}, live object set hash: {:?}",
3834 root_state_hash, live_object_set_hash
3835 );
3836 }
3837 } else {
3838 info!("State consistency check passed");
3839 }
3840
3841 if !panic {
3842 state_hasher.set_inconsistent_state(is_inconsistent);
3843 }
3844 }
3845
3846 pub fn current_epoch_for_testing(&self) -> EpochId {
3847 self.epoch_store_for_testing().epoch()
3848 }
3849
3850 #[instrument(level = "error", skip_all)]
3851 pub fn checkpoint_all_dbs(
3852 &self,
3853 checkpoint_path: &Path,
3854 cur_epoch_store: &AuthorityPerEpochStore,
3855 checkpoint_indexes: bool,
3856 ) -> IotaResult {
3857 let _metrics_guard = self.metrics.db_checkpoint_latency.start_timer();
3858 let current_epoch = cur_epoch_store.epoch();
3859
3860 if checkpoint_path.exists() {
3861 info!("Skipping db checkpoint as it already exists for epoch: {current_epoch}");
3862 return Ok(());
3863 }
3864
3865 let checkpoint_path_tmp = checkpoint_path.with_extension("tmp");
3866 let store_checkpoint_path_tmp = checkpoint_path_tmp.join("store");
3867
3868 if checkpoint_path_tmp.exists() {
3869 fs::remove_dir_all(&checkpoint_path_tmp)
3870 .map_err(|e| IotaError::FileIO(e.to_string()))?;
3871 }
3872
3873 fs::create_dir_all(&checkpoint_path_tmp).map_err(|e| IotaError::FileIO(e.to_string()))?;
3874 fs::create_dir(&store_checkpoint_path_tmp).map_err(|e| IotaError::FileIO(e.to_string()))?;
3875
3876 self.checkpoint_store
3879 .checkpoint_db(&checkpoint_path_tmp.join("checkpoints"))?;
3880
3881 self.get_reconfig_api()
3882 .try_checkpoint_db(&store_checkpoint_path_tmp.join("perpetual"))?;
3883
3884 self.committee_store
3885 .checkpoint_db(&checkpoint_path_tmp.join("epochs"))?;
3886
3887 if checkpoint_indexes {
3888 if let Some(indexes) = self.indexes.as_ref() {
3889 indexes.checkpoint_db(&checkpoint_path_tmp.join("indexes"))?;
3890 }
3891 if let Some(grpc_indexes_store) = self.grpc_indexes_store.as_ref() {
3892 grpc_indexes_store.checkpoint_db(&checkpoint_path_tmp.join(GRPC_INDEXES_DIR))?;
3893 }
3894 }
3895
3896 fs::rename(checkpoint_path_tmp, checkpoint_path)
3897 .map_err(|e| IotaError::FileIO(e.to_string()))?;
3898 Ok(())
3899 }
3900
3901 pub fn load_epoch_store_one_call_per_task(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
3908 self.epoch_store.load()
3909 }
3910
3911 pub fn epoch_store_for_testing(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
3913 self.load_epoch_store_one_call_per_task()
3914 }
3915
3916 pub fn clone_committee_for_testing(&self) -> Committee {
3917 Committee::clone(self.epoch_store_for_testing().committee())
3918 }
3919
3920 #[instrument(level = "trace", skip_all)]
3921 pub fn try_get_object(&self, object_id: &ObjectId) -> IotaResult<Option<Object>> {
3922 self.get_object_store()
3923 .try_get_object(object_id)
3924 .map_err(Into::into)
3925 }
3926
3927 pub fn get_object(&self, object_id: &ObjectId) -> Option<Object> {
3929 self.try_get_object(object_id)
3930 .expect("storage access failed")
3931 }
3932
3933 pub fn get_iota_system_package_object_ref(&self) -> IotaResult<ObjectReference> {
3934 Ok(self
3935 .try_get_object(&ObjectId::SYSTEM)?
3936 .expect("system package should always exist")
3937 .object_ref())
3938 }
3939
3940 pub fn get_iota_system_state_object_for_testing(&self) -> IotaResult<IotaSystemState> {
3942 self.get_object_cache_reader()
3943 .try_get_iota_system_state_object_unsafe()
3944 }
3945
3946 #[instrument(level = "trace", skip_all)]
3947 pub fn get_checkpoint_by_sequence_number(
3948 &self,
3949 sequence_number: CheckpointSequenceNumber,
3950 ) -> IotaResult<Option<VerifiedCheckpoint>> {
3951 Ok(self
3952 .checkpoint_store
3953 .get_checkpoint_by_sequence_number(sequence_number)?)
3954 }
3955
3956 pub async fn wait_for_checkpoint_inclusion(
3967 &self,
3968 digests: &[TransactionDigest],
3969 timeout: Duration,
3970 ) -> IotaResult<BTreeMap<TransactionDigest, (CheckpointSequenceNumber, u64)>> {
3971 let deadline = tokio::time::Instant::now() + timeout;
3972 let mut checkpoint_timestamp_cache = HashMap::<CheckpointSequenceNumber, u64>::new();
3973 let mut results = BTreeMap::new();
3974 let mut remaining = digests.to_vec();
3975 let mut epoch_store = self.load_epoch_store_one_call_per_task().clone();
3976
3977 loop {
3978 let wait = epoch_store.wait_for_transactions_in_checkpoint_with_timeout(
3979 &remaining,
3980 deadline.saturating_duration_since(tokio::time::Instant::now()),
3981 |seq| self.checkpoint_timestamp_ms_cached(seq, &mut checkpoint_timestamp_cache),
3982 );
3983 tokio::select! {
3984 wait_results = wait => {
3985 for (digest, seq_and_ts) in remaining.iter().zip(wait_results?) {
3986 if let Some(seq_and_ts) = seq_and_ts {
3987 results.insert(*digest, seq_and_ts);
3988 }
3989 }
3990 return Ok(results);
3991 }
3992 _ = epoch_store.wait_epoch_terminated() => {}
3993 }
3994
3995 let found = match epoch_store.multi_get_transaction_checkpoint(&remaining) {
4002 Ok(found) => found,
4003 Err(IotaError::EpochEnded(_)) => vec![None; remaining.len()],
4008 Err(err) => return Err(err),
4009 };
4010 let mut still_uncheckpointed = Vec::new();
4011 for (digest, found_seq) in remaining.iter().zip(found) {
4012 match found_seq {
4013 Some(seq) => {
4014 let ts = self
4015 .checkpoint_timestamp_ms_cached(seq, &mut checkpoint_timestamp_cache);
4016 results.insert(*digest, (seq, ts));
4017 }
4018 None => still_uncheckpointed.push(*digest),
4019 }
4020 }
4021 remaining = still_uncheckpointed;
4022 if remaining.is_empty() {
4023 return Ok(results);
4024 }
4025
4026 match self
4027 .wait_for_next_epoch_store(epoch_store.epoch(), deadline)
4028 .await
4029 {
4030 Some(next) => epoch_store = next,
4031 None => return Ok(results),
4032 }
4033 }
4034 }
4035
4036 async fn wait_for_next_epoch_store(
4039 &self,
4040 prev_epoch: EpochId,
4041 deadline: tokio::time::Instant,
4042 ) -> Option<Arc<AuthorityPerEpochStore>> {
4043 const EPOCH_STORE_SWAP_POLL_INTERVAL: Duration = Duration::from_millis(100);
4048
4049 loop {
4050 let current = self.load_epoch_store_one_call_per_task().clone();
4053 if current.epoch() > prev_epoch {
4054 return Some(current);
4055 }
4056 if tokio::time::Instant::now() >= deadline {
4057 return None;
4058 }
4059 tokio::time::sleep(EPOCH_STORE_SWAP_POLL_INTERVAL).await;
4060 }
4061 }
4062
4063 fn checkpoint_timestamp_ms_cached(
4067 &self,
4068 seq: CheckpointSequenceNumber,
4069 cache: &mut HashMap<CheckpointSequenceNumber, u64>,
4070 ) -> u64 {
4071 *cache.entry(seq).or_insert_with(|| {
4072 self.get_checkpoint_by_sequence_number(seq)
4073 .ok()
4074 .flatten()
4075 .map(|c| c.timestamp_ms)
4076 .unwrap_or(0)
4077 })
4078 }
4079
4080 #[instrument(level = "trace", skip_all)]
4081 pub fn get_transaction_checkpoint_for_tests(
4082 &self,
4083 digest: &TransactionDigest,
4084 epoch_store: &AuthorityPerEpochStore,
4085 ) -> IotaResult<Option<VerifiedCheckpoint>> {
4086 let checkpoint = epoch_store.get_transaction_checkpoint(digest)?;
4087 let Some(checkpoint) = checkpoint else {
4088 return Ok(None);
4089 };
4090 let checkpoint = self
4091 .checkpoint_store
4092 .get_checkpoint_by_sequence_number(checkpoint)?;
4093 Ok(checkpoint)
4094 }
4095
4096 #[instrument(level = "trace", skip_all)]
4097 pub fn get_object_read(&self, object_id: &ObjectId) -> IotaResult<ObjectRead> {
4098 Ok(
4099 match self
4100 .get_object_cache_reader()
4101 .try_get_latest_object_or_tombstone(*object_id)?
4102 {
4103 Some((_, ObjectOrTombstone::Object(object))) => {
4104 let layout = self.get_object_layout(&object)?;
4105 ObjectRead::Exists(object.object_ref(), object, layout)
4106 }
4107 Some((_, ObjectOrTombstone::Tombstone(objref))) => ObjectRead::Deleted(objref),
4108 None => ObjectRead::NotExists(*object_id),
4109 },
4110 )
4111 }
4112
4113 pub fn get_chain_identifier(&self) -> ChainIdentifier {
4115 self.chain_identifier
4116 }
4117
4118 #[instrument(level = "trace", skip_all)]
4119 pub fn get_move_object<T>(&self, object_id: &ObjectId) -> IotaResult<T>
4120 where
4121 T: DeserializeOwned,
4122 {
4123 let o = self.get_object_read(object_id)?.into_object()?;
4124 if let Some(move_object) = o.data.as_opt_struct() {
4125 Ok(bcs::from_bytes(move_object.contents()).map_err(|e| {
4126 IotaError::ObjectDeserialization {
4127 error: format!("{e}"),
4128 }
4129 })?)
4130 } else {
4131 Err(IotaError::ObjectDeserialization {
4132 error: format!("Provided object : [{object_id}] is not a Move object."),
4133 })
4134 }
4135 }
4136
4137 #[instrument(level = "trace", skip_all)]
4143 pub fn get_past_object_read(
4144 &self,
4145 object_id: &ObjectId,
4146 version: Version,
4147 ) -> IotaResult<PastObjectRead> {
4148 let Some(obj_ref) = self
4150 .get_object_cache_reader()
4151 .try_get_latest_object_ref_or_tombstone(*object_id)?
4152 else {
4153 return Ok(PastObjectRead::ObjectNotExists(*object_id));
4154 };
4155
4156 if version > obj_ref.version {
4157 return Ok(PastObjectRead::VersionTooHigh {
4158 object_id: *object_id,
4159 asked_version: version,
4160 latest_version: obj_ref.version,
4161 });
4162 }
4163
4164 if version < obj_ref.version {
4165 return Ok(match self.read_object_at_version(object_id, version)? {
4167 Some((object, layout)) => {
4168 let obj_ref = object.object_ref();
4169 PastObjectRead::VersionFound(obj_ref, object, layout)
4170 }
4171
4172 None => PastObjectRead::VersionNotFound(*object_id, version),
4173 });
4174 }
4175
4176 if !obj_ref.digest.is_alive() {
4177 return Ok(PastObjectRead::ObjectDeleted(obj_ref));
4178 }
4179
4180 match self.read_object_at_version(object_id, obj_ref.version)? {
4181 Some((object, layout)) => Ok(PastObjectRead::VersionFound(obj_ref, object, layout)),
4182 None => {
4183 error!(
4184 "Object with in parent_entry is missing from object store, datastore is \
4185 inconsistent",
4186 );
4187 Err(UserInputError::ObjectNotFound {
4188 object_id: *object_id,
4189 version: Some(obj_ref.version),
4190 }
4191 .into())
4192 }
4193 }
4194 }
4195
4196 #[instrument(level = "trace", skip_all)]
4197 fn read_object_at_version(
4198 &self,
4199 object_id: &ObjectId,
4200 version: Version,
4201 ) -> IotaResult<Option<(Object, Option<MoveStructLayout>)>> {
4202 let Some(object) = self
4203 .get_object_cache_reader()
4204 .try_get_object_by_key(object_id, version)?
4205 else {
4206 return Ok(None);
4207 };
4208
4209 let layout = self.get_object_layout(&object)?;
4210 Ok(Some((object, layout)))
4211 }
4212
4213 fn get_object_layout(&self, object: &Object) -> IotaResult<Option<MoveStructLayout>> {
4214 let layout = object
4215 .data
4216 .as_opt_struct()
4217 .map(|object| {
4218 into_struct_layout(
4219 self.load_epoch_store_one_call_per_task()
4220 .executor()
4221 .type_layout_resolver(Box::new(self.get_backing_package_store().as_ref()))
4223 .get_annotated_layout(object.struct_tag())?,
4224 )
4225 })
4226 .transpose()?;
4227 Ok(layout)
4228 }
4229
4230 fn get_owner_at_version(&self, object_id: &ObjectId, version: Version) -> IotaResult<Owner> {
4231 self.get_object_store()
4232 .try_get_object_by_key(object_id, version)?
4233 .ok_or_else(|| {
4234 IotaError::from(UserInputError::ObjectNotFound {
4235 object_id: *object_id,
4236 version: Some(version),
4237 })
4238 })
4239 .map(|o| o.owner)
4240 }
4241
4242 #[instrument(level = "trace", skip_all)]
4243 pub fn get_owner_objects(
4244 &self,
4245 owner: Address,
4246 cursor: Option<ObjectId>,
4248 limit: usize,
4249 filter: Option<IotaObjectDataFilter>,
4250 ) -> IotaResult<Vec<ObjectInfo>> {
4251 if let Some(indexes) = &self.indexes {
4252 indexes.get_owner_objects(owner, cursor, limit, filter)
4253 } else {
4254 Err(IotaError::IndexStoreNotAvailable)
4255 }
4256 }
4257
4258 #[instrument(level = "trace", skip_all)]
4259 pub fn get_owned_coins_iterator_with_cursor(
4260 &self,
4261 owner: Address,
4262 cursor: (String, ObjectId),
4264 limit: usize,
4265 one_coin_type_only: bool,
4266 ) -> IotaResult<impl Iterator<Item = (String, ObjectId, CoinInfo)> + '_> {
4267 if let Some(indexes) = &self.indexes {
4268 indexes.get_owned_coins_iterator_with_cursor(owner, cursor, limit, one_coin_type_only)
4269 } else {
4270 Err(IotaError::IndexStoreNotAvailable)
4271 }
4272 }
4273
4274 #[instrument(level = "trace", skip_all)]
4275 pub fn get_owner_objects_iterator(
4276 &self,
4277 owner: Address,
4278 cursor: Option<ObjectId>,
4280 filter: Option<IotaObjectDataFilter>,
4281 ) -> IotaResult<impl Iterator<Item = ObjectInfo> + '_> {
4282 let cursor_u = cursor.unwrap_or(ObjectId::ZERO);
4283 if let Some(indexes) = &self.indexes {
4284 indexes.get_owner_objects_iterator(owner, cursor_u, filter)
4285 } else {
4286 Err(IotaError::IndexStoreNotAvailable)
4287 }
4288 }
4289
4290 #[instrument(level = "trace", skip_all)]
4291 pub fn get_move_objects<T>(&self, owner: Address, tag: StructTag) -> IotaResult<Vec<T>>
4292 where
4293 T: DeserializeOwned,
4294 {
4295 let object_ids = self
4296 .get_owner_objects_iterator(owner, None, None)?
4297 .filter(|o| match &o.type_ {
4298 ObjectType::Struct(s) => *s == tag,
4299 ObjectType::Package => false,
4300 })
4301 .map(|info| ObjectKey(info.object_id, info.version))
4302 .collect::<Vec<_>>();
4303 let mut move_objects = vec![];
4304
4305 let objects = self
4306 .get_object_store()
4307 .try_multi_get_objects_by_key(&object_ids)?;
4308
4309 for (o, id) in objects.into_iter().zip(object_ids) {
4310 let object = o.ok_or_else(|| {
4311 IotaError::from(UserInputError::ObjectNotFound {
4312 object_id: id.0,
4313 version: Some(id.1),
4314 })
4315 })?;
4316 let move_object = object.data.as_opt_struct().ok_or_else(|| {
4317 IotaError::from(UserInputError::MovePackageAsObject { object_id: id.0 })
4318 })?;
4319 move_objects.push(bcs::from_bytes(move_object.contents()).map_err(|e| {
4320 IotaError::ObjectDeserialization {
4321 error: format!("{e}"),
4322 }
4323 })?);
4324 }
4325 Ok(move_objects)
4326 }
4327
4328 #[instrument(level = "trace", skip_all)]
4329 pub fn get_dynamic_fields(
4330 &self,
4331 owner: ObjectId,
4332 cursor: Option<ObjectId>,
4334 limit: usize,
4335 ) -> IotaResult<Vec<(ObjectId, DynamicFieldInfo)>> {
4336 Ok(self
4337 .get_dynamic_fields_iterator(owner, cursor)?
4338 .take(limit)
4339 .collect::<Result<Vec<_>, _>>()?)
4340 }
4341
4342 fn get_dynamic_fields_iterator(
4343 &self,
4344 owner: ObjectId,
4345 cursor: Option<ObjectId>,
4347 ) -> IotaResult<impl Iterator<Item = Result<(ObjectId, DynamicFieldInfo), TypedStoreError>> + '_>
4348 {
4349 if let Some(indexes) = &self.indexes {
4350 indexes.get_dynamic_fields_iterator(owner, cursor)
4351 } else {
4352 Err(IotaError::IndexStoreNotAvailable)
4353 }
4354 }
4355
4356 #[instrument(level = "trace", skip_all)]
4357 pub fn get_dynamic_field_object_id(
4358 &self,
4359 owner: ObjectId,
4360 name_type: TypeTag,
4361 name_bcs_bytes: &[u8],
4362 ) -> IotaResult<Option<ObjectId>> {
4363 if let Some(indexes) = &self.indexes {
4364 indexes.get_dynamic_field_object_id(owner, name_type, name_bcs_bytes)
4365 } else {
4366 Err(IotaError::IndexStoreNotAvailable)
4367 }
4368 }
4369
4370 #[instrument(level = "trace", skip_all)]
4371 pub fn get_total_transaction_blocks(&self) -> IotaResult<u64> {
4372 Ok(self.get_indexes()?.next_sequence_number())
4373 }
4374
4375 #[instrument(level = "trace", skip_all)]
4376 pub async fn get_executed_transaction_and_effects(
4377 &self,
4378 digest: TransactionDigest,
4379 kv_store: Arc<TransactionKeyValueStore>,
4380 ) -> IotaResult<(Transaction, TransactionEffects)> {
4381 let transaction = kv_store.get_tx(digest).await?;
4382 let effects = kv_store.get_fx_by_tx_digest(digest).await?;
4383 Ok((transaction, effects))
4384 }
4385
4386 #[instrument(level = "trace", skip_all)]
4387 pub fn multi_get_checkpoint_by_sequence_number(
4388 &self,
4389 sequence_numbers: &[CheckpointSequenceNumber],
4390 ) -> IotaResult<Vec<Option<VerifiedCheckpoint>>> {
4391 Ok(self
4392 .checkpoint_store
4393 .multi_get_checkpoint_by_sequence_number(sequence_numbers)?)
4394 }
4395
4396 #[instrument(level = "trace", skip_all)]
4397 pub fn get_transaction_events(
4398 &self,
4399 digest: &TransactionDigest,
4400 ) -> IotaResult<TransactionEvents> {
4401 self.get_transaction_cache_reader()
4402 .try_get_events(digest)?
4403 .ok_or(IotaError::TransactionEventsNotFound { digest: *digest })
4404 }
4405
4406 pub fn get_transaction_input_objects(
4407 &self,
4408 effects: &TransactionEffects,
4409 ) -> anyhow::Result<Vec<Object>> {
4410 iota_types::storage::get_transaction_input_objects(self.get_object_store(), effects)
4411 .map_err(Into::into)
4412 }
4413
4414 pub fn get_transaction_output_objects(
4415 &self,
4416 effects: &TransactionEffects,
4417 ) -> anyhow::Result<Vec<Object>> {
4418 iota_types::storage::get_transaction_output_objects(self.get_object_store(), effects)
4419 .map_err(Into::into)
4420 }
4421
4422 fn get_indexes(&self) -> IotaResult<Arc<IndexStore>> {
4423 match &self.indexes {
4424 Some(i) => Ok(i.clone()),
4425 None => Err(IotaError::UnsupportedFeature {
4426 error: "extended object indexing is not enabled on this server".into(),
4427 }),
4428 }
4429 }
4430
4431 pub async fn get_transactions_for_tests(
4432 self: &Arc<Self>,
4433 filter: Option<TransactionFilter>,
4434 cursor: Option<TransactionDigest>,
4435 limit: Option<usize>,
4436 reverse: bool,
4437 ) -> IotaResult<Vec<TransactionDigest>> {
4438 let metrics = KeyValueStoreMetrics::new_for_tests();
4439 let kv_store = Arc::new(TransactionKeyValueStore::new(
4440 "rocksdb",
4441 metrics,
4442 self.clone(),
4443 ));
4444 self.get_transactions(&kv_store, filter, cursor, limit, reverse)
4445 .await
4446 }
4447
4448 #[instrument(level = "trace", skip_all)]
4449 pub async fn get_transactions(
4450 &self,
4451 kv_store: &Arc<TransactionKeyValueStore>,
4452 filter: Option<TransactionFilter>,
4453 cursor: Option<TransactionDigest>,
4455 limit: Option<usize>,
4456 reverse: bool,
4457 ) -> IotaResult<Vec<TransactionDigest>> {
4458 if let Some(TransactionFilter::Checkpoint(sequence_number)) = filter {
4459 let checkpoint_contents = kv_store.get_checkpoint_contents(sequence_number).await?;
4460 let iter = checkpoint_contents.iter().map(|c| c.transaction);
4461 if reverse {
4462 let iter = iter
4463 .rev()
4464 .skip_while(|d| cursor.is_some() && Some(*d) != cursor)
4465 .skip(usize::from(cursor.is_some()));
4466 return Ok(iter.take(limit.unwrap_or(usize::MAX)).collect());
4467 } else {
4468 let iter = iter
4469 .skip_while(|d| cursor.is_some() && Some(*d) != cursor)
4470 .skip(usize::from(cursor.is_some()));
4471 return Ok(iter.take(limit.unwrap_or(usize::MAX)).collect());
4472 }
4473 }
4474 self.get_indexes()?
4475 .get_transactions(filter, cursor, limit, reverse)
4476 }
4477
4478 pub fn get_checkpoint_store(&self) -> &Arc<CheckpointStore> {
4479 &self.checkpoint_store
4480 }
4481
4482 pub fn pruner(&self) -> &AuthorityStorePruner {
4485 &self.pruner
4486 }
4487
4488 pub fn get_latest_checkpoint_sequence_number(&self) -> IotaResult<CheckpointSequenceNumber> {
4489 self.get_checkpoint_store()
4490 .get_highest_executed_checkpoint_seq_number()?
4491 .ok_or(IotaError::UserInput {
4492 error: UserInputError::LatestCheckpointSequenceNumberNotFound,
4493 })
4494 }
4495
4496 #[cfg(msim)]
4497 pub fn get_highest_pruned_checkpoint_for_testing(
4498 &self,
4499 ) -> IotaResult<CheckpointSequenceNumber> {
4500 self.database_for_testing()
4501 .perpetual_tables
4502 .get_highest_pruned_checkpoint()
4503 .map(|c| c.unwrap_or(0))
4504 .map_err(Into::into)
4505 }
4506
4507 #[instrument(level = "trace", skip_all)]
4508 pub fn get_checkpoint_summary_by_sequence_number(
4509 &self,
4510 sequence_number: CheckpointSequenceNumber,
4511 ) -> IotaResult<CheckpointSummary> {
4512 let verified_checkpoint = self
4513 .get_checkpoint_store()
4514 .get_checkpoint_by_sequence_number(sequence_number)?;
4515 match verified_checkpoint {
4516 Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
4517 None => Err(IotaError::UserInput {
4518 error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4519 }),
4520 }
4521 }
4522
4523 #[instrument(level = "trace", skip_all)]
4524 pub fn get_checkpoint_summary_by_digest(
4525 &self,
4526 digest: CheckpointDigest,
4527 ) -> IotaResult<CheckpointSummary> {
4528 let verified_checkpoint = self
4529 .get_checkpoint_store()
4530 .get_checkpoint_by_digest(&digest)?;
4531 match verified_checkpoint {
4532 Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
4533 None => Err(IotaError::UserInput {
4534 error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
4535 }),
4536 }
4537 }
4538
4539 #[instrument(level = "trace", skip_all)]
4540 pub fn find_publish_txn_digest(&self, package_id: ObjectId) -> IotaResult<TransactionDigest> {
4541 if package_id.is_system_package() {
4542 return self.find_genesis_txn_digest();
4543 }
4544 Ok(self
4545 .get_object_read(&package_id)?
4546 .into_object()?
4547 .previous_transaction)
4548 }
4549
4550 #[instrument(level = "trace", skip_all)]
4551 pub fn find_genesis_txn_digest(&self) -> IotaResult<TransactionDigest> {
4552 let summary = self
4553 .get_verified_checkpoint_by_sequence_number(0)?
4554 .into_message();
4555 let content = self.get_checkpoint_contents(summary.contents_digest)?;
4556 let genesis_transaction = content.enumerate_transactions(&summary).next();
4557 Ok(genesis_transaction
4558 .ok_or(IotaError::UserInput {
4559 error: UserInputError::GenesisTransactionNotFound,
4560 })?
4561 .1
4562 .transaction)
4563 }
4564
4565 #[instrument(level = "trace", skip_all)]
4566 pub fn get_verified_checkpoint_by_sequence_number(
4567 &self,
4568 sequence_number: CheckpointSequenceNumber,
4569 ) -> IotaResult<VerifiedCheckpoint> {
4570 let verified_checkpoint = self
4571 .get_checkpoint_store()
4572 .get_checkpoint_by_sequence_number(sequence_number)?;
4573 match verified_checkpoint {
4574 Some(verified_checkpoint) => Ok(verified_checkpoint),
4575 None => Err(IotaError::UserInput {
4576 error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4577 }),
4578 }
4579 }
4580
4581 #[instrument(level = "trace", skip_all)]
4582 pub fn get_verified_checkpoint_summary_by_digest(
4583 &self,
4584 digest: CheckpointDigest,
4585 ) -> IotaResult<VerifiedCheckpoint> {
4586 let verified_checkpoint = self
4587 .get_checkpoint_store()
4588 .get_checkpoint_by_digest(&digest)?;
4589 match verified_checkpoint {
4590 Some(verified_checkpoint) => Ok(verified_checkpoint),
4591 None => Err(IotaError::UserInput {
4592 error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
4593 }),
4594 }
4595 }
4596
4597 #[instrument(level = "trace", skip_all)]
4598 pub fn get_checkpoint_contents(
4599 &self,
4600 digest: CheckpointContentsDigest,
4601 ) -> IotaResult<CheckpointContents> {
4602 self.get_checkpoint_store()
4603 .get_checkpoint_contents(&digest)?
4604 .ok_or(IotaError::UserInput {
4605 error: UserInputError::CheckpointContentsNotFound(digest),
4606 })
4607 }
4608
4609 #[instrument(level = "trace", skip_all)]
4610 pub fn get_checkpoint_contents_by_sequence_number(
4611 &self,
4612 sequence_number: CheckpointSequenceNumber,
4613 ) -> IotaResult<CheckpointContents> {
4614 let verified_checkpoint = self
4615 .get_checkpoint_store()
4616 .get_checkpoint_by_sequence_number(sequence_number)?;
4617 match verified_checkpoint {
4618 Some(verified_checkpoint) => {
4619 let contents_digest = verified_checkpoint.into_inner().contents_digest;
4620 self.get_checkpoint_contents(contents_digest)
4621 }
4622 None => Err(IotaError::UserInput {
4623 error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4624 }),
4625 }
4626 }
4627
4628 #[instrument(level = "trace", skip_all)]
4629 pub async fn query_events(
4630 &self,
4631 kv_store: &Arc<TransactionKeyValueStore>,
4632 query: EventFilter,
4633 cursor: Option<EventID>,
4635 limit: usize,
4636 descending: bool,
4637 ) -> IotaResult<Vec<IotaEvent>> {
4638 let index_store = self.get_indexes()?;
4639
4640 let (tx_num, event_num) = if let Some(cursor) = cursor.as_ref() {
4642 let tx_seq = index_store.get_transaction_seq(&cursor.tx_digest)?.ok_or(
4643 IotaError::TransactionNotFound {
4644 digest: cursor.tx_digest,
4645 },
4646 )?;
4647 (tx_seq, cursor.event_seq as usize)
4648 } else if descending {
4649 (u64::MAX, usize::MAX)
4650 } else {
4651 (0, 0)
4652 };
4653
4654 let limit = limit + 1;
4655 let mut event_keys = match query {
4656 EventFilter::All(filters) => {
4657 if filters.is_empty() {
4658 index_store.all_events(tx_num, event_num, limit, descending)?
4659 } else {
4660 return Err(IotaError::UserInput {
4661 error: UserInputError::Unsupported(
4662 "This query type does not currently support filter combinations"
4663 .to_string(),
4664 ),
4665 });
4666 }
4667 }
4668 EventFilter::Transaction(digest) => {
4669 index_store.events_by_transaction(&digest, tx_num, event_num, limit, descending)?
4670 }
4671 EventFilter::MoveModule { package, module } => {
4672 let module_id = ModuleId::new(
4673 AccountAddress::new(package.into_bytes()),
4674 move_core_types::identifier::Identifier::new(module.as_str()).unwrap(),
4675 );
4676 index_store.events_by_module_id(&module_id, tx_num, event_num, limit, descending)?
4677 }
4678 EventFilter::MoveEventType(struct_name) => index_store
4679 .events_by_move_event_struct_name(
4680 &struct_name,
4681 tx_num,
4682 event_num,
4683 limit,
4684 descending,
4685 )?,
4686 EventFilter::Sender(sender) => {
4687 index_store.events_by_sender(&sender, tx_num, event_num, limit, descending)?
4688 }
4689 EventFilter::TimeRange {
4690 start_time,
4691 end_time,
4692 } => index_store
4693 .event_iterator(start_time, end_time, tx_num, event_num, limit, descending)?,
4694 EventFilter::MoveEventModule { package, module } => index_store
4695 .events_by_move_event_module(
4696 &ModuleId::new(
4697 AccountAddress::new(package.into_bytes()),
4698 move_core_types::identifier::Identifier::new(module.as_str()).unwrap(),
4699 ),
4700 tx_num,
4701 event_num,
4702 limit,
4703 descending,
4704 )?,
4705 EventFilter::Package(_)
4707 | EventFilter::MoveEventField { .. }
4708 | EventFilter::Any(_)
4709 | EventFilter::And(_, _)
4710 | EventFilter::Or(_, _) => {
4711 return Err(IotaError::UserInput {
4712 error: UserInputError::Unsupported(
4713 "This query type is not supported by the full node.".to_string(),
4714 ),
4715 });
4716 }
4717 };
4718
4719 if cursor.is_some() {
4722 if !event_keys.is_empty() {
4723 event_keys.remove(0);
4724 }
4725 } else {
4726 event_keys.truncate(limit - 1);
4727 }
4728
4729 let transaction_digests = event_keys
4731 .iter()
4732 .map(|(_, digest, _, _)| *digest)
4733 .collect::<HashSet<_>>()
4734 .into_iter()
4735 .collect::<Vec<_>>();
4736
4737 let events = kv_store
4738 .multi_get_events_by_tx_digests(&transaction_digests)
4739 .await?;
4740
4741 let events_map: HashMap<_, _> =
4742 transaction_digests.iter().zip(events.into_iter()).collect();
4743
4744 let stored_events = event_keys
4745 .into_iter()
4746 .map(|k| {
4747 (
4748 k,
4749 events_map
4750 .get(&k.1)
4751 .expect("fetched digest is missing")
4752 .clone()
4753 .and_then(|e| e.get(k.2).cloned()),
4754 )
4755 })
4756 .map(
4757 |((_event_digest, tx_digest, event_seq, timestamp), event)| {
4758 event
4759 .map(|e| (e, tx_digest, event_seq, timestamp))
4760 .ok_or(IotaError::TransactionEventsNotFound { digest: tx_digest })
4761 },
4762 )
4763 .collect::<Result<Vec<_>, _>>()?;
4764
4765 let epoch_store = self.load_epoch_store_one_call_per_task();
4766 let backing_store = self.get_backing_package_store().as_ref();
4767 let mut layout_resolver = epoch_store
4768 .executor()
4769 .type_layout_resolver(Box::new(backing_store));
4770 let mut events = vec![];
4771 for (e, tx_digest, event_seq, timestamp) in stored_events.into_iter() {
4772 events.push(IotaEvent::try_from(
4773 e.clone(),
4774 tx_digest,
4775 event_seq as u64,
4776 Some(timestamp),
4777 layout_resolver.get_annotated_layout(&e.type_)?,
4778 )?)
4779 }
4780 Ok(events)
4781 }
4782
4783 pub fn insert_genesis_object(&self, object: Object) {
4784 self.get_reconfig_api()
4785 .try_insert_genesis_object(object)
4786 .expect("Cannot insert genesis object")
4787 }
4788
4789 pub fn insert_genesis_objects(&self, objects: &[Object]) {
4790 for o in objects {
4791 self.insert_genesis_object(o.clone());
4792 }
4793 }
4794
4795 #[instrument(level = "trace", skip_all)]
4797 pub fn get_transaction_status(
4798 &self,
4799 transaction_digest: &TransactionDigest,
4800 epoch_store: &Arc<AuthorityPerEpochStore>,
4801 ) -> IotaResult<Option<(SenderSignedData, TransactionStatus)>> {
4802 if let Some(effects) =
4804 self.get_signed_effects_and_maybe_resign(transaction_digest, epoch_store)?
4805 {
4806 if let Some(transaction) = self
4807 .get_transaction_cache_reader()
4808 .try_get_transaction_block(transaction_digest)?
4809 {
4810 let cert_sig = epoch_store.get_transaction_cert_sig(transaction_digest)?;
4811 let events = if effects.events_digest().is_some() {
4812 self.get_transaction_events(effects.transaction_digest())?
4813 } else {
4814 TransactionEvents::default()
4815 };
4816 return Ok(Some((
4817 (*transaction).clone().into_message(),
4818 TransactionStatus::Executed(cert_sig, effects.into_inner(), events),
4819 )));
4820 } else {
4821 debug!(tx_digest=?transaction_digest, "Signed effects exist but no transaction found");
4826 }
4827 }
4828 if let Some(signed) = epoch_store.get_signed_transaction(transaction_digest)? {
4829 self.metrics.tx_already_processed.inc();
4830 let (transaction, sig) = signed.into_inner().into_data_and_sig();
4831 Ok(Some((transaction, TransactionStatus::Signed(sig))))
4832 } else {
4833 Ok(None)
4834 }
4835 }
4836
4837 #[instrument(level = "trace", skip_all)]
4841 pub fn get_signed_effects_and_maybe_resign(
4842 &self,
4843 transaction_digest: &TransactionDigest,
4844 epoch_store: &Arc<AuthorityPerEpochStore>,
4845 ) -> IotaResult<Option<VerifiedSignedTransactionEffects>> {
4846 let effects = self
4847 .get_transaction_cache_reader()
4848 .try_get_executed_effects(transaction_digest)?;
4849 match effects {
4850 Some(effects) => {
4851 if effects.epoch() != epoch_store.epoch() {
4874 debug!(
4875 tx_digest=?transaction_digest,
4876 effects_epoch=?effects.epoch(),
4877 epoch=?epoch_store.epoch(),
4878 "Re-signing the effects with the current epoch"
4879 );
4880 }
4881 Ok(Some(self.sign_effects(effects, epoch_store)?))
4882 }
4883 None => Ok(None),
4884 }
4885 }
4886
4887 #[instrument(level = "trace", skip_all)]
4888 pub(crate) fn sign_effects(
4889 &self,
4890 effects: TransactionEffects,
4891 epoch_store: &Arc<AuthorityPerEpochStore>,
4892 ) -> IotaResult<VerifiedSignedTransactionEffects> {
4893 let tx_digest = *effects.transaction_digest();
4894 let signed_effects = match epoch_store.get_effects_signature(&tx_digest)? {
4895 Some(sig) => {
4896 debug_assert!(sig.epoch == epoch_store.epoch());
4897 SignedTransactionEffects::new_from_data_and_sig(effects, sig)
4898 }
4899 _ => {
4900 let sig = AuthoritySignInfo::new(
4901 epoch_store.epoch(),
4902 &effects,
4903 Intent::iota_app(IntentScope::TransactionEffects),
4904 self.name,
4905 &*self.secret,
4906 );
4907
4908 let effects = SignedTransactionEffects::new_from_data_and_sig(effects, sig.clone());
4909
4910 epoch_store.insert_effects_digest_and_signature(
4911 &tx_digest,
4912 effects.digest(),
4913 &sig,
4914 )?;
4915
4916 effects
4917 }
4918 };
4919
4920 Ok(VerifiedSignedTransactionEffects::new_unchecked(
4921 signed_effects,
4922 ))
4923 }
4924
4925 #[instrument(level = "trace", skip_all)]
4927 fn fullnode_only_get_tx_coins_for_indexing(
4928 &self,
4929 effects: &TransactionEffects,
4930 inner_temporary_store: &InnerTemporaryStore,
4931 epoch_store: &Arc<AuthorityPerEpochStore>,
4932 ) -> Option<TxCoins> {
4933 if self.indexes.is_none() || self.is_committee_validator(epoch_store) {
4934 return None;
4935 }
4936 let written_coin_objects = inner_temporary_store
4937 .written
4938 .iter()
4939 .filter_map(|(k, v)| {
4940 if v.is_coin() {
4941 Some((*k, v.clone()))
4942 } else {
4943 None
4944 }
4945 })
4946 .collect();
4947 let mut input_coin_objects = inner_temporary_store
4948 .input_objects
4949 .iter()
4950 .filter_map(|(k, v)| {
4951 if v.is_coin() {
4952 Some((*k, v.clone()))
4953 } else {
4954 None
4955 }
4956 })
4957 .collect::<ObjectMap>();
4958
4959 for (object_id, version) in effects.modified_at_versions() {
4964 if inner_temporary_store
4965 .loaded_runtime_objects
4966 .contains_key(&object_id)
4967 {
4968 if let Some(object) = self
4969 .get_object_store()
4970 .get_object_by_key(&object_id, version)
4971 {
4972 if object.is_coin() {
4973 input_coin_objects.insert(object_id, object);
4974 }
4975 }
4976 }
4977 }
4978
4979 Some((input_coin_objects, written_coin_objects))
4980 }
4981
4982 #[instrument(level = "trace", skip_all)]
4994 pub fn get_transaction_lock(
4995 &self,
4996 object_ref: &ObjectReference,
4997 epoch_store: &AuthorityPerEpochStore,
4998 ) -> IotaResult<Option<VerifiedSignedTransaction>> {
4999 let lock_info = self
5000 .get_object_cache_reader()
5001 .try_get_lock(*object_ref, epoch_store)?;
5002 let lock_info = match lock_info {
5003 ObjectLockStatus::LockedAtDifferentVersion { locked_ref } => {
5004 return Err(UserInputError::ObjectVersionUnavailableForConsumption {
5005 provided_obj_ref: *object_ref,
5006 current_version: locked_ref.version,
5007 }
5008 .into());
5009 }
5010 ObjectLockStatus::Initialized => {
5011 return Ok(None);
5012 }
5013 ObjectLockStatus::LockedToTx { locked_by_tx } => locked_by_tx,
5014 };
5015
5016 epoch_store.get_signed_transaction(&lock_info)
5017 }
5018
5019 pub fn try_get_objects(&self, objects: &[ObjectId]) -> IotaResult<Vec<Option<Object>>> {
5020 self.get_object_cache_reader().try_get_objects(objects)
5021 }
5022
5023 pub fn get_objects(&self, objects: &[ObjectId]) -> Vec<Option<Object>> {
5025 self.try_get_objects(objects)
5026 .expect("storage access failed")
5027 }
5028
5029 pub fn try_get_object_or_tombstone(
5030 &self,
5031 object_id: ObjectId,
5032 ) -> IotaResult<Option<ObjectReference>> {
5033 self.get_object_cache_reader()
5034 .try_get_latest_object_ref_or_tombstone(object_id)
5035 }
5036
5037 pub fn get_object_or_tombstone(&self, object_id: ObjectId) -> Option<ObjectReference> {
5039 self.try_get_object_or_tombstone(object_id)
5040 .expect("storage access failed")
5041 }
5042
5043 pub fn set_override_protocol_upgrade_buffer_stake(
5053 &self,
5054 expected_epoch: EpochId,
5055 buffer_stake_bps: u64,
5056 ) -> IotaResult {
5057 let epoch_store = self.load_epoch_store_one_call_per_task();
5058 let actual_epoch = epoch_store.epoch();
5059 if actual_epoch != expected_epoch {
5060 return Err(IotaError::WrongEpoch {
5061 expected_epoch,
5062 actual_epoch,
5063 });
5064 }
5065
5066 epoch_store.set_override_protocol_upgrade_buffer_stake(buffer_stake_bps)
5067 }
5068
5069 pub fn clear_override_protocol_upgrade_buffer_stake(
5070 &self,
5071 expected_epoch: EpochId,
5072 ) -> IotaResult {
5073 let epoch_store = self.load_epoch_store_one_call_per_task();
5074 let actual_epoch = epoch_store.epoch();
5075 if actual_epoch != expected_epoch {
5076 return Err(IotaError::WrongEpoch {
5077 expected_epoch,
5078 actual_epoch,
5079 });
5080 }
5081
5082 epoch_store.clear_override_protocol_upgrade_buffer_stake()
5083 }
5084
5085 pub async fn get_available_system_packages(
5089 &self,
5090 binary_config: &BinaryConfig,
5091 ) -> Vec<ObjectReference> {
5092 let mut results = vec![];
5093
5094 let system_packages = BuiltInFramework::iter_system_packages();
5095
5096 #[cfg(msim)]
5098 let extra_packages = framework_injection::get_extra_packages(self.name);
5099 #[cfg(msim)]
5100 let system_packages = {
5101 let mut packages: Vec<_> = system_packages.collect();
5102 packages.extend(extra_packages.iter());
5103 packages
5104 };
5105
5106 for system_package in system_packages {
5107 let modules = system_package.modules().to_vec();
5108 #[cfg(msim)]
5110 let modules = framework_injection::get_override_modules(&system_package.id, self.name)
5111 .unwrap_or(modules);
5112
5113 let Some(obj_ref) = iota_framework::compare_system_package(
5114 &self.get_object_store(),
5115 &system_package.id,
5116 &modules,
5117 system_package.dependencies.to_vec(),
5118 binary_config,
5119 )
5120 .await
5121 else {
5122 return vec![];
5123 };
5124 results.push(obj_ref);
5125 }
5126
5127 results
5128 }
5129
5130 async fn get_system_package_bytes(
5147 &self,
5148 system_packages: Vec<ObjectReference>,
5149 binary_config: &BinaryConfig,
5150 ) -> Option<Vec<SystemPackage>> {
5151 let ids: Vec<_> = system_packages
5152 .iter()
5153 .map(|object_ref| object_ref.object_id)
5154 .collect();
5155 let objects = self.get_objects(&ids);
5156
5157 let mut res = Vec::with_capacity(system_packages.len());
5158 for (system_package_ref, object) in system_packages.into_iter().zip(objects.iter()) {
5159 let prev_transaction = match object {
5160 Some(cur_object) if cur_object.object_ref() == system_package_ref => {
5161 info!(
5163 "Framework {} does not need updating",
5164 system_package_ref.object_id
5165 );
5166 continue;
5167 }
5168
5169 Some(cur_object) => cur_object.previous_transaction,
5170 None => TransactionDigest::GENESIS_MARKER,
5171 };
5172
5173 #[cfg(msim)]
5174 let FrameworkSystemPackage {
5175 id: _,
5176 bytes,
5177 dependencies,
5178 } = framework_injection::get_override_system_package(
5179 &system_package_ref.object_id,
5180 self.name,
5181 )
5182 .unwrap_or_else(|| {
5183 BuiltInFramework::get_package_by_id(&system_package_ref.object_id).clone()
5184 });
5185
5186 #[cfg(not(msim))]
5187 let FrameworkSystemPackage {
5188 id: _,
5189 bytes,
5190 dependencies,
5191 } = BuiltInFramework::get_package_by_id(&system_package_ref.object_id).clone();
5192
5193 let modules: Vec<_> = bytes
5194 .iter()
5195 .map(|m| CompiledModule::deserialize_with_config(m, binary_config).unwrap())
5196 .collect();
5197
5198 let new_object = Object::new_system_package(
5199 &modules,
5200 system_package_ref.version,
5201 dependencies.clone(),
5202 prev_transaction,
5203 );
5204
5205 let new_ref = new_object.object_ref();
5206 if new_ref != system_package_ref {
5207 error!(
5208 "Framework mismatch -- binary: {new_ref:?}\n upgrade: {system_package_ref:?}"
5209 );
5210 return None;
5211 }
5212
5213 res.push(SystemPackage {
5214 version: system_package_ref.version,
5215 modules: bytes,
5216 dependencies,
5217 });
5218 }
5219
5220 Some(res)
5221 }
5222
5223 fn is_protocol_version_supported_v1(
5227 proposed_protocol_version: ProtocolVersion,
5228 committee: &Committee,
5229 capabilities: Vec<AuthorityCapabilitiesV1>,
5230 mut buffer_stake_bps: u64,
5231 ) -> Option<(ProtocolVersion, Digest, Vec<ObjectReference>)> {
5232 if buffer_stake_bps > 10000 {
5233 warn!("clamping buffer_stake_bps to 10000");
5234 buffer_stake_bps = 10000;
5235 }
5236
5237 let mut desired_upgrades: Vec<_> = capabilities
5240 .into_iter()
5241 .filter_map(|mut cap| {
5242 if cap.available_system_packages.is_empty() {
5244 return None;
5245 }
5246
5247 cap.available_system_packages.sort();
5248
5249 info!(
5250 "validator {:?} supports {:?} with system packages: {:?}",
5251 cap.authority.concise(),
5252 cap.supported_protocol_versions,
5253 cap.available_system_packages,
5254 );
5255
5256 cap.supported_protocol_versions
5260 .get_version_digest(proposed_protocol_version)
5261 .map(|digest| (digest, cap.available_system_packages, cap.authority))
5262 })
5263 .collect();
5264
5265 desired_upgrades.sort();
5268 desired_upgrades
5269 .into_iter()
5270 .chunk_by(|(digest, packages, _authority)| (*digest, packages.clone()))
5271 .into_iter()
5272 .find_map(|((digest, packages), group)| {
5273 assert!(!packages.is_empty());
5275
5276 let mut stake_aggregator: StakeAggregator<(), true> =
5277 StakeAggregator::new(Arc::new(committee.clone()));
5278
5279 for (_, _, authority) in group {
5280 stake_aggregator.insert_generic(authority, ());
5281 }
5282
5283 let total_votes = stake_aggregator.total_votes();
5284 let quorum_threshold = committee.quorum_threshold();
5285 let effective_threshold = committee.effective_threshold(buffer_stake_bps);
5286
5287 info!(
5288 protocol_config_digest = ?digest,
5289 ?total_votes,
5290 ?quorum_threshold,
5291 ?buffer_stake_bps,
5292 ?effective_threshold,
5293 ?proposed_protocol_version,
5294 ?packages,
5295 "support for upgrade"
5296 );
5297
5298 let has_support = total_votes >= effective_threshold;
5299 has_support.then_some((proposed_protocol_version, digest, packages))
5300 })
5301 }
5302
5303 fn choose_protocol_version_and_system_packages_v1(
5307 current_protocol_version: ProtocolVersion,
5308 current_protocol_digest: Digest,
5309 committee: &Committee,
5310 capabilities: Vec<AuthorityCapabilitiesV1>,
5311 buffer_stake_bps: u64,
5312 ) -> (ProtocolVersion, Digest, Vec<ObjectReference>) {
5313 let mut next_protocol_version = current_protocol_version;
5314 let mut system_packages = vec![];
5315 let mut protocol_version_digest = current_protocol_digest;
5316
5317 while let Some((version, digest, packages)) = Self::is_protocol_version_supported_v1(
5321 next_protocol_version + 1,
5322 committee,
5323 capabilities.clone(),
5324 buffer_stake_bps,
5325 ) {
5326 next_protocol_version = version;
5327 protocol_version_digest = digest;
5328 system_packages = packages;
5329 }
5330
5331 (
5332 next_protocol_version,
5333 protocol_version_digest,
5334 system_packages,
5335 )
5336 }
5337
5338 fn get_validators_supporting_protocol_version(
5343 target_protocol_version: ProtocolVersion,
5344 target_digest: Digest,
5345 active_validators: &[AuthorityPublicKey],
5346 capabilities: &[AuthorityCapabilitiesV1],
5347 ) -> Vec<u64> {
5348 let mut eligible_validators = Vec::new();
5349
5350 for capability in capabilities {
5351 if let Some(digest) = capability
5353 .supported_protocol_versions
5354 .get_version_digest(target_protocol_version)
5355 {
5356 if digest == target_digest {
5357 if let Some(index) = active_validators
5359 .iter()
5360 .position(|name| AuthorityName::from(name) == capability.authority)
5361 {
5362 eligible_validators.push(index as u64);
5363 }
5364 }
5365 }
5366 }
5367
5368 eligible_validators.sort();
5370 eligible_validators
5371 }
5372
5373 fn calculate_eligible_validators_weight(
5378 eligible_validator_indices: &[u64],
5379 active_validators: &[AuthorityPublicKey],
5380 committee: &Committee,
5381 ) -> u64 {
5382 let mut total_weight = 0u64;
5383
5384 for &index in eligible_validator_indices {
5385 let authority_pubkey = &active_validators[index as usize];
5386 if let Some((_, weight)) = committee
5388 .members()
5389 .find(|(name, _)| *name == AuthorityName::from(authority_pubkey))
5390 {
5391 total_weight += weight;
5392 }
5393 }
5394
5395 total_weight
5396 }
5397
5398 #[instrument(level = "error", skip_all)]
5411 pub async fn create_and_execute_advance_epoch_tx(
5412 &self,
5413 epoch_store: &Arc<AuthorityPerEpochStore>,
5414 gas_cost_summary: &GasCostSummary,
5415 checkpoint: CheckpointSequenceNumber,
5416 epoch_start_timestamp_ms: CheckpointTimestamp,
5417 scores: Vec<u64>,
5418 ) -> anyhow::Result<(
5419 IotaSystemState,
5420 Option<SystemEpochInfoEvent>,
5421 TransactionEffects,
5422 )> {
5423 let mut txns = Vec::new();
5424
5425 let next_epoch = epoch_store.epoch() + 1;
5426
5427 let buffer_stake_bps = epoch_store.get_effective_buffer_stake_bps();
5428 let authority_capabilities = epoch_store
5429 .get_capabilities_v1()
5430 .expect("read capabilities from db cannot fail");
5431 let (next_epoch_protocol_version, next_epoch_protocol_digest, next_epoch_system_packages) =
5432 Self::choose_protocol_version_and_system_packages_v1(
5433 epoch_store.protocol_version(),
5434 SupportedProtocolVersionsWithHashes::protocol_config_digest(
5435 epoch_store.protocol_config(),
5436 ),
5437 epoch_store.committee(),
5438 authority_capabilities.clone(),
5439 buffer_stake_bps,
5440 );
5441
5442 let config = epoch_store.protocol_config();
5446 let binary_config = to_binary_config(config);
5447 let Some(next_epoch_system_package_bytes) = self
5448 .get_system_package_bytes(next_epoch_system_packages.clone(), &binary_config)
5449 .await
5450 else {
5451 error!(
5452 "upgraded system packages {:?} are not locally available, cannot create \
5453 ChangeEpochTx. validator binary must be upgraded to the correct version!",
5454 next_epoch_system_packages
5455 );
5456 bail!("missing system packages: cannot form ChangeEpochTx");
5466 };
5467
5468 if config.select_committee_from_eligible_validators() {
5471 let active_validators = epoch_store.epoch_start_state().get_active_validators();
5473
5474 let mut eligible_active_validators = (0..active_validators.len() as u64).collect();
5475
5476 if config.select_committee_supporting_next_epoch_version() {
5480 eligible_active_validators = Self::get_validators_supporting_protocol_version(
5481 next_epoch_protocol_version,
5482 next_epoch_protocol_digest,
5483 &active_validators,
5484 &authority_capabilities,
5485 );
5486
5487 let eligible_validators_weight = Self::calculate_eligible_validators_weight(
5489 &eligible_active_validators,
5490 &active_validators,
5491 epoch_store.committee(),
5492 );
5493
5494 let committee = epoch_store.committee();
5498 let effective_threshold = committee.effective_threshold(buffer_stake_bps);
5499
5500 if eligible_validators_weight < effective_threshold {
5501 error!(
5502 "Eligible validators weight {eligible_validators_weight} is less than effective threshold {effective_threshold}. \
5503 This could indicate a bug in validator selection logic or inconsistency with protocol version decision.",
5504 );
5505 eligible_active_validators = (0..active_validators.len() as u64).collect();
5508 }
5509 }
5510
5511 if config.pass_validator_scores_to_advance_epoch() {
5514 txns.push(EndOfEpochTransactionKind::new_change_epoch_v4(
5515 next_epoch,
5516 next_epoch_protocol_version.as_u64(),
5517 gas_cost_summary.storage_cost,
5518 gas_cost_summary.computation_cost,
5519 gas_cost_summary.computation_cost_burned,
5520 gas_cost_summary.storage_rebate,
5521 gas_cost_summary.non_refundable_storage_fee,
5522 epoch_start_timestamp_ms,
5523 next_epoch_system_package_bytes,
5524 eligible_active_validators,
5525 scores,
5526 config.adjust_rewards_by_score(),
5527 ));
5528 } else {
5529 txns.push(EndOfEpochTransactionKind::new_change_epoch_v3(
5530 next_epoch,
5531 next_epoch_protocol_version.as_u64(),
5532 gas_cost_summary.storage_cost,
5533 gas_cost_summary.computation_cost,
5534 gas_cost_summary.computation_cost_burned,
5535 gas_cost_summary.storage_rebate,
5536 gas_cost_summary.non_refundable_storage_fee,
5537 epoch_start_timestamp_ms,
5538 next_epoch_system_package_bytes,
5539 eligible_active_validators,
5540 ));
5541 }
5542 } else if config.protocol_defined_base_fee()
5543 && config.max_committee_members_count_as_option().is_some()
5544 {
5545 txns.push(EndOfEpochTransactionKind::new_change_epoch_v2(
5546 next_epoch,
5547 next_epoch_protocol_version.as_u64(),
5548 gas_cost_summary.storage_cost,
5549 gas_cost_summary.computation_cost,
5550 gas_cost_summary.computation_cost_burned,
5551 gas_cost_summary.storage_rebate,
5552 gas_cost_summary.non_refundable_storage_fee,
5553 epoch_start_timestamp_ms,
5554 next_epoch_system_package_bytes,
5555 ));
5556 } else {
5557 txns.push(EndOfEpochTransactionKind::new_change_epoch(
5558 next_epoch,
5559 next_epoch_protocol_version.as_u64(),
5560 gas_cost_summary.storage_cost,
5561 gas_cost_summary.computation_cost,
5562 gas_cost_summary.storage_rebate,
5563 gas_cost_summary.non_refundable_storage_fee,
5564 epoch_start_timestamp_ms,
5565 next_epoch_system_package_bytes,
5566 ));
5567 }
5568
5569 let tx = VerifiedTransaction::new_end_of_epoch_transaction(txns);
5570
5571 let executable_tx = VerifiedExecutableTransaction::new_from_checkpoint(
5572 tx.clone(),
5573 epoch_store.epoch(),
5574 checkpoint,
5575 );
5576
5577 let tx_digest = executable_tx.digest();
5578
5579 info!(
5580 ?next_epoch,
5581 ?next_epoch_protocol_version,
5582 ?next_epoch_system_packages,
5583 computation_cost=?gas_cost_summary.computation_cost,
5584 computation_cost_burned=?gas_cost_summary.computation_cost_burned,
5585 storage_cost=?gas_cost_summary.storage_cost,
5586 storage_rebate=?gas_cost_summary.storage_rebate,
5587 non_refundable_storage_fee=?gas_cost_summary.non_refundable_storage_fee,
5588 ?tx_digest,
5589 "Creating advance epoch transaction"
5590 );
5591
5592 fail_point_async!("change_epoch_tx_delay");
5593 let tx_lock = epoch_store.acquire_tx_lock(tx_digest);
5594
5595 if self
5599 .get_transaction_cache_reader()
5600 .try_is_tx_already_executed(tx_digest)?
5601 {
5602 warn!("change epoch tx has already been executed via state sync");
5603 bail!("change epoch tx has already been executed via state sync",);
5604 }
5605
5606 let execution_guard = self.execution_lock_for_executable_transaction(&executable_tx)?;
5607
5608 epoch_store.assign_shared_object_versions_idempotent(
5612 self.get_object_cache_reader().as_ref(),
5613 std::slice::from_ref(&executable_tx),
5614 )?;
5615
5616 let (input_objects, _) =
5617 self.read_objects_for_execution(&tx_lock, &executable_tx, epoch_store)?;
5618
5619 let (temporary_store, effects, _execution_error_opt) = self.execute_transaction(
5620 &execution_guard,
5621 &executable_tx,
5622 input_objects,
5623 vec![],
5624 epoch_store,
5625 )?;
5626 let system_obj = get_iota_system_state(&temporary_store.written)
5627 .expect("change epoch tx must write to system object");
5628 let system_epoch_info_event = temporary_store
5630 .events
5631 .0
5632 .into_iter()
5633 .find(|event| event.is_system_epoch_info_event())
5634 .map(SystemEpochInfoEvent::from);
5635 assert!(system_epoch_info_event.is_some() || system_obj.safe_mode());
5638
5639 self.get_state_sync_store()
5643 .try_insert_transaction_and_effects(&tx, &effects)
5644 .map_err(|err| {
5645 let err: anyhow::Error = err.into();
5646 err
5647 })?;
5648
5649 info!(
5650 "Effects summary of the change epoch transaction: {:?}",
5651 effects.summary_for_debug()
5652 );
5653 epoch_store.record_checkpoint_builder_is_safe_mode_metric(system_obj.safe_mode());
5654 assert!(effects.status().is_success());
5656 Ok((system_obj, system_epoch_info_event, effects))
5657 }
5658
5659 #[instrument(level = "error", skip_all)]
5663 async fn revert_uncommitted_epoch_transactions(
5664 &self,
5665 epoch_store: &AuthorityPerEpochStore,
5666 ) -> IotaResult {
5667 {
5668 let state = epoch_store.get_reconfig_state_write_lock_guard();
5669 if state.should_accept_user_certs() {
5670 epoch_store.close_user_certs(state);
5679 }
5680 }
5682
5683 if !epoch_store.protocol_config().enable_pcool_flow() {
5686 let pending_certificates = epoch_store.pending_consensus_certificates();
5687 info!(
5688 "Reverting {} locally executed transactions that was not included in the epoch: \
5689 {:?}",
5690 pending_certificates.len(),
5691 pending_certificates,
5692 );
5693 for digest in pending_certificates {
5694 if epoch_store.is_transaction_executed_in_checkpoint(&digest)? {
5695 info!(
5696 "Not reverting pending consensus transaction {:?} - it was included in \
5697 checkpoint",
5698 digest
5699 );
5700 continue;
5701 }
5702 info!("Reverting {:?} at the end of epoch", digest);
5703 epoch_store.revert_executed_transaction(&digest)?;
5704 self.get_reconfig_api().try_revert_state_update(&digest)?;
5705 }
5706 info!("All uncommitted local transactions reverted");
5707 } else {
5708 info!("P-COOL mode: skipping revert of uncommitted epoch transactions");
5709 }
5710
5711 Ok(())
5712 }
5713
5714 #[instrument(level = "error", skip_all)]
5715 async fn reopen_epoch_db(
5716 &self,
5717 cur_epoch_store: &AuthorityPerEpochStore,
5718 new_committee: Committee,
5719 epoch_start_configuration: EpochStartConfiguration,
5720 expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
5721 epoch_last_checkpoint: CheckpointSequenceNumber,
5722 ) -> IotaResult<Arc<AuthorityPerEpochStore>> {
5723 let new_epoch = new_committee.epoch;
5724 info!(new_epoch = ?new_epoch, "re-opening AuthorityEpochTables for new epoch");
5725 assert_eq!(
5726 epoch_start_configuration.epoch_start_state().epoch(),
5727 new_committee.epoch
5728 );
5729 fail_point!("before-open-new-epoch-store");
5730 let new_epoch_store = cur_epoch_store.new_at_next_epoch(
5731 self.name,
5732 new_committee,
5733 epoch_start_configuration,
5734 self.get_backing_package_store().clone(),
5735 expensive_safety_check_config,
5736 epoch_last_checkpoint,
5737 )?;
5738 self.epoch_store.store(new_epoch_store.clone());
5739 Ok(new_epoch_store)
5740 }
5741
5742 fn check_move_account_for_execution(
5750 &self,
5751 auth_account_object_id: ObjectId,
5752 auth_account_object_seq_number: Option<Version>,
5753 auth_account_object_digest: Option<ObjectDigest>,
5754 account_object: ObjectReadResult,
5755 signer: &Address,
5756 ) -> AuthenticatorFunctionRefForExecution {
5757 self.check_move_account(
5758 auth_account_object_id,
5759 auth_account_object_seq_number,
5760 auth_account_object_digest,
5761 account_object,
5762 signer,
5763 true,
5764 )
5765 .expect("move account checks cannot fail during execution")
5766 }
5767
5768 fn check_move_account_for_validation(
5772 &self,
5773 auth_account_object_id: ObjectId,
5774 auth_account_object_seq_number: Option<Version>,
5775 auth_account_object_digest: Option<ObjectDigest>,
5776 account_object: ObjectReadResult,
5777 signer: &Address,
5778 ) -> IotaResult<AuthenticatorFunctionRefForExecution> {
5779 self.check_move_account(
5780 auth_account_object_id,
5781 auth_account_object_seq_number,
5782 auth_account_object_digest,
5783 account_object,
5784 signer,
5785 false,
5786 )
5787 }
5788
5789 fn check_move_account(
5796 &self,
5797 auth_account_object_id: ObjectId,
5798 auth_account_object_seq_number: Option<Version>,
5799 auth_account_object_digest: Option<ObjectDigest>,
5800 account_object: ObjectReadResult,
5801 signer: &Address,
5802 is_execution: bool,
5803 ) -> IotaResult<AuthenticatorFunctionRefForExecution> {
5804 let auth_account_object_seq_number = match (&account_object.object, is_execution) {
5805 (ObjectReadResultKind::Object(object), _) => {
5809 let account_object_addr = Address::from(auth_account_object_id);
5810 fp_ensure!(
5811 signer == &account_object_addr,
5812 UserInputError::IncorrectUserSignature {
5813 error: format!("Move authenticator is trying to unlock {account_object_addr:?}, but given signer address is {signer:?}")
5814 }
5815 .into()
5816 );
5817
5818 fp_ensure!(
5819 object.is_shared() || object.is_immutable(),
5820 UserInputError::AccountObjectNotSupported {
5821 object_id: auth_account_object_id
5822 }
5823 .into()
5824 );
5825
5826 let auth_account_object_seq_number =
5827 if let Some(auth_account_object_seq_number) = auth_account_object_seq_number {
5828 let account_object_version = object.version();
5829
5830 fp_ensure!(
5831 account_object_version == auth_account_object_seq_number,
5832 UserInputError::AccountObjectVersionMismatch {
5833 object_id: auth_account_object_id,
5834 expected_version: auth_account_object_seq_number,
5835 actual_version: account_object_version,
5836 }
5837 .into()
5838 );
5839
5840 auth_account_object_seq_number
5841 } else {
5842 object.version()
5843 };
5844
5845 if let Some(auth_account_object_digest) = auth_account_object_digest {
5846 let expected_digest = object.digest();
5847 fp_ensure!(
5848 expected_digest == auth_account_object_digest,
5849 UserInputError::InvalidAccountObjectDigest {
5850 object_id: auth_account_object_id,
5851 expected_digest,
5852 actual_digest: auth_account_object_digest,
5853 }
5854 .into()
5855 );
5856 }
5857
5858 Ok(auth_account_object_seq_number)
5859 }
5860 (ObjectReadResultKind::DeletedSharedObject(version, digest), false) => {
5863 Err(UserInputError::AccountObjectDeleted {
5864 account_id: account_object.id(),
5865 account_version: *version,
5866 transaction_digest: *digest,
5867 })
5868 }
5869 (ObjectReadResultKind::CancelledTransactionSharedObject(version), false) => {
5873 Err(UserInputError::AccountObjectInCanceledTransaction {
5874 account_id: account_object.id(),
5875 account_version: *version,
5876 })
5877 }
5878 (ObjectReadResultKind::DeletedSharedObject(version, _), true) => Ok(*version),
5883 (ObjectReadResultKind::CancelledTransactionSharedObject(version), true) => Ok(*version),
5889 }?;
5890
5891 let authenticator_function_ref_field_id =
5892 derive_authenticator_function_ref_v1_dynamic_field_id(auth_account_object_id)?;
5893
5894 let authenticator_function_ref_field = self
5895 .get_object_cache_reader()
5896 .try_find_object_lt_or_eq_version(
5897 authenticator_function_ref_field_id,
5898 auth_account_object_seq_number,
5899 )?;
5900
5901 if let Some(authenticator_function_ref_field_obj) = authenticator_function_ref_field {
5902 Ok(authenticator_function_ref_v1_from_dynamic_field_object(
5903 auth_account_object_id,
5904 &authenticator_function_ref_field_obj,
5905 )?)
5906 } else {
5907 Err(UserInputError::MoveAuthenticatorNotFound {
5908 authenticator_function_ref_id: authenticator_function_ref_field_id,
5909 account_object_id: auth_account_object_id,
5910 account_object_version: auth_account_object_seq_number,
5911 }
5912 .into())
5913 }
5914 }
5915
5916 #[allow(clippy::type_complexity)]
5917 fn read_objects_for_validation(
5918 &self,
5919 transaction: &VerifiedTransaction,
5920 epoch: u64,
5921 ) -> IotaResult<(
5922 InputObjects,
5923 ReceivingObjects,
5924 Vec<(InputObjects, ObjectReadResult)>,
5925 )> {
5926 let (input_objects, tx_receiving_objects) = self.input_loader.read_objects_for_signing(
5927 Some(transaction.digest()),
5928 &transaction.collect_all_input_object_kind_for_reading()?,
5929 &transaction.data().transaction().receiving_objects(),
5930 epoch,
5931 )?;
5932
5933 transaction
5934 .split_input_objects_into_groups_for_reading(input_objects)
5935 .map(|(tx_input_objects, per_authenticator_inputs)| {
5936 (
5937 tx_input_objects,
5938 tx_receiving_objects,
5939 per_authenticator_inputs,
5940 )
5941 })
5942 }
5943
5944 #[allow(clippy::type_complexity)]
5945 fn check_transaction_inputs_for_validation(
5946 &self,
5947 protocol_config: &ProtocolConfig,
5948 reference_gas_price: u64,
5949 tx_data: &TransactionData,
5950 tx_input_objects: InputObjects,
5951 tx_receiving_objects: &ReceivingObjects,
5952 move_authenticators: &Vec<&MoveAuthenticator>,
5953 per_authenticator_inputs: Vec<(InputObjects, ObjectReadResult)>,
5954 ) -> IotaResult<(
5955 IotaGasStatus,
5956 CheckedInputObjects,
5957 Vec<(CheckedInputObjects, AuthenticatorFunctionRef)>,
5958 )> {
5959 let authenticator_gas_budget = if move_authenticators.is_empty() {
5960 0
5961 } else {
5962 protocol_config.max_auth_gas()
5965 };
5966
5967 debug_assert_eq!(
5968 move_authenticators.len(),
5969 per_authenticator_inputs.len(),
5970 "Move authenticators amount must match the number of authenticator inputs"
5971 );
5972
5973 let per_authenticator_checked_inputs = move_authenticators
5974 .iter()
5975 .zip(per_authenticator_inputs)
5976 .map(
5977 |(move_authenticator, (authenticator_input_objects, account_object))| {
5978 let (
5980 auth_account_object_id,
5981 auth_account_object_seq_number,
5982 auth_account_object_digest,
5983 ) = move_authenticator.object_to_authenticate_components()?;
5984
5985 let signer = move_authenticator.address();
5986
5987 let AuthenticatorFunctionRefForExecution {
5989 authenticator_function_ref,
5990 ..
5991 } = self.check_move_account_for_validation(
5992 auth_account_object_id,
5993 auth_account_object_seq_number,
5994 auth_account_object_digest,
5995 account_object,
5996 &signer,
5997 )?;
5998
5999 let authenticator_checked_input_objects =
6001 iota_transaction_checks::check_move_authenticator_input_for_validation(
6002 authenticator_input_objects,
6003 )?;
6004
6005 Ok((
6006 authenticator_checked_input_objects,
6007 authenticator_function_ref,
6008 ))
6009 },
6010 )
6011 .collect::<IotaResult<Vec<_>>>()?;
6012
6013 let (gas_status, tx_checked_input_objects) =
6015 iota_transaction_checks::check_transaction_input(
6016 protocol_config,
6017 reference_gas_price,
6018 tx_data,
6019 tx_input_objects,
6020 tx_receiving_objects,
6021 &self.metrics.bytecode_verifier_metrics,
6022 &self.config.verifier_signing_config,
6023 authenticator_gas_budget,
6024 )?;
6025
6026 Ok((
6027 gas_status,
6028 tx_checked_input_objects,
6029 per_authenticator_checked_inputs,
6030 ))
6031 }
6032
6033 #[cfg(test)]
6034 pub(crate) fn iter_live_object_set_for_testing(
6035 &self,
6036 ) -> impl Iterator<Item = authority_store_tables::LiveObject> + '_ {
6037 self.get_global_state_hash_store()
6038 .iter_cached_live_object_set_for_testing()
6039 }
6040
6041 #[cfg(test)]
6042 pub(crate) fn shutdown_execution_for_test(&self) {
6043 self.tx_execution_shutdown
6044 .lock()
6045 .take()
6046 .unwrap()
6047 .send(())
6048 .unwrap();
6049 }
6050
6051 pub async fn insert_objects_unsafe_for_testing_only(&self, objects: &[Object]) {
6054 self.get_reconfig_api().bulk_insert_genesis_objects(objects);
6055 self.get_object_cache_reader()
6056 .force_reload_system_packages(&BuiltInFramework::all_package_ids());
6057 self.get_reconfig_api()
6058 .clear_state_end_of_epoch(&self.execution_lock_for_reconfiguration().await);
6059 }
6060}
6061
6062pub struct RandomnessRoundReceiver {
6063 authority_state: Arc<AuthorityState>,
6064 randomness_rx: mpsc::Receiver<(EpochId, RandomnessRound, Vec<u8>)>,
6065}
6066
6067impl RandomnessRoundReceiver {
6068 pub fn spawn(
6069 authority_state: Arc<AuthorityState>,
6070 randomness_rx: mpsc::Receiver<(EpochId, RandomnessRound, Vec<u8>)>,
6071 ) -> JoinHandle<()> {
6072 let rrr = RandomnessRoundReceiver {
6073 authority_state,
6074 randomness_rx,
6075 };
6076 spawn_monitored_task!(rrr.run())
6077 }
6078
6079 async fn run(mut self) {
6080 info!("RandomnessRoundReceiver event loop started");
6081
6082 loop {
6083 tokio::select! {
6084 maybe_recv = self.randomness_rx.recv() => {
6085 if let Some((epoch, round, bytes)) = maybe_recv {
6086 self.handle_new_randomness(epoch, round, bytes).await;
6087 } else {
6088 break;
6089 }
6090 },
6091 }
6092 }
6093
6094 info!("RandomnessRoundReceiver event loop ended");
6095 }
6096
6097 #[instrument(level = "debug", skip_all, fields(?epoch, ?round))]
6098 async fn handle_new_randomness(&self, epoch: EpochId, round: RandomnessRound, bytes: Vec<u8>) {
6099 fail_point_async!("randomness-delay");
6100
6101 let epoch_store = self.authority_state.load_epoch_store_one_call_per_task();
6102 if epoch_store.epoch() != epoch {
6103 warn!(
6104 "dropping randomness for epoch {epoch}, round {round}, because we are in epoch {}",
6105 epoch_store.epoch()
6106 );
6107 return;
6108 }
6109 let transaction = VerifiedTransaction::new_randomness_state_update(
6110 epoch,
6111 round,
6112 bytes,
6113 epoch_store
6114 .epoch_start_config()
6115 .randomness_obj_initial_shared_version(),
6116 );
6117 debug!(
6118 "created randomness state update transaction with digest: {:?}",
6119 transaction.digest()
6120 );
6121 let transaction = VerifiedExecutableTransaction::new_system(transaction, epoch);
6122 let digest = *transaction.digest();
6123
6124 self.authority_state
6129 .get_cache_commit()
6130 .persist_transaction(&transaction);
6131
6132 self.authority_state
6134 .transaction_manager()
6135 .enqueue(vec![transaction], &epoch_store);
6136
6137 let authority_state = self.authority_state.clone();
6138 spawn_monitored_task!(async move {
6139 const RANDOMNESS_STATE_UPDATE_EXECUTION_TIMEOUT: Duration = Duration::from_secs(300);
6148 let result = tokio::time::timeout(
6149 RANDOMNESS_STATE_UPDATE_EXECUTION_TIMEOUT,
6150 authority_state
6151 .get_transaction_cache_reader()
6152 .try_notify_read_executed_effects(&[digest]),
6153 )
6154 .await;
6155 let result = match result {
6156 Ok(result) => result,
6157 Err(_) => {
6158 if cfg!(debug_assertions) {
6159 panic!(
6161 "randomness state update transaction execution timed out at epoch {epoch}, round {round}"
6162 );
6163 }
6164 warn!(
6165 "randomness state update transaction execution timed out at epoch {epoch}, round {round}"
6166 );
6167 authority_state
6169 .get_transaction_cache_reader()
6170 .try_notify_read_executed_effects(&[digest])
6171 .await
6172 }
6173 };
6174
6175 let mut effects = result.unwrap_or_else(|_| panic!("failed to get effects for randomness state update transaction at epoch {epoch}, round {round}"));
6176 let effects = effects.pop().expect("should return effects");
6177 if *effects.status() != ExecutionStatus::Success {
6178 fatal!(
6179 "failed to execute randomness state update transaction at epoch {epoch}, round {round}: {effects:?}"
6180 );
6181 }
6182 debug!(
6183 "successfully executed randomness state update transaction at epoch {epoch}, round {round}"
6184 );
6185 });
6186 }
6187}
6188
6189#[async_trait]
6190impl TransactionKeyValueStoreTrait for AuthorityState {
6191 async fn multi_get(
6192 &self,
6193 transaction_keys: &[TransactionDigest],
6194 effects_keys: &[TransactionDigest],
6195 ) -> IotaResult<KVStoreTransactionData> {
6196 let txns = if !transaction_keys.is_empty() {
6197 self.get_transaction_cache_reader()
6198 .try_multi_get_transaction_blocks(transaction_keys)?
6199 .into_iter()
6200 .map(|t| t.map(|t| (*t).clone().into_inner()))
6201 .collect()
6202 } else {
6203 vec![]
6204 };
6205
6206 let fx = if !effects_keys.is_empty() {
6207 self.get_transaction_cache_reader()
6208 .try_multi_get_executed_effects(effects_keys)?
6209 } else {
6210 vec![]
6211 };
6212
6213 Ok((txns, fx))
6214 }
6215
6216 async fn multi_get_checkpoints(
6217 &self,
6218 checkpoint_summaries: &[CheckpointSequenceNumber],
6219 checkpoint_contents: &[CheckpointSequenceNumber],
6220 checkpoint_summaries_by_digest: &[CheckpointDigest],
6221 ) -> IotaResult<(
6222 Vec<Option<CertifiedCheckpointSummary>>,
6223 Vec<Option<CheckpointContents>>,
6224 Vec<Option<CertifiedCheckpointSummary>>,
6225 )> {
6226 let mut summaries = Vec::with_capacity(checkpoint_summaries.len());
6228 let store = self.get_checkpoint_store();
6229 for seq in checkpoint_summaries {
6230 let checkpoint = store
6231 .get_checkpoint_by_sequence_number(*seq)?
6232 .map(|c| c.into_inner());
6233
6234 summaries.push(checkpoint);
6235 }
6236
6237 let mut contents = Vec::with_capacity(checkpoint_contents.len());
6238 for seq in checkpoint_contents {
6239 let checkpoint = store
6240 .get_checkpoint_by_sequence_number(*seq)?
6241 .and_then(|summary| {
6242 store
6243 .get_checkpoint_contents(&summary.contents_digest)
6244 .expect("db read cannot fail")
6245 });
6246 contents.push(checkpoint);
6247 }
6248
6249 let mut summaries_by_digest = Vec::with_capacity(checkpoint_summaries_by_digest.len());
6250 for digest in checkpoint_summaries_by_digest {
6251 let checkpoint = store
6252 .get_checkpoint_by_digest(digest)?
6253 .map(|c| c.into_inner());
6254 summaries_by_digest.push(checkpoint);
6255 }
6256
6257 Ok((summaries, contents, summaries_by_digest))
6258 }
6259
6260 async fn get_transaction_perpetual_checkpoint(
6261 &self,
6262 digest: TransactionDigest,
6263 ) -> IotaResult<Option<CheckpointSequenceNumber>> {
6264 self.get_checkpoint_cache()
6265 .try_get_transaction_perpetual_checkpoint(&digest)
6266 .map(|res| res.map(|(_epoch, checkpoint)| checkpoint))
6267 }
6268
6269 async fn get_object(
6270 &self,
6271 object_id: ObjectId,
6272 version: VersionNumber,
6273 ) -> IotaResult<Option<Object>> {
6274 self.get_object_cache_reader()
6275 .try_get_object_by_key(&object_id, version)
6276 }
6277
6278 #[instrument(skip_all)]
6279 async fn multi_get_objects(
6280 &self,
6281 object_keys: &[ObjectKey],
6282 ) -> IotaResult<Vec<Option<Object>>> {
6283 Ok(self
6284 .get_object_cache_reader()
6285 .multi_get_objects_by_key(object_keys))
6286 }
6287
6288 async fn multi_get_transactions_perpetual_checkpoints(
6289 &self,
6290 digests: &[TransactionDigest],
6291 ) -> IotaResult<Vec<Option<CheckpointSequenceNumber>>> {
6292 let res = self
6293 .get_checkpoint_cache()
6294 .try_multi_get_transactions_perpetual_checkpoints(digests)?;
6295
6296 Ok(res
6297 .into_iter()
6298 .map(|maybe| maybe.map(|(_epoch, checkpoint)| checkpoint))
6299 .collect())
6300 }
6301
6302 #[instrument(skip(self, digests), fields(digests = digests.iter().map(|d| d.to_string()).collect::<Vec<String>>().join(", ")))]
6303 async fn multi_get_events_by_tx_digests(
6304 &self,
6305 digests: &[TransactionDigest],
6306 ) -> IotaResult<Vec<Option<TransactionEvents>>> {
6307 if digests.is_empty() {
6308 return Ok(vec![]);
6309 }
6310
6311 Ok(self
6312 .get_transaction_cache_reader()
6313 .multi_get_events(digests))
6314 }
6315}
6316
6317#[cfg(msim)]
6318pub mod framework_injection {
6319 use std::{
6320 cell::RefCell,
6321 collections::{BTreeMap, BTreeSet},
6322 };
6323
6324 use iota_framework::{BuiltInFramework, SystemPackage};
6325 use iota_sdk_types::ObjectId;
6326 use iota_types::base_types::AuthorityName;
6327 use move_binary_format::CompiledModule;
6328
6329 type FrameworkOverrideConfig = BTreeMap<ObjectId, PackageOverrideConfig>;
6330
6331 thread_local! {
6333 static OVERRIDE: RefCell<FrameworkOverrideConfig> = RefCell::new(FrameworkOverrideConfig::default());
6334 }
6335
6336 type Framework = Vec<CompiledModule>;
6337
6338 pub type PackageUpgradeCallback =
6339 Box<dyn Fn(AuthorityName) -> Option<Framework> + Send + Sync + 'static>;
6340
6341 enum PackageOverrideConfig {
6342 Global(Framework),
6343 PerValidator(PackageUpgradeCallback),
6344 }
6345
6346 fn compiled_modules_to_bytes(modules: &[CompiledModule]) -> Vec<Vec<u8>> {
6347 modules
6348 .iter()
6349 .map(|m| {
6350 let mut buf = Vec::new();
6351 m.serialize_with_version(m.version, &mut buf).unwrap();
6352 buf
6353 })
6354 .collect()
6355 }
6356
6357 pub fn set_override(package_id: ObjectId, modules: Vec<CompiledModule>) {
6358 OVERRIDE.with(|bs| {
6359 bs.borrow_mut()
6360 .insert(package_id, PackageOverrideConfig::Global(modules))
6361 });
6362 }
6363
6364 pub fn set_override_cb(package_id: ObjectId, func: PackageUpgradeCallback) {
6365 OVERRIDE.with(|bs| {
6366 bs.borrow_mut()
6367 .insert(package_id, PackageOverrideConfig::PerValidator(func))
6368 });
6369 }
6370
6371 pub fn get_override_bytes(package_id: &ObjectId, name: AuthorityName) -> Option<Vec<Vec<u8>>> {
6372 OVERRIDE.with(|cfg| {
6373 cfg.borrow().get(package_id).and_then(|entry| match entry {
6374 PackageOverrideConfig::Global(framework) => {
6375 Some(compiled_modules_to_bytes(framework))
6376 }
6377 PackageOverrideConfig::PerValidator(func) => {
6378 func(name).map(|fw| compiled_modules_to_bytes(&fw))
6379 }
6380 })
6381 })
6382 }
6383
6384 pub fn get_override_modules(
6385 package_id: &ObjectId,
6386 name: AuthorityName,
6387 ) -> Option<Vec<CompiledModule>> {
6388 OVERRIDE.with(|cfg| {
6389 cfg.borrow().get(package_id).and_then(|entry| match entry {
6390 PackageOverrideConfig::Global(framework) => Some(framework.clone()),
6391 PackageOverrideConfig::PerValidator(func) => func(name),
6392 })
6393 })
6394 }
6395
6396 pub fn get_override_system_package(
6397 package_id: &ObjectId,
6398 name: AuthorityName,
6399 ) -> Option<SystemPackage> {
6400 let bytes = get_override_bytes(package_id, name)?;
6401 let dependencies = if package_id.is_system_package() {
6402 BuiltInFramework::get_package_by_id(package_id)
6403 .dependencies
6404 .to_vec()
6405 } else {
6406 BuiltInFramework::all_package_ids()
6409 };
6410 Some(SystemPackage {
6411 id: *package_id,
6412 bytes,
6413 dependencies,
6414 })
6415 }
6416
6417 pub fn get_extra_packages(name: AuthorityName) -> Vec<SystemPackage> {
6418 let built_in = BTreeSet::from_iter(BuiltInFramework::all_package_ids());
6419 let extra: Vec<ObjectId> = OVERRIDE.with(|cfg| {
6420 cfg.borrow()
6421 .keys()
6422 .filter_map(|package| (!built_in.contains(package)).then_some(*package))
6423 .collect()
6424 });
6425
6426 extra
6427 .into_iter()
6428 .map(|package| SystemPackage {
6429 id: package,
6430 bytes: get_override_bytes(&package, name).unwrap(),
6431 dependencies: BuiltInFramework::all_package_ids(),
6432 })
6433 .collect()
6434 }
6435}
6436
6437#[derive(Debug, Serialize, Deserialize, Clone)]
6438pub struct ObjDumpFormat {
6439 pub id: ObjectId,
6440 pub version: VersionNumber,
6441 pub digest: ObjectDigest,
6442 pub object: Object,
6443}
6444
6445impl ObjDumpFormat {
6446 fn new(object: Object) -> Self {
6447 let oref = object.object_ref();
6448 Self {
6449 id: oref.object_id,
6450 version: oref.version,
6451 digest: oref.digest,
6452 object,
6453 }
6454 }
6455}
6456
6457#[derive(Debug, Serialize, Deserialize, Clone)]
6458pub struct NodeStateDump {
6459 pub tx_digest: TransactionDigest,
6460 pub sender_signed_data: SenderSignedData,
6461 pub executed_epoch: u64,
6462 pub reference_gas_price: u64,
6463 pub protocol_version: u64,
6464 pub epoch_start_timestamp_ms: u64,
6465 pub computed_effects: TransactionEffects,
6466 pub expected_effects_digest: TransactionEffectsDigest,
6467 pub relevant_system_packages: Vec<ObjDumpFormat>,
6468 pub shared_objects: Vec<ObjDumpFormat>,
6469 pub loaded_child_objects: Vec<ObjDumpFormat>,
6470 pub modified_at_versions: Vec<ObjDumpFormat>,
6471 pub runtime_reads: Vec<ObjDumpFormat>,
6472 pub input_objects: Vec<ObjDumpFormat>,
6473}
6474
6475impl NodeStateDump {
6476 pub fn new(
6477 tx_digest: &TransactionDigest,
6478 effects: &TransactionEffects,
6479 expected_effects_digest: TransactionEffectsDigest,
6480 object_store: &dyn ObjectStore,
6481 epoch_store: &Arc<AuthorityPerEpochStore>,
6482 inner_temporary_store: &InnerTemporaryStore,
6483 transaction: &VerifiedExecutableTransaction,
6484 ) -> IotaResult<Self> {
6485 let executed_epoch = epoch_store.epoch();
6487 let reference_gas_price = epoch_store.reference_gas_price();
6488 let epoch_start_config = epoch_store.epoch_start_config();
6489 let protocol_version = epoch_store.protocol_version().as_u64();
6490 let epoch_start_timestamp_ms = epoch_start_config.epoch_data().epoch_start_timestamp();
6491
6492 let mut relevant_system_packages = Vec::new();
6494 for sys_package_id in BuiltInFramework::all_package_ids() {
6495 if let Some(w) = object_store.try_get_object(&sys_package_id)? {
6496 relevant_system_packages.push(ObjDumpFormat::new(w))
6497 }
6498 }
6499
6500 let mut shared_objects = Vec::new();
6502 for kind in effects.input_shared_objects() {
6503 match kind {
6504 InputSharedObject::Mutate(obj_ref) | InputSharedObject::ReadOnly(obj_ref) => {
6505 if let Some(w) =
6506 object_store.try_get_object_by_key(&obj_ref.object_id, obj_ref.version)?
6507 {
6508 shared_objects.push(ObjDumpFormat::new(w))
6509 }
6510 }
6511 InputSharedObject::ReadDeleted(..)
6512 | InputSharedObject::MutateDeleted(..)
6513 | InputSharedObject::Cancelled(..) => (), }
6516 }
6517
6518 let mut loaded_child_objects = Vec::new();
6521 for (id, meta) in &inner_temporary_store.loaded_runtime_objects {
6522 if let Some(w) = object_store.try_get_object_by_key(id, meta.version)? {
6523 loaded_child_objects.push(ObjDumpFormat::new(w))
6524 }
6525 }
6526
6527 let mut modified_at_versions = Vec::new();
6529 for (id, ver) in effects.modified_at_versions() {
6530 if let Some(w) = object_store.try_get_object_by_key(&id, ver)? {
6531 modified_at_versions.push(ObjDumpFormat::new(w))
6532 }
6533 }
6534
6535 let mut runtime_reads = Vec::new();
6539 for obj in inner_temporary_store
6540 .runtime_packages_loaded_from_db
6541 .values()
6542 {
6543 runtime_reads.push(ObjDumpFormat::new(obj.object().clone()));
6544 }
6545
6546 Ok(Self {
6549 tx_digest: *tx_digest,
6550 executed_epoch,
6551 reference_gas_price,
6552 epoch_start_timestamp_ms,
6553 protocol_version,
6554 relevant_system_packages,
6555 shared_objects,
6556 loaded_child_objects,
6557 modified_at_versions,
6558 runtime_reads,
6559 sender_signed_data: transaction.clone().into_message(),
6560 input_objects: inner_temporary_store
6561 .input_objects
6562 .values()
6563 .map(|o| ObjDumpFormat::new(o.clone()))
6564 .collect(),
6565 computed_effects: effects.clone(),
6566 expected_effects_digest,
6567 })
6568 }
6569
6570 pub fn all_objects(&self) -> Vec<ObjDumpFormat> {
6571 let mut objects = Vec::new();
6572 objects.extend(self.relevant_system_packages.clone());
6573 objects.extend(self.shared_objects.clone());
6574 objects.extend(self.loaded_child_objects.clone());
6575 objects.extend(self.modified_at_versions.clone());
6576 objects.extend(self.runtime_reads.clone());
6577 objects.extend(self.input_objects.clone());
6578 objects
6579 }
6580
6581 pub fn write_to_file(&self, path: &Path) -> Result<PathBuf, anyhow::Error> {
6582 let file_name = format!(
6583 "{}_{}_NODE_DUMP.json",
6584 self.tx_digest,
6585 AuthorityState::unixtime_now_ms()
6586 );
6587 let mut path = path.to_path_buf();
6588 path.push(&file_name);
6589 let mut file = File::create(path.clone())?;
6590 file.write_all(serde_json::to_string_pretty(self)?.as_bytes())?;
6591 Ok(path)
6592 }
6593
6594 pub fn read_from_file(path: &PathBuf) -> Result<Self, anyhow::Error> {
6595 let file = File::open(path)?;
6596 serde_json::from_reader(file).map_err(|e| anyhow::anyhow!(e))
6597 }
6598}
6599
6600fn pre_consensus_move_authenticators<'a>(
6612 tx: &'a VerifiedTransaction,
6613 protocol_config: &ProtocolConfig,
6614) -> Vec<&'a MoveAuthenticator> {
6615 if protocol_config.pre_consensus_sponsor_only_move_authentication() {
6616 if tx.transaction().is_sponsored_tx() {
6617 if let Some(sponsor_move_authenticator) = tx.sponsor_move_authenticator() {
6618 vec![sponsor_move_authenticator]
6619 } else {
6620 vec![]
6621 }
6622 } else {
6623 tx.move_authenticators()
6624 }
6625 } else {
6626 tx.move_authenticators()
6627 }
6628}