solana_runtime/
bank.rs

1//! The `bank` module tracks client accounts and the progress of on-chain
2//! programs.
3//!
4//! A single bank relates to a block produced by a single leader and each bank
5//! except for the genesis bank points back to a parent bank.
6//!
7//! The bank is the main entrypoint for processing verified transactions with the function
8//! `Bank::process_transactions`
9//!
10//! It does this by loading the accounts using the reference it holds on the account store,
11//! and then passing those to an InvokeContext which handles loading the programs specified
12//! by the Transaction and executing it.
13//!
14//! The bank then stores the results to the accounts store.
15//!
16//! It then has APIs for retrieving if a transaction has been processed and it's status.
17//! See `get_signature_status` et al.
18//!
19//! Bank lifecycle:
20//!
21//! A bank is newly created and open to transactions. Transactions are applied
22//! until either the bank reached the tick count when the node is the leader for that slot, or the
23//! node has applied all transactions present in all `Entry`s in the slot.
24//!
25//! Once it is complete, the bank can then be frozen. After frozen, no more transactions can
26//! be applied or state changes made. At the frozen step, rent will be applied and various
27//! sysvar special accounts update to the new state of the system.
28//!
29//! After frozen, and the bank has had the appropriate number of votes on it, then it can become
30//! rooted. At this point, it will not be able to be removed from the chain and the
31//! state is finalized.
32//!
33//! It offers a high-level API that signs transactions
34//! on behalf of the caller, and a low-level API for when they have
35//! already been signed and verified.
36use {
37    crate::{
38        account_saver::collect_accounts_to_store,
39        bank::{
40            metrics::*,
41            partitioned_epoch_rewards::{EpochRewardStatus, StakeRewards, VoteRewardsAccounts},
42        },
43        bank_forks::BankForks,
44        epoch_stakes::{split_epoch_stakes, EpochStakes, NodeVoteAccounts, VersionedEpochStakes},
45        installed_scheduler_pool::{BankWithScheduler, InstalledSchedulerRwLock},
46        rent_collector::RentCollectorWithMetrics,
47        runtime_config::RuntimeConfig,
48        serde_snapshot::BankIncrementalSnapshotPersistence,
49        snapshot_hash::SnapshotHash,
50        stake_account::StakeAccount,
51        stake_weighted_timestamp::{
52            calculate_stake_weighted_timestamp, MaxAllowableDrift,
53            MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW_V2,
54        },
55        stakes::{Stakes, StakesCache, StakesEnum},
56        status_cache::{SlotDelta, StatusCache},
57        transaction_batch::{OwnedOrBorrowed, TransactionBatch},
58        verify_precompiles::verify_precompiles,
59    },
60    accounts_lt_hash::{CacheValue as AccountsLtHashCacheValue, Stats as AccountsLtHashStats},
61    agave_feature_set::{self as feature_set, reward_full_priority_fee, FeatureSet},
62    agave_precompiles::get_precompiles,
63    agave_reserved_account_keys::ReservedAccountKeys,
64    ahash::AHashSet,
65    dashmap::{DashMap, DashSet},
66    log::*,
67    rayon::{
68        iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator},
69        ThreadPoolBuilder,
70    },
71    serde::Serialize,
72    solana_accounts_db::{
73        account_locks::validate_account_locks,
74        accounts::{AccountAddressFilter, Accounts, PubkeyAccountSlot},
75        accounts_db::{
76            AccountStorageEntry, AccountsDb, AccountsDbConfig, CalcAccountsHashDataSource,
77            DuplicatesLtHash, OldStoragesPolicy, PubkeyHashAccount,
78            VerifyAccountsHashAndLamportsConfig,
79        },
80        accounts_hash::{
81            AccountHash, AccountsHash, AccountsLtHash, CalcAccountsHashConfig, HashStats,
82            IncrementalAccountsHash, MerkleOrLatticeAccountsHash,
83        },
84        accounts_index::{IndexKey, ScanConfig, ScanResult},
85        accounts_partition::{self, Partition, PartitionIndex},
86        accounts_update_notifier_interface::AccountsUpdateNotifier,
87        ancestors::{Ancestors, AncestorsForSerialization},
88        blockhash_queue::BlockhashQueue,
89        epoch_accounts_hash::EpochAccountsHash,
90        sorted_storages::SortedStorages,
91        storable_accounts::StorableAccounts,
92    },
93    solana_bpf_loader_program::syscalls::{
94        create_program_runtime_environment_v1, create_program_runtime_environment_v2,
95    },
96    solana_builtins::{prototype::BuiltinPrototype, BUILTINS, STATELESS_BUILTINS},
97    solana_compute_budget::compute_budget::ComputeBudget,
98    solana_compute_budget_instruction::instructions_processor::process_compute_budget_instructions,
99    solana_cost_model::{block_cost_limits::simd_0207_block_limits, cost_tracker::CostTracker},
100    solana_fee::FeeFeatures,
101    solana_lattice_hash::lt_hash::LtHash,
102    solana_measure::{meas_dur, measure::Measure, measure_time, measure_us},
103    solana_program_runtime::{
104        invoke_context::BuiltinFunctionWithContext, loaded_programs::ProgramCacheEntry,
105    },
106    solana_runtime_transaction::{
107        runtime_transaction::RuntimeTransaction, transaction_with_meta::TransactionWithMeta,
108    },
109    solana_sdk::{
110        account::{
111            create_account_shared_data_with_fields as create_account, from_account, Account,
112            AccountSharedData, InheritableAccountFields, ReadableAccount, WritableAccount,
113        },
114        bpf_loader_upgradeable,
115        clock::{
116            BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_HASHES_PER_TICK,
117            DEFAULT_TICKS_PER_SECOND, INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE,
118            MAX_TRANSACTION_FORWARDING_DELAY, SECONDS_PER_DAY, UPDATED_HASHES_PER_TICK2,
119            UPDATED_HASHES_PER_TICK3, UPDATED_HASHES_PER_TICK4, UPDATED_HASHES_PER_TICK5,
120            UPDATED_HASHES_PER_TICK6,
121        },
122        epoch_info::EpochInfo,
123        epoch_schedule::EpochSchedule,
124        feature,
125        fee::{FeeBudgetLimits, FeeDetails, FeeStructure},
126        fee_calculator::FeeRateGovernor,
127        genesis_config::{ClusterType, GenesisConfig},
128        hard_forks::HardForks,
129        hash::{extend_and_hash, hashv, Hash},
130        incinerator,
131        inflation::Inflation,
132        inner_instruction::InnerInstructions,
133        message::{AccountKeys, SanitizedMessage},
134        native_loader,
135        native_token::LAMPORTS_PER_SOL,
136        packet::PACKET_DATA_SIZE,
137        pubkey::Pubkey,
138        rent_collector::{CollectedInfo, RentCollector},
139        rent_debits::RentDebits,
140        reward_info::RewardInfo,
141        signature::{Keypair, Signature},
142        slot_hashes::SlotHashes,
143        slot_history::{Check, SlotHistory},
144        stake::state::Delegation,
145        system_transaction,
146        sysvar::{self, last_restart_slot::LastRestartSlot, Sysvar, SysvarId},
147        timing::years_as_slots,
148        transaction::{
149            MessageHash, Result, SanitizedTransaction, Transaction, TransactionError,
150            TransactionVerificationMode, VersionedTransaction, MAX_TX_ACCOUNT_LOCKS,
151        },
152    },
153    solana_stake_program::points::InflationPointCalculationEvent,
154    solana_svm::{
155        account_loader::{collect_rent_from_account, LoadedTransaction},
156        account_overrides::AccountOverrides,
157        transaction_commit_result::{CommittedTransaction, TransactionCommitResult},
158        transaction_error_metrics::TransactionErrorMetrics,
159        transaction_execution_result::{
160            TransactionExecutionDetails, TransactionLoadedAccountsStats,
161        },
162        transaction_processing_callback::{AccountState, TransactionProcessingCallback},
163        transaction_processing_result::{
164            ProcessedTransaction, TransactionProcessingResult,
165            TransactionProcessingResultExtensions,
166        },
167        transaction_processor::{
168            ExecutionRecordingConfig, TransactionBatchProcessor, TransactionLogMessages,
169            TransactionProcessingConfig, TransactionProcessingEnvironment,
170        },
171    },
172    solana_svm_transaction::svm_message::SVMMessage,
173    solana_timings::{ExecuteTimingType, ExecuteTimings},
174    solana_transaction_context::{TransactionAccount, TransactionReturnData},
175    solana_vote::vote_account::{VoteAccount, VoteAccountsHashMap},
176    std::{
177        collections::{HashMap, HashSet},
178        convert::TryFrom,
179        fmt,
180        ops::{AddAssign, RangeFull, RangeInclusive},
181        path::PathBuf,
182        slice,
183        sync::{
184            atomic::{
185                AtomicBool, AtomicI64, AtomicU64, AtomicUsize,
186                Ordering::{AcqRel, Acquire, Relaxed},
187            },
188            Arc, LockResult, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak,
189        },
190        thread::Builder,
191        time::{Duration, Instant},
192    },
193};
194pub use {
195    partitioned_epoch_rewards::KeyedRewardsAndNumPartitions, solana_sdk::reward_type::RewardType,
196};
197#[cfg(feature = "dev-context-only-utils")]
198use {
199    solana_accounts_db::accounts_db::{
200        ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS, ACCOUNTS_DB_CONFIG_FOR_TESTING,
201    },
202    solana_nonce_account::{get_system_account_kind, SystemAccountKind},
203    solana_program_runtime::{loaded_programs::ProgramCacheForTxBatch, sysvar_cache::SysvarCache},
204    solana_sdk::nonce,
205    solana_svm::program_loader::load_program_with_pubkey,
206};
207
208/// params to `verify_accounts_hash`
209struct VerifyAccountsHashConfig {
210    test_hash_calculation: bool,
211    ignore_mismatch: bool,
212    require_rooted_bank: bool,
213    run_in_background: bool,
214    store_hash_raw_data_for_debug: bool,
215}
216
217mod accounts_lt_hash;
218mod address_lookup_table;
219pub mod bank_hash_details;
220mod builtin_programs;
221pub mod builtins;
222mod check_transactions;
223pub mod epoch_accounts_hash_utils;
224mod fee_distribution;
225mod metrics;
226pub(crate) mod partitioned_epoch_rewards;
227mod recent_blockhashes_account;
228mod serde_snapshot;
229mod sysvar_cache;
230pub(crate) mod tests;
231
232pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
233
234pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
235
236#[derive(Default)]
237struct RentMetrics {
238    hold_range_us: AtomicU64,
239    load_us: AtomicU64,
240    collect_us: AtomicU64,
241    hash_us: AtomicU64,
242    store_us: AtomicU64,
243    count: AtomicUsize,
244}
245
246pub type BankStatusCache = StatusCache<Result<()>>;
247#[cfg_attr(
248    feature = "frozen-abi",
249    frozen_abi(digest = "4e7a7AAsQrM5Lp5bhREdVZ5QGZfyETbBthhWjYMYb6zS")
250)]
251pub type BankSlotDelta = SlotDelta<Result<()>>;
252
253#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
254pub struct SquashTiming {
255    pub squash_accounts_ms: u64,
256    pub squash_accounts_cache_ms: u64,
257    pub squash_accounts_index_ms: u64,
258    pub squash_accounts_store_ms: u64,
259
260    pub squash_cache_ms: u64,
261}
262
263impl AddAssign for SquashTiming {
264    fn add_assign(&mut self, rhs: Self) {
265        self.squash_accounts_ms += rhs.squash_accounts_ms;
266        self.squash_accounts_cache_ms += rhs.squash_accounts_cache_ms;
267        self.squash_accounts_index_ms += rhs.squash_accounts_index_ms;
268        self.squash_accounts_store_ms += rhs.squash_accounts_store_ms;
269        self.squash_cache_ms += rhs.squash_cache_ms;
270    }
271}
272
273#[derive(Debug, Default, PartialEq)]
274pub(crate) struct CollectorFeeDetails {
275    transaction_fee: u64,
276    priority_fee: u64,
277}
278
279impl CollectorFeeDetails {
280    pub(crate) fn accumulate(&mut self, fee_details: &FeeDetails) {
281        self.transaction_fee = self
282            .transaction_fee
283            .saturating_add(fee_details.transaction_fee());
284        self.priority_fee = self
285            .priority_fee
286            .saturating_add(fee_details.prioritization_fee());
287    }
288
289    pub(crate) fn total(&self) -> u64 {
290        self.transaction_fee.saturating_add(self.priority_fee)
291    }
292}
293
294impl From<FeeDetails> for CollectorFeeDetails {
295    fn from(fee_details: FeeDetails) -> Self {
296        CollectorFeeDetails {
297            transaction_fee: fee_details.transaction_fee(),
298            priority_fee: fee_details.prioritization_fee(),
299        }
300    }
301}
302
303#[derive(Debug)]
304pub struct BankRc {
305    /// where all the Accounts are stored
306    pub accounts: Arc<Accounts>,
307
308    /// Previous checkpoint of this bank
309    pub(crate) parent: RwLock<Option<Arc<Bank>>>,
310
311    pub(crate) bank_id_generator: Arc<AtomicU64>,
312}
313
314impl BankRc {
315    pub(crate) fn new(accounts: Accounts) -> Self {
316        Self {
317            accounts: Arc::new(accounts),
318            parent: RwLock::new(None),
319            bank_id_generator: Arc::new(AtomicU64::new(0)),
320        }
321    }
322}
323
324pub struct LoadAndExecuteTransactionsOutput {
325    // Vector of results indicating whether a transaction was processed or could not
326    // be processed. Note processed transactions can still have failed!
327    pub processing_results: Vec<TransactionProcessingResult>,
328    // Processed transaction counts used to update bank transaction counts and
329    // for metrics reporting.
330    pub processed_counts: ProcessedTransactionCounts,
331}
332
333#[derive(Debug, PartialEq)]
334pub struct TransactionSimulationResult {
335    pub result: Result<()>,
336    pub logs: TransactionLogMessages,
337    pub post_simulation_accounts: Vec<TransactionAccount>,
338    pub units_consumed: u64,
339    pub return_data: Option<TransactionReturnData>,
340    pub inner_instructions: Option<Vec<InnerInstructions>>,
341}
342
343#[derive(Clone, Debug)]
344pub struct TransactionBalancesSet {
345    pub pre_balances: TransactionBalances,
346    pub post_balances: TransactionBalances,
347}
348
349impl TransactionBalancesSet {
350    pub fn new(pre_balances: TransactionBalances, post_balances: TransactionBalances) -> Self {
351        assert_eq!(pre_balances.len(), post_balances.len());
352        Self {
353            pre_balances,
354            post_balances,
355        }
356    }
357}
358pub type TransactionBalances = Vec<Vec<u64>>;
359
360pub type PreCommitResult<'a> = Result<Option<RwLockReadGuard<'a, Hash>>>;
361
362#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
363pub enum TransactionLogCollectorFilter {
364    All,
365    AllWithVotes,
366    None,
367    OnlyMentionedAddresses,
368}
369
370impl Default for TransactionLogCollectorFilter {
371    fn default() -> Self {
372        Self::None
373    }
374}
375
376#[derive(Debug, Default)]
377pub struct TransactionLogCollectorConfig {
378    pub mentioned_addresses: HashSet<Pubkey>,
379    pub filter: TransactionLogCollectorFilter,
380}
381
382#[derive(Clone, Debug, PartialEq, Eq)]
383pub struct TransactionLogInfo {
384    pub signature: Signature,
385    pub result: Result<()>,
386    pub is_vote: bool,
387    pub log_messages: TransactionLogMessages,
388}
389
390#[derive(Default, Debug)]
391pub struct TransactionLogCollector {
392    // All the logs collected for from this Bank.  Exact contents depend on the
393    // active `TransactionLogCollectorFilter`
394    pub logs: Vec<TransactionLogInfo>,
395
396    // For each `mentioned_addresses`, maintain a list of indices into `logs` to easily
397    // locate the logs from transactions that included the mentioned addresses.
398    pub mentioned_address_map: HashMap<Pubkey, Vec<usize>>,
399}
400
401impl TransactionLogCollector {
402    pub fn get_logs_for_address(
403        &self,
404        address: Option<&Pubkey>,
405    ) -> Option<Vec<TransactionLogInfo>> {
406        match address {
407            None => Some(self.logs.clone()),
408            Some(address) => self.mentioned_address_map.get(address).map(|log_indices| {
409                log_indices
410                    .iter()
411                    .filter_map(|i| self.logs.get(*i).cloned())
412                    .collect()
413            }),
414        }
415    }
416}
417
418/// Bank's common fields shared by all supported snapshot versions for deserialization.
419/// Sync fields with BankFieldsToSerialize! This is paired with it.
420/// All members are made public to remain Bank's members private and to make versioned deserializer workable on this
421/// Note that some fields are missing from the serializer struct. This is because of fields added later.
422/// Since it is difficult to insert fields to serialize/deserialize against existing code already deployed,
423/// new fields can be optionally serialized and optionally deserialized. At some point, the serialization and
424/// deserialization will use a new mechanism or otherwise be in sync more clearly.
425#[derive(Clone, Debug, Default)]
426#[cfg_attr(feature = "dev-context-only-utils", derive(PartialEq))]
427pub struct BankFieldsToDeserialize {
428    pub(crate) blockhash_queue: BlockhashQueue,
429    pub(crate) ancestors: AncestorsForSerialization,
430    pub(crate) hash: Hash,
431    pub(crate) parent_hash: Hash,
432    pub(crate) parent_slot: Slot,
433    pub(crate) hard_forks: HardForks,
434    pub(crate) transaction_count: u64,
435    pub(crate) tick_height: u64,
436    pub(crate) signature_count: u64,
437    pub(crate) capitalization: u64,
438    pub(crate) max_tick_height: u64,
439    pub(crate) hashes_per_tick: Option<u64>,
440    pub(crate) ticks_per_slot: u64,
441    pub(crate) ns_per_slot: u128,
442    pub(crate) genesis_creation_time: UnixTimestamp,
443    pub(crate) slots_per_year: f64,
444    pub(crate) slot: Slot,
445    pub(crate) epoch: Epoch,
446    pub(crate) block_height: u64,
447    pub(crate) collector_id: Pubkey,
448    pub(crate) collector_fees: u64,
449    pub(crate) fee_rate_governor: FeeRateGovernor,
450    pub(crate) collected_rent: u64,
451    pub(crate) rent_collector: RentCollector,
452    pub(crate) epoch_schedule: EpochSchedule,
453    pub(crate) inflation: Inflation,
454    pub(crate) stakes: Stakes<Delegation>,
455    pub(crate) epoch_stakes: HashMap<Epoch, EpochStakes>,
456    pub(crate) is_delta: bool,
457    pub(crate) accounts_data_len: u64,
458    pub(crate) incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
459    pub(crate) epoch_accounts_hash: Option<Hash>,
460    // When removing the accounts lt hash featurization code, also remove this Option wrapper
461    pub(crate) accounts_lt_hash: Option<AccountsLtHash>,
462    pub(crate) bank_hash_stats: BankHashStats,
463}
464
465/// Bank's common fields shared by all supported snapshot versions for serialization.
466/// This was separated from BankFieldsToDeserialize to avoid cloning by using refs.
467/// So, sync fields with BankFieldsToDeserialize!
468/// all members are made public to keep Bank private and to make versioned serializer workable on this.
469/// Note that some fields are missing from the serializer struct. This is because of fields added later.
470/// Since it is difficult to insert fields to serialize/deserialize against existing code already deployed,
471/// new fields can be optionally serialized and optionally deserialized. At some point, the serialization and
472/// deserialization will use a new mechanism or otherwise be in sync more clearly.
473#[derive(Debug)]
474pub struct BankFieldsToSerialize {
475    pub blockhash_queue: BlockhashQueue,
476    pub ancestors: AncestorsForSerialization,
477    pub hash: Hash,
478    pub parent_hash: Hash,
479    pub parent_slot: Slot,
480    pub hard_forks: HardForks,
481    pub transaction_count: u64,
482    pub tick_height: u64,
483    pub signature_count: u64,
484    pub capitalization: u64,
485    pub max_tick_height: u64,
486    pub hashes_per_tick: Option<u64>,
487    pub ticks_per_slot: u64,
488    pub ns_per_slot: u128,
489    pub genesis_creation_time: UnixTimestamp,
490    pub slots_per_year: f64,
491    pub slot: Slot,
492    pub epoch: Epoch,
493    pub block_height: u64,
494    pub collector_id: Pubkey,
495    pub collector_fees: u64,
496    pub fee_rate_governor: FeeRateGovernor,
497    pub collected_rent: u64,
498    pub rent_collector: RentCollector,
499    pub epoch_schedule: EpochSchedule,
500    pub inflation: Inflation,
501    pub stakes: StakesEnum,
502    pub epoch_stakes: HashMap<Epoch, EpochStakes>,
503    pub is_delta: bool,
504    pub accounts_data_len: u64,
505    pub versioned_epoch_stakes: HashMap<u64, VersionedEpochStakes>,
506    // When removing the accounts lt hash featurization code, also remove this Option wrapper
507    pub accounts_lt_hash: Option<AccountsLtHash>,
508}
509
510// Can't derive PartialEq because RwLock doesn't implement PartialEq
511#[cfg(feature = "dev-context-only-utils")]
512impl PartialEq for Bank {
513    fn eq(&self, other: &Self) -> bool {
514        if std::ptr::eq(self, other) {
515            return true;
516        }
517        // Suppress rustfmt until https://github.com/rust-lang/rustfmt/issues/5920 is fixed ...
518        #[rustfmt::skip]
519        let Self {
520            skipped_rewrites: _,
521            rc: _,
522            status_cache: _,
523            blockhash_queue,
524            ancestors,
525            hash,
526            parent_hash,
527            parent_slot,
528            hard_forks,
529            transaction_count,
530            non_vote_transaction_count_since_restart: _,
531            transaction_error_count: _,
532            transaction_entries_count: _,
533            transactions_per_entry_max: _,
534            tick_height,
535            signature_count,
536            capitalization,
537            max_tick_height,
538            hashes_per_tick,
539            ticks_per_slot,
540            ns_per_slot,
541            genesis_creation_time,
542            slots_per_year,
543            slot,
544            bank_id: _,
545            epoch,
546            block_height,
547            collector_id,
548            collector_fees,
549            fee_rate_governor,
550            collected_rent,
551            rent_collector,
552            epoch_schedule,
553            inflation,
554            stakes_cache,
555            epoch_stakes,
556            is_delta,
557            #[cfg(feature = "dev-context-only-utils")]
558            hash_overrides,
559            accounts_lt_hash,
560            // TODO: Confirm if all these fields are intentionally ignored!
561            rewards: _,
562            cluster_type: _,
563            lazy_rent_collection: _,
564            rewards_pool_pubkeys: _,
565            transaction_debug_keys: _,
566            transaction_log_collector_config: _,
567            transaction_log_collector: _,
568            feature_set: _,
569            reserved_account_keys: _,
570            drop_callback: _,
571            freeze_started: _,
572            vote_only_bank: _,
573            cost_tracker: _,
574            accounts_data_size_initial: _,
575            accounts_data_size_delta_on_chain: _,
576            accounts_data_size_delta_off_chain: _,
577            epoch_reward_status: _,
578            transaction_processor: _,
579            check_program_modification_slot: _,
580            collector_fee_details: _,
581            compute_budget: _,
582            transaction_account_lock_limit: _,
583            fee_structure: _,
584            cache_for_accounts_lt_hash: _,
585            stats_for_accounts_lt_hash: _,
586            block_id,
587            bank_hash_stats: _,
588            // Ignore new fields explicitly if they do not impact PartialEq.
589            // Adding ".." will remove compile-time checks that if a new field
590            // is added to the struct, this PartialEq is accordingly updated.
591        } = self;
592        *blockhash_queue.read().unwrap() == *other.blockhash_queue.read().unwrap()
593            && ancestors == &other.ancestors
594            && *hash.read().unwrap() == *other.hash.read().unwrap()
595            && parent_hash == &other.parent_hash
596            && parent_slot == &other.parent_slot
597            && *hard_forks.read().unwrap() == *other.hard_forks.read().unwrap()
598            && transaction_count.load(Relaxed) == other.transaction_count.load(Relaxed)
599            && tick_height.load(Relaxed) == other.tick_height.load(Relaxed)
600            && signature_count.load(Relaxed) == other.signature_count.load(Relaxed)
601            && capitalization.load(Relaxed) == other.capitalization.load(Relaxed)
602            && max_tick_height == &other.max_tick_height
603            && hashes_per_tick == &other.hashes_per_tick
604            && ticks_per_slot == &other.ticks_per_slot
605            && ns_per_slot == &other.ns_per_slot
606            && genesis_creation_time == &other.genesis_creation_time
607            && slots_per_year == &other.slots_per_year
608            && slot == &other.slot
609            && epoch == &other.epoch
610            && block_height == &other.block_height
611            && collector_id == &other.collector_id
612            && collector_fees.load(Relaxed) == other.collector_fees.load(Relaxed)
613            && fee_rate_governor == &other.fee_rate_governor
614            && collected_rent.load(Relaxed) == other.collected_rent.load(Relaxed)
615            && rent_collector == &other.rent_collector
616            && epoch_schedule == &other.epoch_schedule
617            && *inflation.read().unwrap() == *other.inflation.read().unwrap()
618            && *stakes_cache.stakes() == *other.stakes_cache.stakes()
619            && epoch_stakes == &other.epoch_stakes
620            && is_delta.load(Relaxed) == other.is_delta.load(Relaxed)
621            // No deadlock is possbile, when Arc::ptr_eq() returns false, because of being
622            // different Mutexes.
623            && (Arc::ptr_eq(hash_overrides, &other.hash_overrides) ||
624                *hash_overrides.lock().unwrap() == *other.hash_overrides.lock().unwrap())
625            && !(self.is_accounts_lt_hash_enabled() && other.is_accounts_lt_hash_enabled()
626                && *accounts_lt_hash.lock().unwrap() != *other.accounts_lt_hash.lock().unwrap())
627            && *block_id.read().unwrap() == *other.block_id.read().unwrap()
628    }
629}
630
631#[cfg(feature = "dev-context-only-utils")]
632impl BankFieldsToSerialize {
633    /// Create a new BankFieldsToSerialize where basically every field is defaulted.
634    /// Only use for tests; many of the fields are invalid!
635    pub fn default_for_tests() -> Self {
636        Self {
637            blockhash_queue: BlockhashQueue::default(),
638            ancestors: AncestorsForSerialization::default(),
639            hash: Hash::default(),
640            parent_hash: Hash::default(),
641            parent_slot: Slot::default(),
642            hard_forks: HardForks::default(),
643            transaction_count: u64::default(),
644            tick_height: u64::default(),
645            signature_count: u64::default(),
646            capitalization: u64::default(),
647            max_tick_height: u64::default(),
648            hashes_per_tick: Option::default(),
649            ticks_per_slot: u64::default(),
650            ns_per_slot: u128::default(),
651            genesis_creation_time: UnixTimestamp::default(),
652            slots_per_year: f64::default(),
653            slot: Slot::default(),
654            epoch: Epoch::default(),
655            block_height: u64::default(),
656            collector_id: Pubkey::default(),
657            collector_fees: u64::default(),
658            fee_rate_governor: FeeRateGovernor::default(),
659            collected_rent: u64::default(),
660            rent_collector: RentCollector::default(),
661            epoch_schedule: EpochSchedule::default(),
662            inflation: Inflation::default(),
663            stakes: Stakes::<Delegation>::default().into(),
664            epoch_stakes: HashMap::default(),
665            is_delta: bool::default(),
666            accounts_data_len: u64::default(),
667            versioned_epoch_stakes: HashMap::default(),
668            accounts_lt_hash: Some(AccountsLtHash(LtHash([0x7E57; LtHash::NUM_ELEMENTS]))),
669        }
670    }
671}
672
673#[derive(Debug)]
674pub enum RewardCalculationEvent<'a, 'b> {
675    Staking(&'a Pubkey, &'b InflationPointCalculationEvent),
676}
677
678/// type alias is not supported for trait in rust yet. As a workaround, we define the
679/// `RewardCalcTracer` trait explicitly and implement it on any type that implement
680/// `Fn(&RewardCalculationEvent) + Send + Sync`.
681pub trait RewardCalcTracer: Fn(&RewardCalculationEvent) + Send + Sync {}
682
683impl<T: Fn(&RewardCalculationEvent) + Send + Sync> RewardCalcTracer for T {}
684
685fn null_tracer() -> Option<impl RewardCalcTracer> {
686    None::<fn(&RewardCalculationEvent)>
687}
688
689pub trait DropCallback: fmt::Debug {
690    fn callback(&self, b: &Bank);
691    fn clone_box(&self) -> Box<dyn DropCallback + Send + Sync>;
692}
693
694#[derive(Debug, Default)]
695pub struct OptionalDropCallback(Option<Box<dyn DropCallback + Send + Sync>>);
696
697#[derive(Default, Debug, Clone, PartialEq)]
698#[cfg(feature = "dev-context-only-utils")]
699pub struct HashOverrides {
700    hashes: HashMap<Slot, HashOverride>,
701}
702
703#[cfg(feature = "dev-context-only-utils")]
704impl HashOverrides {
705    fn get_hash_override(&self, slot: Slot) -> Option<&HashOverride> {
706        self.hashes.get(&slot)
707    }
708
709    fn get_blockhash_override(&self, slot: Slot) -> Option<&Hash> {
710        self.get_hash_override(slot)
711            .map(|hash_override| &hash_override.blockhash)
712    }
713
714    fn get_bank_hash_override(&self, slot: Slot) -> Option<&Hash> {
715        self.get_hash_override(slot)
716            .map(|hash_override| &hash_override.bank_hash)
717    }
718
719    pub fn add_override(&mut self, slot: Slot, blockhash: Hash, bank_hash: Hash) {
720        let is_new = self
721            .hashes
722            .insert(
723                slot,
724                HashOverride {
725                    blockhash,
726                    bank_hash,
727                },
728            )
729            .is_none();
730        assert!(is_new);
731    }
732}
733
734#[derive(Debug, Clone, PartialEq)]
735#[cfg(feature = "dev-context-only-utils")]
736struct HashOverride {
737    blockhash: Hash,
738    bank_hash: Hash,
739}
740
741/// Manager for the state of all accounts and programs after processing its entries.
742#[derive(Debug)]
743pub struct Bank {
744    /// References to accounts, parent and signature status
745    pub rc: BankRc,
746
747    /// A cache of signature statuses
748    pub status_cache: Arc<RwLock<BankStatusCache>>,
749
750    /// FIFO queue of `recent_blockhash` items
751    blockhash_queue: RwLock<BlockhashQueue>,
752
753    /// The set of parents including this bank
754    pub ancestors: Ancestors,
755
756    /// Hash of this Bank's state. Only meaningful after freezing.
757    hash: RwLock<Hash>,
758
759    /// Hash of this Bank's parent's state
760    parent_hash: Hash,
761
762    /// parent's slot
763    parent_slot: Slot,
764
765    /// slots to hard fork at
766    hard_forks: Arc<RwLock<HardForks>>,
767
768    /// The number of committed transactions since genesis.
769    transaction_count: AtomicU64,
770
771    /// The number of non-vote transactions committed since the most
772    /// recent boot from snapshot or genesis. This value is only stored in
773    /// blockstore for the RPC method "getPerformanceSamples". It is not
774    /// retained within snapshots, but is preserved in `Bank::new_from_parent`.
775    non_vote_transaction_count_since_restart: AtomicU64,
776
777    /// The number of transaction errors in this slot
778    transaction_error_count: AtomicU64,
779
780    /// The number of transaction entries in this slot
781    transaction_entries_count: AtomicU64,
782
783    /// The max number of transaction in an entry in this slot
784    transactions_per_entry_max: AtomicU64,
785
786    /// Bank tick height
787    tick_height: AtomicU64,
788
789    /// The number of signatures from valid transactions in this slot
790    signature_count: AtomicU64,
791
792    /// Total capitalization, used to calculate inflation
793    capitalization: AtomicU64,
794
795    // Bank max_tick_height
796    max_tick_height: u64,
797
798    /// The number of hashes in each tick. None value means hashing is disabled.
799    hashes_per_tick: Option<u64>,
800
801    /// The number of ticks in each slot.
802    ticks_per_slot: u64,
803
804    /// length of a slot in ns
805    pub ns_per_slot: u128,
806
807    /// genesis time, used for computed clock
808    genesis_creation_time: UnixTimestamp,
809
810    /// The number of slots per year, used for inflation
811    slots_per_year: f64,
812
813    /// Bank slot (i.e. block)
814    slot: Slot,
815
816    bank_id: BankId,
817
818    /// Bank epoch
819    epoch: Epoch,
820
821    /// Bank block_height
822    block_height: u64,
823
824    /// The pubkey to send transactions fees to.
825    collector_id: Pubkey,
826
827    /// Fees that have been collected
828    collector_fees: AtomicU64,
829
830    /// Track cluster signature throughput and adjust fee rate
831    pub(crate) fee_rate_governor: FeeRateGovernor,
832
833    /// Rent that has been collected
834    collected_rent: AtomicU64,
835
836    /// latest rent collector, knows the epoch
837    rent_collector: RentCollector,
838
839    /// initialized from genesis
840    pub(crate) epoch_schedule: EpochSchedule,
841
842    /// inflation specs
843    inflation: Arc<RwLock<Inflation>>,
844
845    /// cache of vote_account and stake_account state for this fork
846    stakes_cache: StakesCache,
847
848    /// staked nodes on epoch boundaries, saved off when a bank.slot() is at
849    ///   a leader schedule calculation boundary
850    epoch_stakes: HashMap<Epoch, EpochStakes>,
851
852    /// A boolean reflecting whether any entries were recorded into the PoH
853    /// stream for the slot == self.slot
854    is_delta: AtomicBool,
855
856    /// Protocol-level rewards that were distributed by this bank
857    pub rewards: RwLock<Vec<(Pubkey, RewardInfo)>>,
858
859    pub cluster_type: Option<ClusterType>,
860
861    pub lazy_rent_collection: AtomicBool,
862
863    // this is temporary field only to remove rewards_pool entirely
864    pub rewards_pool_pubkeys: Arc<HashSet<Pubkey>>,
865
866    transaction_debug_keys: Option<Arc<HashSet<Pubkey>>>,
867
868    // Global configuration for how transaction logs should be collected across all banks
869    pub transaction_log_collector_config: Arc<RwLock<TransactionLogCollectorConfig>>,
870
871    // Logs from transactions that this Bank executed collected according to the criteria in
872    // `transaction_log_collector_config`
873    pub transaction_log_collector: Arc<RwLock<TransactionLogCollector>>,
874
875    pub feature_set: Arc<FeatureSet>,
876
877    /// Set of reserved account keys that cannot be write locked
878    reserved_account_keys: Arc<ReservedAccountKeys>,
879
880    /// callback function only to be called when dropping and should only be called once
881    pub drop_callback: RwLock<OptionalDropCallback>,
882
883    pub freeze_started: AtomicBool,
884
885    vote_only_bank: bool,
886
887    cost_tracker: RwLock<CostTracker>,
888
889    /// The initial accounts data size at the start of this Bank, before processing any transactions/etc
890    accounts_data_size_initial: u64,
891    /// The change to accounts data size in this Bank, due on-chain events (i.e. transactions)
892    accounts_data_size_delta_on_chain: AtomicI64,
893    /// The change to accounts data size in this Bank, due to off-chain events (i.e. rent collection)
894    accounts_data_size_delta_off_chain: AtomicI64,
895
896    /// until the skipped rewrites feature is activated, it is possible to skip rewrites and still include
897    /// the account hash of the accounts that would have been rewritten as bank hash expects.
898    skipped_rewrites: Mutex<HashMap<Pubkey, AccountHash>>,
899
900    epoch_reward_status: EpochRewardStatus,
901
902    transaction_processor: TransactionBatchProcessor<BankForks>,
903
904    check_program_modification_slot: bool,
905
906    /// Collected fee details
907    collector_fee_details: RwLock<CollectorFeeDetails>,
908
909    /// The compute budget to use for transaction execution.
910    compute_budget: Option<ComputeBudget>,
911
912    /// The max number of accounts that a transaction may lock.
913    transaction_account_lock_limit: Option<usize>,
914
915    /// Fee structure to use for assessing transaction fees.
916    fee_structure: FeeStructure,
917
918    /// blockhash and bank_hash overrides keyed by slot for simulated block production.
919    /// This _field_ was needed to be DCOU-ed to avoid 2 locks per bank freezing...
920    #[cfg(feature = "dev-context-only-utils")]
921    hash_overrides: Arc<Mutex<HashOverrides>>,
922
923    /// The lattice hash of all accounts
924    ///
925    /// The value is only meaningful after freezing.
926    accounts_lt_hash: Mutex<AccountsLtHash>,
927
928    /// A cache of *the initial state* of accounts modified in this slot
929    ///
930    /// The accounts lt hash needs both the initial and final state of each
931    /// account that was modified in this slot.  Cache the initial state here.
932    ///
933    /// Note: The initial state must be strictly from an ancestor,
934    /// and not an intermediate state within this slot.
935    cache_for_accounts_lt_hash: DashMap<Pubkey, AccountsLtHashCacheValue, ahash::RandomState>,
936
937    /// Stats related to the accounts lt hash
938    stats_for_accounts_lt_hash: AccountsLtHashStats,
939
940    /// The unique identifier for the corresponding block for this bank.
941    /// None for banks that have not yet completed replay or for leader banks as we cannot populate block_id
942    /// until bankless leader. Can be computed directly from shreds without needing to execute transactions.
943    block_id: RwLock<Option<Hash>>,
944
945    /// Accounts stats for computing the bank hash
946    bank_hash_stats: AtomicBankHashStats,
947}
948
949#[derive(Debug)]
950struct VoteReward {
951    vote_account: AccountSharedData,
952    commission: u8,
953    vote_rewards: u64,
954    vote_needs_store: bool,
955}
956
957type VoteRewards = DashMap<Pubkey, VoteReward>;
958
959#[derive(Debug, Default)]
960pub struct NewBankOptions {
961    pub vote_only_bank: bool,
962}
963
964#[cfg(feature = "dev-context-only-utils")]
965#[derive(Debug)]
966pub struct BankTestConfig {
967    pub accounts_db_config: AccountsDbConfig,
968}
969
970#[cfg(feature = "dev-context-only-utils")]
971impl Default for BankTestConfig {
972    fn default() -> Self {
973        Self {
974            accounts_db_config: ACCOUNTS_DB_CONFIG_FOR_TESTING,
975        }
976    }
977}
978
979#[derive(Debug)]
980struct PrevEpochInflationRewards {
981    validator_rewards: u64,
982    prev_epoch_duration_in_years: f64,
983    validator_rate: f64,
984    foundation_rate: f64,
985}
986
987#[derive(Debug, Default, PartialEq)]
988pub struct ProcessedTransactionCounts {
989    pub processed_transactions_count: u64,
990    pub processed_non_vote_transactions_count: u64,
991    pub processed_with_successful_result_count: u64,
992    pub signature_count: u64,
993}
994
995/// Account stats for computing the bank hash
996/// This struct is serialized and stored in the snapshot.
997#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
998#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)]
999pub struct BankHashStats {
1000    pub num_updated_accounts: u64,
1001    pub num_removed_accounts: u64,
1002    pub num_lamports_stored: u64,
1003    pub total_data_len: u64,
1004    pub num_executable_accounts: u64,
1005}
1006
1007impl BankHashStats {
1008    pub fn update<T: ReadableAccount>(&mut self, account: &T) {
1009        if account.lamports() == 0 {
1010            self.num_removed_accounts += 1;
1011        } else {
1012            self.num_updated_accounts += 1;
1013        }
1014        self.total_data_len = self
1015            .total_data_len
1016            .wrapping_add(account.data().len() as u64);
1017        if account.executable() {
1018            self.num_executable_accounts += 1;
1019        }
1020        self.num_lamports_stored = self.num_lamports_stored.wrapping_add(account.lamports());
1021    }
1022    pub fn accumulate(&mut self, other: &BankHashStats) {
1023        self.num_updated_accounts += other.num_updated_accounts;
1024        self.num_removed_accounts += other.num_removed_accounts;
1025        self.total_data_len = self.total_data_len.wrapping_add(other.total_data_len);
1026        self.num_lamports_stored = self
1027            .num_lamports_stored
1028            .wrapping_add(other.num_lamports_stored);
1029        self.num_executable_accounts += other.num_executable_accounts;
1030    }
1031}
1032
1033#[derive(Debug, Default)]
1034pub struct AtomicBankHashStats {
1035    pub num_updated_accounts: AtomicU64,
1036    pub num_removed_accounts: AtomicU64,
1037    pub num_lamports_stored: AtomicU64,
1038    pub total_data_len: AtomicU64,
1039    pub num_executable_accounts: AtomicU64,
1040}
1041
1042impl AtomicBankHashStats {
1043    pub fn new(stat: &BankHashStats) -> Self {
1044        AtomicBankHashStats {
1045            num_updated_accounts: AtomicU64::new(stat.num_updated_accounts),
1046            num_removed_accounts: AtomicU64::new(stat.num_removed_accounts),
1047            num_lamports_stored: AtomicU64::new(stat.num_lamports_stored),
1048            total_data_len: AtomicU64::new(stat.total_data_len),
1049            num_executable_accounts: AtomicU64::new(stat.num_executable_accounts),
1050        }
1051    }
1052
1053    pub fn accumulate(&self, other: &BankHashStats) {
1054        self.num_updated_accounts
1055            .fetch_add(other.num_updated_accounts, Relaxed);
1056        self.num_removed_accounts
1057            .fetch_add(other.num_removed_accounts, Relaxed);
1058        self.total_data_len.fetch_add(other.total_data_len, Relaxed);
1059        self.num_lamports_stored
1060            .fetch_add(other.num_lamports_stored, Relaxed);
1061        self.num_executable_accounts
1062            .fetch_add(other.num_executable_accounts, Relaxed);
1063    }
1064
1065    pub fn load(&self) -> BankHashStats {
1066        BankHashStats {
1067            num_updated_accounts: self.num_updated_accounts.load(Relaxed),
1068            num_removed_accounts: self.num_removed_accounts.load(Relaxed),
1069            num_lamports_stored: self.num_lamports_stored.load(Relaxed),
1070            total_data_len: self.total_data_len.load(Relaxed),
1071            num_executable_accounts: self.num_executable_accounts.load(Relaxed),
1072        }
1073    }
1074}
1075
1076impl Bank {
1077    fn default_with_accounts(accounts: Accounts) -> Self {
1078        let mut bank = Self {
1079            skipped_rewrites: Mutex::default(),
1080            rc: BankRc::new(accounts),
1081            status_cache: Arc::<RwLock<BankStatusCache>>::default(),
1082            blockhash_queue: RwLock::<BlockhashQueue>::default(),
1083            ancestors: Ancestors::default(),
1084            hash: RwLock::<Hash>::default(),
1085            parent_hash: Hash::default(),
1086            parent_slot: Slot::default(),
1087            hard_forks: Arc::<RwLock<HardForks>>::default(),
1088            transaction_count: AtomicU64::default(),
1089            non_vote_transaction_count_since_restart: AtomicU64::default(),
1090            transaction_error_count: AtomicU64::default(),
1091            transaction_entries_count: AtomicU64::default(),
1092            transactions_per_entry_max: AtomicU64::default(),
1093            tick_height: AtomicU64::default(),
1094            signature_count: AtomicU64::default(),
1095            capitalization: AtomicU64::default(),
1096            max_tick_height: u64::default(),
1097            hashes_per_tick: Option::<u64>::default(),
1098            ticks_per_slot: u64::default(),
1099            ns_per_slot: u128::default(),
1100            genesis_creation_time: UnixTimestamp::default(),
1101            slots_per_year: f64::default(),
1102            slot: Slot::default(),
1103            bank_id: BankId::default(),
1104            epoch: Epoch::default(),
1105            block_height: u64::default(),
1106            collector_id: Pubkey::default(),
1107            collector_fees: AtomicU64::default(),
1108            fee_rate_governor: FeeRateGovernor::default(),
1109            collected_rent: AtomicU64::default(),
1110            rent_collector: RentCollector::default(),
1111            epoch_schedule: EpochSchedule::default(),
1112            inflation: Arc::<RwLock<Inflation>>::default(),
1113            stakes_cache: StakesCache::default(),
1114            epoch_stakes: HashMap::<Epoch, EpochStakes>::default(),
1115            is_delta: AtomicBool::default(),
1116            rewards: RwLock::<Vec<(Pubkey, RewardInfo)>>::default(),
1117            cluster_type: Option::<ClusterType>::default(),
1118            lazy_rent_collection: AtomicBool::default(),
1119            rewards_pool_pubkeys: Arc::<HashSet<Pubkey>>::default(),
1120            transaction_debug_keys: Option::<Arc<HashSet<Pubkey>>>::default(),
1121            transaction_log_collector_config: Arc::<RwLock<TransactionLogCollectorConfig>>::default(
1122            ),
1123            transaction_log_collector: Arc::<RwLock<TransactionLogCollector>>::default(),
1124            feature_set: Arc::<FeatureSet>::default(),
1125            reserved_account_keys: Arc::<ReservedAccountKeys>::default(),
1126            drop_callback: RwLock::new(OptionalDropCallback(None)),
1127            freeze_started: AtomicBool::default(),
1128            vote_only_bank: false,
1129            cost_tracker: RwLock::<CostTracker>::default(),
1130            accounts_data_size_initial: 0,
1131            accounts_data_size_delta_on_chain: AtomicI64::new(0),
1132            accounts_data_size_delta_off_chain: AtomicI64::new(0),
1133            epoch_reward_status: EpochRewardStatus::default(),
1134            transaction_processor: TransactionBatchProcessor::default(),
1135            check_program_modification_slot: false,
1136            collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
1137            compute_budget: None,
1138            transaction_account_lock_limit: None,
1139            fee_structure: FeeStructure::default(),
1140            #[cfg(feature = "dev-context-only-utils")]
1141            hash_overrides: Arc::new(Mutex::new(HashOverrides::default())),
1142            accounts_lt_hash: Mutex::new(AccountsLtHash(LtHash::identity())),
1143            cache_for_accounts_lt_hash: DashMap::default(),
1144            stats_for_accounts_lt_hash: AccountsLtHashStats::default(),
1145            block_id: RwLock::new(None),
1146            bank_hash_stats: AtomicBankHashStats::default(),
1147        };
1148
1149        bank.transaction_processor =
1150            TransactionBatchProcessor::new_uninitialized(bank.slot, bank.epoch);
1151
1152        let accounts_data_size_initial = bank.get_total_accounts_stats().unwrap().data_len as u64;
1153        bank.accounts_data_size_initial = accounts_data_size_initial;
1154
1155        bank
1156    }
1157
1158    #[allow(clippy::too_many_arguments)]
1159    pub fn new_with_paths(
1160        genesis_config: &GenesisConfig,
1161        runtime_config: Arc<RuntimeConfig>,
1162        paths: Vec<PathBuf>,
1163        debug_keys: Option<Arc<HashSet<Pubkey>>>,
1164        additional_builtins: Option<&[BuiltinPrototype]>,
1165        debug_do_not_add_builtins: bool,
1166        accounts_db_config: Option<AccountsDbConfig>,
1167        accounts_update_notifier: Option<AccountsUpdateNotifier>,
1168        #[allow(unused)] collector_id_for_tests: Option<Pubkey>,
1169        exit: Arc<AtomicBool>,
1170        #[allow(unused)] genesis_hash: Option<Hash>,
1171        #[allow(unused)] feature_set: Option<FeatureSet>,
1172    ) -> Self {
1173        let accounts_db =
1174            AccountsDb::new_with_config(paths, accounts_db_config, accounts_update_notifier, exit);
1175        let accounts = Accounts::new(Arc::new(accounts_db));
1176        let mut bank = Self::default_with_accounts(accounts);
1177        bank.ancestors = Ancestors::from(vec![bank.slot()]);
1178        bank.compute_budget = runtime_config.compute_budget;
1179        bank.transaction_account_lock_limit = runtime_config.transaction_account_lock_limit;
1180        bank.transaction_debug_keys = debug_keys;
1181        bank.cluster_type = Some(genesis_config.cluster_type);
1182
1183        #[cfg(feature = "dev-context-only-utils")]
1184        {
1185            bank.feature_set = Arc::new(feature_set.unwrap_or_default());
1186        }
1187
1188        #[cfg(not(feature = "dev-context-only-utils"))]
1189        bank.process_genesis_config(genesis_config);
1190        #[cfg(feature = "dev-context-only-utils")]
1191        bank.process_genesis_config(genesis_config, collector_id_for_tests, genesis_hash);
1192
1193        bank.finish_init(
1194            genesis_config,
1195            additional_builtins,
1196            debug_do_not_add_builtins,
1197        );
1198
1199        // genesis needs stakes for all epochs up to the epoch implied by
1200        //  slot = 0 and genesis configuration
1201        {
1202            let stakes = bank.stakes_cache.stakes().clone();
1203            let stakes = Arc::new(StakesEnum::from(stakes));
1204            for epoch in 0..=bank.get_leader_schedule_epoch(bank.slot) {
1205                bank.epoch_stakes
1206                    .insert(epoch, EpochStakes::new(stakes.clone(), epoch));
1207            }
1208            bank.update_stake_history(None);
1209        }
1210        bank.update_clock(None);
1211        bank.update_rent();
1212        bank.update_epoch_schedule();
1213        bank.update_recent_blockhashes();
1214        bank.update_last_restart_slot();
1215        bank.transaction_processor
1216            .fill_missing_sysvar_cache_entries(&bank);
1217        bank
1218    }
1219
1220    /// Create a new bank that points to an immutable checkpoint of another bank.
1221    pub fn new_from_parent(parent: Arc<Bank>, collector_id: &Pubkey, slot: Slot) -> Self {
1222        Self::_new_from_parent(
1223            parent,
1224            collector_id,
1225            slot,
1226            null_tracer(),
1227            NewBankOptions::default(),
1228        )
1229    }
1230
1231    pub fn new_from_parent_with_options(
1232        parent: Arc<Bank>,
1233        collector_id: &Pubkey,
1234        slot: Slot,
1235        new_bank_options: NewBankOptions,
1236    ) -> Self {
1237        Self::_new_from_parent(parent, collector_id, slot, null_tracer(), new_bank_options)
1238    }
1239
1240    pub fn new_from_parent_with_tracer(
1241        parent: Arc<Bank>,
1242        collector_id: &Pubkey,
1243        slot: Slot,
1244        reward_calc_tracer: impl RewardCalcTracer,
1245    ) -> Self {
1246        Self::_new_from_parent(
1247            parent,
1248            collector_id,
1249            slot,
1250            Some(reward_calc_tracer),
1251            NewBankOptions::default(),
1252        )
1253    }
1254
1255    fn get_rent_collector_from(rent_collector: &RentCollector, epoch: Epoch) -> RentCollector {
1256        rent_collector.clone_with_epoch(epoch)
1257    }
1258
1259    fn _new_from_parent(
1260        parent: Arc<Bank>,
1261        collector_id: &Pubkey,
1262        slot: Slot,
1263        reward_calc_tracer: Option<impl RewardCalcTracer>,
1264        new_bank_options: NewBankOptions,
1265    ) -> Self {
1266        let mut time = Measure::start("bank::new_from_parent");
1267        let NewBankOptions { vote_only_bank } = new_bank_options;
1268
1269        parent.freeze();
1270        assert_ne!(slot, parent.slot());
1271
1272        let epoch_schedule = parent.epoch_schedule().clone();
1273        let epoch = epoch_schedule.get_epoch(slot);
1274
1275        let (rc, bank_rc_creation_time_us) = measure_us!({
1276            let accounts_db = Arc::clone(&parent.rc.accounts.accounts_db);
1277            BankRc {
1278                accounts: Arc::new(Accounts::new(accounts_db)),
1279                parent: RwLock::new(Some(Arc::clone(&parent))),
1280                bank_id_generator: Arc::clone(&parent.rc.bank_id_generator),
1281            }
1282        });
1283
1284        let (status_cache, status_cache_time_us) = measure_us!(Arc::clone(&parent.status_cache));
1285
1286        let (fee_rate_governor, fee_components_time_us) = measure_us!(
1287            FeeRateGovernor::new_derived(&parent.fee_rate_governor, parent.signature_count())
1288        );
1289
1290        let bank_id = rc.bank_id_generator.fetch_add(1, Relaxed) + 1;
1291        let (blockhash_queue, blockhash_queue_time_us) =
1292            measure_us!(RwLock::new(parent.blockhash_queue.read().unwrap().clone()));
1293
1294        let (stakes_cache, stakes_cache_time_us) =
1295            measure_us!(StakesCache::new(parent.stakes_cache.stakes().clone()));
1296
1297        let (epoch_stakes, epoch_stakes_time_us) = measure_us!(parent.epoch_stakes.clone());
1298
1299        let (transaction_processor, builtin_program_ids_time_us) = measure_us!(
1300            TransactionBatchProcessor::new_from(&parent.transaction_processor, slot, epoch)
1301        );
1302
1303        let (rewards_pool_pubkeys, rewards_pool_pubkeys_time_us) =
1304            measure_us!(parent.rewards_pool_pubkeys.clone());
1305
1306        let (transaction_debug_keys, transaction_debug_keys_time_us) =
1307            measure_us!(parent.transaction_debug_keys.clone());
1308
1309        let (transaction_log_collector_config, transaction_log_collector_config_time_us) =
1310            measure_us!(parent.transaction_log_collector_config.clone());
1311
1312        let (feature_set, feature_set_time_us) = measure_us!(parent.feature_set.clone());
1313
1314        let accounts_data_size_initial = parent.load_accounts_data_size();
1315        let mut new = Self {
1316            skipped_rewrites: Mutex::default(),
1317            rc,
1318            status_cache,
1319            slot,
1320            bank_id,
1321            epoch,
1322            blockhash_queue,
1323
1324            // TODO: clean this up, so much special-case copying...
1325            hashes_per_tick: parent.hashes_per_tick,
1326            ticks_per_slot: parent.ticks_per_slot,
1327            ns_per_slot: parent.ns_per_slot,
1328            genesis_creation_time: parent.genesis_creation_time,
1329            slots_per_year: parent.slots_per_year,
1330            epoch_schedule,
1331            collected_rent: AtomicU64::new(0),
1332            rent_collector: Self::get_rent_collector_from(&parent.rent_collector, epoch),
1333            max_tick_height: slot
1334                .checked_add(1)
1335                .expect("max tick height addition overflowed")
1336                .checked_mul(parent.ticks_per_slot)
1337                .expect("max tick height multiplication overflowed"),
1338            block_height: parent
1339                .block_height
1340                .checked_add(1)
1341                .expect("block height addition overflowed"),
1342            fee_rate_governor,
1343            capitalization: AtomicU64::new(parent.capitalization()),
1344            vote_only_bank,
1345            inflation: parent.inflation.clone(),
1346            transaction_count: AtomicU64::new(parent.transaction_count()),
1347            non_vote_transaction_count_since_restart: AtomicU64::new(
1348                parent.non_vote_transaction_count_since_restart(),
1349            ),
1350            transaction_error_count: AtomicU64::new(0),
1351            transaction_entries_count: AtomicU64::new(0),
1352            transactions_per_entry_max: AtomicU64::new(0),
1353            // we will .clone_with_epoch() this soon after stake data update; so just .clone() for now
1354            stakes_cache,
1355            epoch_stakes,
1356            parent_hash: parent.hash(),
1357            parent_slot: parent.slot(),
1358            collector_id: *collector_id,
1359            collector_fees: AtomicU64::new(0),
1360            ancestors: Ancestors::default(),
1361            hash: RwLock::new(Hash::default()),
1362            is_delta: AtomicBool::new(false),
1363            tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
1364            signature_count: AtomicU64::new(0),
1365            hard_forks: parent.hard_forks.clone(),
1366            rewards: RwLock::new(vec![]),
1367            cluster_type: parent.cluster_type,
1368            lazy_rent_collection: AtomicBool::new(parent.lazy_rent_collection.load(Relaxed)),
1369            rewards_pool_pubkeys,
1370            transaction_debug_keys,
1371            transaction_log_collector_config,
1372            transaction_log_collector: Arc::new(RwLock::new(TransactionLogCollector::default())),
1373            feature_set: Arc::clone(&feature_set),
1374            reserved_account_keys: parent.reserved_account_keys.clone(),
1375            drop_callback: RwLock::new(OptionalDropCallback(
1376                parent
1377                    .drop_callback
1378                    .read()
1379                    .unwrap()
1380                    .0
1381                    .as_ref()
1382                    .map(|drop_callback| drop_callback.clone_box()),
1383            )),
1384            freeze_started: AtomicBool::new(false),
1385            cost_tracker: RwLock::new(parent.read_cost_tracker().unwrap().new_from_parent_limits()),
1386            accounts_data_size_initial,
1387            accounts_data_size_delta_on_chain: AtomicI64::new(0),
1388            accounts_data_size_delta_off_chain: AtomicI64::new(0),
1389            epoch_reward_status: parent.epoch_reward_status.clone(),
1390            transaction_processor,
1391            check_program_modification_slot: false,
1392            collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
1393            compute_budget: parent.compute_budget,
1394            transaction_account_lock_limit: parent.transaction_account_lock_limit,
1395            fee_structure: parent.fee_structure.clone(),
1396            #[cfg(feature = "dev-context-only-utils")]
1397            hash_overrides: parent.hash_overrides.clone(),
1398            accounts_lt_hash: Mutex::new(parent.accounts_lt_hash.lock().unwrap().clone()),
1399            cache_for_accounts_lt_hash: DashMap::default(),
1400            stats_for_accounts_lt_hash: AccountsLtHashStats::default(),
1401            block_id: RwLock::new(None),
1402            bank_hash_stats: AtomicBankHashStats::default(),
1403        };
1404
1405        let (_, ancestors_time_us) = measure_us!({
1406            let mut ancestors = Vec::with_capacity(1 + new.parents().len());
1407            ancestors.push(new.slot());
1408            new.parents().iter().for_each(|p| {
1409                ancestors.push(p.slot());
1410            });
1411            new.ancestors = Ancestors::from(ancestors);
1412        });
1413
1414        // Following code may touch AccountsDb, requiring proper ancestors
1415        let (_, update_epoch_time_us) = measure_us!({
1416            if parent.epoch() < new.epoch() {
1417                new.process_new_epoch(
1418                    parent.epoch(),
1419                    parent.slot(),
1420                    parent.block_height(),
1421                    reward_calc_tracer,
1422                );
1423            } else {
1424                // Save a snapshot of stakes for use in consensus and stake weighted networking
1425                let leader_schedule_epoch = new.epoch_schedule().get_leader_schedule_epoch(slot);
1426                new.update_epoch_stakes(leader_schedule_epoch);
1427            }
1428            new.distribute_partitioned_epoch_rewards();
1429        });
1430
1431        let (_epoch, slot_index) = new.epoch_schedule.get_epoch_and_slot_index(new.slot);
1432        let slots_in_epoch = new.epoch_schedule.get_slots_in_epoch(new.epoch);
1433
1434        let (_, cache_preparation_time_us) = measure_us!(new
1435            .transaction_processor
1436            .prepare_program_cache_for_upcoming_feature_set(
1437                &new,
1438                &new.compute_active_feature_set(true).0,
1439                &new.compute_budget.unwrap_or_default(),
1440                slot_index,
1441                slots_in_epoch,
1442            ));
1443
1444        // Update sysvars before processing transactions
1445        let (_, update_sysvars_time_us) = measure_us!({
1446            new.update_slot_hashes();
1447            new.update_stake_history(Some(parent.epoch()));
1448            new.update_clock(Some(parent.epoch()));
1449            new.update_last_restart_slot()
1450        });
1451
1452        let (_, fill_sysvar_cache_time_us) = measure_us!(new
1453            .transaction_processor
1454            .fill_missing_sysvar_cache_entries(&new));
1455
1456        let (num_accounts_modified_this_slot, populate_cache_for_accounts_lt_hash_us) = new
1457            .is_accounts_lt_hash_enabled()
1458            .then(|| {
1459                measure_us!({
1460                    // The cache for accounts lt hash needs to be made aware of accounts modified
1461                    // before transaction processing begins.  Otherwise we may calculate the wrong
1462                    // accounts lt hash due to having the wrong initial state of the account.  The
1463                    // lt hash cache's initial state must always be from an ancestor, and cannot be
1464                    // an intermediate state within this Bank's slot.  If the lt hash cache has the
1465                    // wrong initial account state, we'll mix out the wrong lt hash value, and thus
1466                    // have the wrong overall accounts lt hash, and diverge.
1467                    let accounts_modified_this_slot =
1468                        new.rc.accounts.accounts_db.get_pubkeys_for_slot(slot);
1469                    let num_accounts_modified_this_slot = accounts_modified_this_slot.len();
1470                    for pubkey in accounts_modified_this_slot {
1471                        new.cache_for_accounts_lt_hash
1472                            .entry(pubkey)
1473                            .or_insert(AccountsLtHashCacheValue::BankNew);
1474                    }
1475                    num_accounts_modified_this_slot
1476                })
1477            })
1478            .unzip();
1479
1480        time.stop();
1481        report_new_bank_metrics(
1482            slot,
1483            parent.slot(),
1484            new.block_height,
1485            num_accounts_modified_this_slot,
1486            NewBankTimings {
1487                bank_rc_creation_time_us,
1488                total_elapsed_time_us: time.as_us(),
1489                status_cache_time_us,
1490                fee_components_time_us,
1491                blockhash_queue_time_us,
1492                stakes_cache_time_us,
1493                epoch_stakes_time_us,
1494                builtin_program_ids_time_us,
1495                rewards_pool_pubkeys_time_us,
1496                executor_cache_time_us: 0,
1497                transaction_debug_keys_time_us,
1498                transaction_log_collector_config_time_us,
1499                feature_set_time_us,
1500                ancestors_time_us,
1501                update_epoch_time_us,
1502                cache_preparation_time_us,
1503                update_sysvars_time_us,
1504                fill_sysvar_cache_time_us,
1505                populate_cache_for_accounts_lt_hash_us,
1506            },
1507        );
1508
1509        report_loaded_programs_stats(
1510            &parent
1511                .transaction_processor
1512                .program_cache
1513                .read()
1514                .unwrap()
1515                .stats,
1516            parent.slot(),
1517        );
1518
1519        new.transaction_processor
1520            .program_cache
1521            .write()
1522            .unwrap()
1523            .stats
1524            .reset();
1525
1526        new
1527    }
1528
1529    pub fn set_fork_graph_in_program_cache(&self, fork_graph: Weak<RwLock<BankForks>>) {
1530        self.transaction_processor
1531            .program_cache
1532            .write()
1533            .unwrap()
1534            .set_fork_graph(fork_graph);
1535    }
1536
1537    pub fn prune_program_cache(&self, new_root_slot: Slot, new_root_epoch: Epoch) {
1538        self.transaction_processor
1539            .program_cache
1540            .write()
1541            .unwrap()
1542            .prune(new_root_slot, new_root_epoch);
1543    }
1544
1545    pub fn prune_program_cache_by_deployment_slot(&self, deployment_slot: Slot) {
1546        self.transaction_processor
1547            .program_cache
1548            .write()
1549            .unwrap()
1550            .prune_by_deployment_slot(deployment_slot);
1551    }
1552
1553    /// Epoch in which the new cooldown warmup rate for stake was activated
1554    pub fn new_warmup_cooldown_rate_epoch(&self) -> Option<Epoch> {
1555        self.feature_set
1556            .new_warmup_cooldown_rate_epoch(&self.epoch_schedule)
1557    }
1558
1559    /// process for the start of a new epoch
1560    fn process_new_epoch(
1561        &mut self,
1562        parent_epoch: Epoch,
1563        parent_slot: Slot,
1564        parent_height: u64,
1565        reward_calc_tracer: Option<impl RewardCalcTracer>,
1566    ) {
1567        let epoch = self.epoch();
1568        let slot = self.slot();
1569        let (thread_pool, thread_pool_time_us) = measure_us!(ThreadPoolBuilder::new()
1570            .thread_name(|i| format!("solBnkNewEpch{i:02}"))
1571            .build()
1572            .expect("new rayon threadpool"));
1573
1574        let (_, apply_feature_activations_time_us) = measure_us!(thread_pool.install(|| {
1575            self.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false)
1576        }));
1577
1578        // Add new entry to stakes.stake_history, set appropriate epoch and
1579        // update vote accounts with warmed up stakes before saving a
1580        // snapshot of stakes in epoch stakes
1581        let (_, activate_epoch_time_us) = measure_us!(self.stakes_cache.activate_epoch(
1582            epoch,
1583            &thread_pool,
1584            self.new_warmup_cooldown_rate_epoch()
1585        ));
1586
1587        // Save a snapshot of stakes for use in consensus and stake weighted networking
1588        let leader_schedule_epoch = self.epoch_schedule.get_leader_schedule_epoch(slot);
1589        let (_, update_epoch_stakes_time_us) =
1590            measure_us!(self.update_epoch_stakes(leader_schedule_epoch));
1591
1592        let mut rewards_metrics = RewardsMetrics::default();
1593        // After saving a snapshot of stakes, apply stake rewards and commission
1594        let (_, update_rewards_with_thread_pool_time_us) = measure_us!(self
1595            .begin_partitioned_rewards(
1596                reward_calc_tracer,
1597                &thread_pool,
1598                parent_epoch,
1599                parent_slot,
1600                parent_height,
1601                &mut rewards_metrics,
1602            ));
1603
1604        report_new_epoch_metrics(
1605            epoch,
1606            slot,
1607            parent_slot,
1608            NewEpochTimings {
1609                thread_pool_time_us,
1610                apply_feature_activations_time_us,
1611                activate_epoch_time_us,
1612                update_epoch_stakes_time_us,
1613                update_rewards_with_thread_pool_time_us,
1614            },
1615            rewards_metrics,
1616        );
1617    }
1618
1619    pub fn byte_limit_for_scans(&self) -> Option<usize> {
1620        self.rc
1621            .accounts
1622            .accounts_db
1623            .accounts_index
1624            .scan_results_limit_bytes
1625    }
1626
1627    pub fn proper_ancestors_set(&self) -> HashSet<Slot> {
1628        HashSet::from_iter(self.proper_ancestors())
1629    }
1630
1631    /// Returns all ancestors excluding self.slot.
1632    pub(crate) fn proper_ancestors(&self) -> impl Iterator<Item = Slot> + '_ {
1633        self.ancestors
1634            .keys()
1635            .into_iter()
1636            .filter(move |slot| *slot != self.slot)
1637    }
1638
1639    pub fn set_callback(&self, callback: Option<Box<dyn DropCallback + Send + Sync>>) {
1640        *self.drop_callback.write().unwrap() = OptionalDropCallback(callback);
1641    }
1642
1643    pub fn vote_only_bank(&self) -> bool {
1644        self.vote_only_bank
1645    }
1646
1647    /// Like `new_from_parent` but additionally:
1648    /// * Doesn't assume that the parent is anywhere near `slot`, parent could be millions of slots
1649    ///   in the past
1650    /// * Adjusts the new bank's tick height to avoid having to run PoH for millions of slots
1651    /// * Freezes the new bank, assuming that the user will `Bank::new_from_parent` from this bank
1652    /// * Calculates and sets the epoch accounts hash from the parent
1653    pub fn warp_from_parent(
1654        parent: Arc<Bank>,
1655        collector_id: &Pubkey,
1656        slot: Slot,
1657        data_source: CalcAccountsHashDataSource,
1658    ) -> Self {
1659        parent.freeze();
1660        parent
1661            .rc
1662            .accounts
1663            .accounts_db
1664            .epoch_accounts_hash_manager
1665            .set_in_flight(parent.slot());
1666        let accounts_hash = parent.update_accounts_hash(data_source, false, true);
1667        let epoch_accounts_hash = accounts_hash.into();
1668        parent
1669            .rc
1670            .accounts
1671            .accounts_db
1672            .epoch_accounts_hash_manager
1673            .set_valid(epoch_accounts_hash, parent.slot());
1674
1675        let parent_timestamp = parent.clock().unix_timestamp;
1676        let mut new = Bank::new_from_parent(parent, collector_id, slot);
1677        new.apply_feature_activations(ApplyFeatureActivationsCaller::WarpFromParent, false);
1678        new.update_epoch_stakes(new.epoch_schedule().get_epoch(slot));
1679        new.tick_height.store(new.max_tick_height(), Relaxed);
1680
1681        let mut clock = new.clock();
1682        clock.epoch_start_timestamp = parent_timestamp;
1683        clock.unix_timestamp = parent_timestamp;
1684        new.update_sysvar_account(&sysvar::clock::id(), |account| {
1685            create_account(
1686                &clock,
1687                new.inherit_specially_retained_account_fields(account),
1688            )
1689        });
1690        new.transaction_processor
1691            .fill_missing_sysvar_cache_entries(&new);
1692        new.freeze();
1693        new
1694    }
1695
1696    /// Create a bank from explicit arguments and deserialized fields from snapshot
1697    pub(crate) fn new_from_fields(
1698        bank_rc: BankRc,
1699        genesis_config: &GenesisConfig,
1700        runtime_config: Arc<RuntimeConfig>,
1701        fields: BankFieldsToDeserialize,
1702        debug_keys: Option<Arc<HashSet<Pubkey>>>,
1703        additional_builtins: Option<&[BuiltinPrototype]>,
1704        debug_do_not_add_builtins: bool,
1705        accounts_data_size_initial: u64,
1706    ) -> Self {
1707        let now = Instant::now();
1708        let ancestors = Ancestors::from(&fields.ancestors);
1709        // For backward compatibility, we can only serialize and deserialize
1710        // Stakes<Delegation> in BankFieldsTo{Serialize,Deserialize}. But Bank
1711        // caches Stakes<StakeAccount>. Below Stakes<StakeAccount> is obtained
1712        // from Stakes<Delegation> by reading the full account state from
1713        // accounts-db. Note that it is crucial that these accounts are loaded
1714        // at the right slot and match precisely with serialized Delegations.
1715        //
1716        // Note that we are disabling the read cache while we populate the stakes cache.
1717        // The stakes accounts will not be expected to be loaded again.
1718        // If we populate the read cache with these loads, then we'll just soon have to evict these.
1719        let (stakes, stakes_time) = measure_time!(Stakes::new(&fields.stakes, |pubkey| {
1720            let (account, _slot) = bank_rc
1721                .accounts
1722                .load_with_fixed_root_do_not_populate_read_cache(&ancestors, pubkey)?;
1723            Some(account)
1724        })
1725        .expect(
1726            "Stakes cache is inconsistent with accounts-db. This can indicate \
1727            a corrupted snapshot or bugs in cached accounts or accounts-db.",
1728        ));
1729        info!("Loading Stakes took: {stakes_time}");
1730        let stakes_accounts_load_duration = now.elapsed();
1731        let mut bank = Self {
1732            skipped_rewrites: Mutex::default(),
1733            rc: bank_rc,
1734            status_cache: Arc::<RwLock<BankStatusCache>>::default(),
1735            blockhash_queue: RwLock::new(fields.blockhash_queue),
1736            ancestors,
1737            hash: RwLock::new(fields.hash),
1738            parent_hash: fields.parent_hash,
1739            parent_slot: fields.parent_slot,
1740            hard_forks: Arc::new(RwLock::new(fields.hard_forks)),
1741            transaction_count: AtomicU64::new(fields.transaction_count),
1742            non_vote_transaction_count_since_restart: AtomicU64::default(),
1743            transaction_error_count: AtomicU64::default(),
1744            transaction_entries_count: AtomicU64::default(),
1745            transactions_per_entry_max: AtomicU64::default(),
1746            tick_height: AtomicU64::new(fields.tick_height),
1747            signature_count: AtomicU64::new(fields.signature_count),
1748            capitalization: AtomicU64::new(fields.capitalization),
1749            max_tick_height: fields.max_tick_height,
1750            hashes_per_tick: fields.hashes_per_tick,
1751            ticks_per_slot: fields.ticks_per_slot,
1752            ns_per_slot: fields.ns_per_slot,
1753            genesis_creation_time: fields.genesis_creation_time,
1754            slots_per_year: fields.slots_per_year,
1755            slot: fields.slot,
1756            bank_id: 0,
1757            epoch: fields.epoch,
1758            block_height: fields.block_height,
1759            collector_id: fields.collector_id,
1760            collector_fees: AtomicU64::new(fields.collector_fees),
1761            fee_rate_governor: fields.fee_rate_governor,
1762            collected_rent: AtomicU64::new(fields.collected_rent),
1763            // clone()-ing is needed to consider a gated behavior in rent_collector
1764            rent_collector: Self::get_rent_collector_from(&fields.rent_collector, fields.epoch),
1765            epoch_schedule: fields.epoch_schedule,
1766            inflation: Arc::new(RwLock::new(fields.inflation)),
1767            stakes_cache: StakesCache::new(stakes),
1768            epoch_stakes: fields.epoch_stakes,
1769            is_delta: AtomicBool::new(fields.is_delta),
1770            rewards: RwLock::new(vec![]),
1771            cluster_type: Some(genesis_config.cluster_type),
1772            lazy_rent_collection: AtomicBool::default(),
1773            rewards_pool_pubkeys: Arc::<HashSet<Pubkey>>::default(),
1774            transaction_debug_keys: debug_keys,
1775            transaction_log_collector_config: Arc::<RwLock<TransactionLogCollectorConfig>>::default(
1776            ),
1777            transaction_log_collector: Arc::<RwLock<TransactionLogCollector>>::default(),
1778            feature_set: Arc::<FeatureSet>::default(),
1779            reserved_account_keys: Arc::<ReservedAccountKeys>::default(),
1780            drop_callback: RwLock::new(OptionalDropCallback(None)),
1781            freeze_started: AtomicBool::new(fields.hash != Hash::default()),
1782            vote_only_bank: false,
1783            cost_tracker: RwLock::new(CostTracker::default()),
1784            accounts_data_size_initial,
1785            accounts_data_size_delta_on_chain: AtomicI64::new(0),
1786            accounts_data_size_delta_off_chain: AtomicI64::new(0),
1787            epoch_reward_status: EpochRewardStatus::default(),
1788            transaction_processor: TransactionBatchProcessor::default(),
1789            check_program_modification_slot: false,
1790            // collector_fee_details is not serialized to snapshot
1791            collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
1792            compute_budget: runtime_config.compute_budget,
1793            transaction_account_lock_limit: runtime_config.transaction_account_lock_limit,
1794            fee_structure: FeeStructure::default(),
1795            #[cfg(feature = "dev-context-only-utils")]
1796            hash_overrides: Arc::new(Mutex::new(HashOverrides::default())),
1797            accounts_lt_hash: Mutex::new(AccountsLtHash(LtHash([0xBAD1; LtHash::NUM_ELEMENTS]))),
1798            cache_for_accounts_lt_hash: DashMap::default(),
1799            stats_for_accounts_lt_hash: AccountsLtHashStats::default(),
1800            block_id: RwLock::new(None),
1801            bank_hash_stats: AtomicBankHashStats::new(&fields.bank_hash_stats),
1802        };
1803
1804        bank.transaction_processor =
1805            TransactionBatchProcessor::new_uninitialized(bank.slot, bank.epoch);
1806
1807        let thread_pool = ThreadPoolBuilder::new()
1808            .thread_name(|i| format!("solBnkNewFlds{i:02}"))
1809            .build()
1810            .expect("new rayon threadpool");
1811        bank.recalculate_partitioned_rewards(null_tracer(), &thread_pool);
1812
1813        bank.finish_init(
1814            genesis_config,
1815            additional_builtins,
1816            debug_do_not_add_builtins,
1817        );
1818        bank.transaction_processor
1819            .fill_missing_sysvar_cache_entries(&bank);
1820        bank.rebuild_skipped_rewrites();
1821
1822        let mut calculate_accounts_lt_hash_duration = None;
1823        if let Some(accounts_lt_hash) = fields.accounts_lt_hash {
1824            *bank.accounts_lt_hash.get_mut().unwrap() = accounts_lt_hash;
1825        } else {
1826            // Use the accounts lt hash from the snapshot, if present, otherwise calculate it.
1827            // When the feature gate is enabled, the snapshot *must* contain an accounts lt hash.
1828            assert!(
1829                !bank
1830                    .feature_set
1831                    .is_active(&feature_set::accounts_lt_hash::id()),
1832                "snapshot must have an accounts lt hash if the feature is enabled",
1833            );
1834            if bank.is_accounts_lt_hash_enabled() {
1835                info!(
1836                    "Calculating the accounts lt hash for slot {}...",
1837                    bank.slot(),
1838                );
1839                let (ancestors, slot) = if bank.is_frozen() {
1840                    // Loading from a snapshot necessarily means this slot was rooted, and thus
1841                    // the bank has been frozen.  So when calculating the accounts lt hash,
1842                    // do it based on *this slot*, not our parent, since
1843                    // update_accounts_lt_hash() will not be called on us again.
1844                    (bank.ancestors.clone(), bank.slot())
1845                } else {
1846                    // If the bank is not frozen (e.g. if called from tests), then when this bank
1847                    // is frozen later it will call `update_accounts_lt_hash()`.  Therefore, we
1848                    // must calculate the accounts lt hash *here* based on *our parent*, so that
1849                    // the accounts lt hash is correct after freezing.
1850                    let parent_ancestors = {
1851                        let mut ancestors = bank.ancestors.clone();
1852                        ancestors.remove(&bank.slot());
1853                        ancestors
1854                    };
1855                    (parent_ancestors, bank.parent_slot)
1856                };
1857                let (accounts_lt_hash, duration) = meas_dur!({
1858                    thread_pool.install(|| {
1859                        bank.rc
1860                            .accounts
1861                            .accounts_db
1862                            .calculate_accounts_lt_hash_at_startup_from_index(&ancestors, slot)
1863                    })
1864                });
1865                calculate_accounts_lt_hash_duration = Some(duration);
1866                *bank.accounts_lt_hash.get_mut().unwrap() = accounts_lt_hash;
1867                info!(
1868                    "Calculating the accounts lt hash for slot {}... \
1869                     Done in {duration:?}, accounts_lt_hash checksum: {}",
1870                    bank.slot(),
1871                    bank.accounts_lt_hash.get_mut().unwrap().0.checksum(),
1872                );
1873            }
1874        }
1875
1876        // Sanity assertions between bank snapshot and genesis config
1877        // Consider removing from serializable bank state
1878        // (BankFieldsToSerialize/BankFieldsToDeserialize) and initializing
1879        // from the passed in genesis_config instead (as new()/new_with_paths() already do)
1880        assert_eq!(
1881            bank.genesis_creation_time, genesis_config.creation_time,
1882            "Bank snapshot genesis creation time does not match genesis.bin creation time. \
1883             The snapshot and genesis.bin might pertain to different clusters"
1884        );
1885        assert_eq!(bank.ticks_per_slot, genesis_config.ticks_per_slot);
1886        assert_eq!(
1887            bank.ns_per_slot,
1888            genesis_config.poh_config.target_tick_duration.as_nanos()
1889                * genesis_config.ticks_per_slot as u128
1890        );
1891        assert_eq!(bank.max_tick_height, (bank.slot + 1) * bank.ticks_per_slot);
1892        assert_eq!(
1893            bank.slots_per_year,
1894            years_as_slots(
1895                1.0,
1896                &genesis_config.poh_config.target_tick_duration,
1897                bank.ticks_per_slot,
1898            )
1899        );
1900        assert_eq!(bank.epoch_schedule, genesis_config.epoch_schedule);
1901        assert_eq!(bank.epoch, bank.epoch_schedule.get_epoch(bank.slot));
1902
1903        datapoint_info!(
1904            "bank-new-from-fields",
1905            (
1906                "accounts_data_len-from-snapshot",
1907                fields.accounts_data_len as i64,
1908                i64
1909            ),
1910            (
1911                "accounts_data_len-from-generate_index",
1912                accounts_data_size_initial as i64,
1913                i64
1914            ),
1915            (
1916                "stakes_accounts_load_duration_us",
1917                stakes_accounts_load_duration.as_micros(),
1918                i64
1919            ),
1920            (
1921                "calculate_accounts_lt_hash_us",
1922                calculate_accounts_lt_hash_duration.as_ref().map(Duration::as_micros),
1923                Option<i64>
1924            ),
1925        );
1926        bank
1927    }
1928
1929    /// Return subset of bank fields representing serializable state
1930    pub(crate) fn get_fields_to_serialize(&self) -> BankFieldsToSerialize {
1931        let (epoch_stakes, versioned_epoch_stakes) = split_epoch_stakes(self.epoch_stakes.clone());
1932        BankFieldsToSerialize {
1933            blockhash_queue: self.blockhash_queue.read().unwrap().clone(),
1934            ancestors: AncestorsForSerialization::from(&self.ancestors),
1935            hash: *self.hash.read().unwrap(),
1936            parent_hash: self.parent_hash,
1937            parent_slot: self.parent_slot,
1938            hard_forks: self.hard_forks.read().unwrap().clone(),
1939            transaction_count: self.transaction_count.load(Relaxed),
1940            tick_height: self.tick_height.load(Relaxed),
1941            signature_count: self.signature_count.load(Relaxed),
1942            capitalization: self.capitalization.load(Relaxed),
1943            max_tick_height: self.max_tick_height,
1944            hashes_per_tick: self.hashes_per_tick,
1945            ticks_per_slot: self.ticks_per_slot,
1946            ns_per_slot: self.ns_per_slot,
1947            genesis_creation_time: self.genesis_creation_time,
1948            slots_per_year: self.slots_per_year,
1949            slot: self.slot,
1950            epoch: self.epoch,
1951            block_height: self.block_height,
1952            collector_id: self.collector_id,
1953            collector_fees: self.collector_fees.load(Relaxed),
1954            fee_rate_governor: self.fee_rate_governor.clone(),
1955            collected_rent: self.collected_rent.load(Relaxed),
1956            rent_collector: self.rent_collector.clone(),
1957            epoch_schedule: self.epoch_schedule.clone(),
1958            inflation: *self.inflation.read().unwrap(),
1959            stakes: StakesEnum::from(self.stakes_cache.stakes().clone()),
1960            epoch_stakes,
1961            is_delta: self.is_delta.load(Relaxed),
1962            accounts_data_len: self.load_accounts_data_size(),
1963            versioned_epoch_stakes,
1964            accounts_lt_hash: self
1965                .is_accounts_lt_hash_enabled()
1966                .then(|| self.accounts_lt_hash.lock().unwrap().clone()),
1967        }
1968    }
1969
1970    pub fn collector_id(&self) -> &Pubkey {
1971        &self.collector_id
1972    }
1973
1974    pub fn genesis_creation_time(&self) -> UnixTimestamp {
1975        self.genesis_creation_time
1976    }
1977
1978    pub fn slot(&self) -> Slot {
1979        self.slot
1980    }
1981
1982    pub fn bank_id(&self) -> BankId {
1983        self.bank_id
1984    }
1985
1986    pub fn epoch(&self) -> Epoch {
1987        self.epoch
1988    }
1989
1990    pub fn first_normal_epoch(&self) -> Epoch {
1991        self.epoch_schedule().first_normal_epoch
1992    }
1993
1994    pub fn freeze_lock(&self) -> RwLockReadGuard<Hash> {
1995        self.hash.read().unwrap()
1996    }
1997
1998    pub fn hash(&self) -> Hash {
1999        *self.hash.read().unwrap()
2000    }
2001
2002    pub fn is_frozen(&self) -> bool {
2003        *self.hash.read().unwrap() != Hash::default()
2004    }
2005
2006    pub fn freeze_started(&self) -> bool {
2007        self.freeze_started.load(Relaxed)
2008    }
2009
2010    pub fn status_cache_ancestors(&self) -> Vec<u64> {
2011        let mut roots = self.status_cache.read().unwrap().roots().clone();
2012        let min = roots.iter().min().cloned().unwrap_or(0);
2013        for ancestor in self.ancestors.keys() {
2014            if ancestor >= min {
2015                roots.insert(ancestor);
2016            }
2017        }
2018
2019        let mut ancestors: Vec<_> = roots.into_iter().collect();
2020        #[allow(clippy::stable_sort_primitive)]
2021        ancestors.sort();
2022        ancestors
2023    }
2024
2025    /// computed unix_timestamp at this slot height
2026    pub fn unix_timestamp_from_genesis(&self) -> i64 {
2027        self.genesis_creation_time.saturating_add(
2028            (self.slot as u128)
2029                .saturating_mul(self.ns_per_slot)
2030                .saturating_div(1_000_000_000) as i64,
2031        )
2032    }
2033
2034    fn update_sysvar_account<F>(&self, pubkey: &Pubkey, updater: F)
2035    where
2036        F: Fn(&Option<AccountSharedData>) -> AccountSharedData,
2037    {
2038        let old_account = self.get_account_with_fixed_root(pubkey);
2039        let mut new_account = updater(&old_account);
2040
2041        // When new sysvar comes into existence (with RENT_UNADJUSTED_INITIAL_BALANCE lamports),
2042        // this code ensures that the sysvar's balance is adjusted to be rent-exempt.
2043        //
2044        // More generally, this code always re-calculates for possible sysvar data size change,
2045        // although there is no such sysvars currently.
2046        self.adjust_sysvar_balance_for_rent(&mut new_account);
2047        self.store_account_and_update_capitalization(pubkey, &new_account);
2048    }
2049
2050    fn inherit_specially_retained_account_fields(
2051        &self,
2052        old_account: &Option<AccountSharedData>,
2053    ) -> InheritableAccountFields {
2054        const RENT_UNADJUSTED_INITIAL_BALANCE: u64 = 1;
2055
2056        (
2057            old_account
2058                .as_ref()
2059                .map(|a| a.lamports())
2060                .unwrap_or(RENT_UNADJUSTED_INITIAL_BALANCE),
2061            old_account
2062                .as_ref()
2063                .map(|a| a.rent_epoch())
2064                .unwrap_or(INITIAL_RENT_EPOCH),
2065        )
2066    }
2067
2068    pub fn clock(&self) -> sysvar::clock::Clock {
2069        from_account(&self.get_account(&sysvar::clock::id()).unwrap_or_default())
2070            .unwrap_or_default()
2071    }
2072
2073    fn update_clock(&self, parent_epoch: Option<Epoch>) {
2074        let mut unix_timestamp = self.clock().unix_timestamp;
2075        // set epoch_start_timestamp to None to warp timestamp
2076        let epoch_start_timestamp = {
2077            let epoch = if let Some(epoch) = parent_epoch {
2078                epoch
2079            } else {
2080                self.epoch()
2081            };
2082            let first_slot_in_epoch = self.epoch_schedule().get_first_slot_in_epoch(epoch);
2083            Some((first_slot_in_epoch, self.clock().epoch_start_timestamp))
2084        };
2085        let max_allowable_drift = MaxAllowableDrift {
2086            fast: MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST,
2087            slow: MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW_V2,
2088        };
2089
2090        let ancestor_timestamp = self.clock().unix_timestamp;
2091        if let Some(timestamp_estimate) =
2092            self.get_timestamp_estimate(max_allowable_drift, epoch_start_timestamp)
2093        {
2094            unix_timestamp = timestamp_estimate;
2095            if timestamp_estimate < ancestor_timestamp {
2096                unix_timestamp = ancestor_timestamp;
2097            }
2098        }
2099        datapoint_info!(
2100            "bank-timestamp-correction",
2101            ("slot", self.slot(), i64),
2102            ("from_genesis", self.unix_timestamp_from_genesis(), i64),
2103            ("corrected", unix_timestamp, i64),
2104            ("ancestor_timestamp", ancestor_timestamp, i64),
2105        );
2106        let mut epoch_start_timestamp =
2107            // On epoch boundaries, update epoch_start_timestamp
2108            if parent_epoch.is_some() && parent_epoch.unwrap() != self.epoch() {
2109                unix_timestamp
2110            } else {
2111                self.clock().epoch_start_timestamp
2112            };
2113        if self.slot == 0 {
2114            unix_timestamp = self.unix_timestamp_from_genesis();
2115            epoch_start_timestamp = self.unix_timestamp_from_genesis();
2116        }
2117        let clock = sysvar::clock::Clock {
2118            slot: self.slot,
2119            epoch_start_timestamp,
2120            epoch: self.epoch_schedule().get_epoch(self.slot),
2121            leader_schedule_epoch: self.epoch_schedule().get_leader_schedule_epoch(self.slot),
2122            unix_timestamp,
2123        };
2124        self.update_sysvar_account(&sysvar::clock::id(), |account| {
2125            create_account(
2126                &clock,
2127                self.inherit_specially_retained_account_fields(account),
2128            )
2129        });
2130    }
2131
2132    pub fn update_last_restart_slot(&self) {
2133        let feature_flag = self
2134            .feature_set
2135            .is_active(&feature_set::last_restart_slot_sysvar::id());
2136
2137        if feature_flag {
2138            // First, see what the currently stored last restart slot is. This
2139            // account may not exist yet if the feature was just activated.
2140            let current_last_restart_slot = self
2141                .get_account(&sysvar::last_restart_slot::id())
2142                .and_then(|account| {
2143                    let lrs: Option<LastRestartSlot> = from_account(&account);
2144                    lrs
2145                })
2146                .map(|account| account.last_restart_slot);
2147
2148            let last_restart_slot = {
2149                let slot = self.slot;
2150                let hard_forks_r = self.hard_forks.read().unwrap();
2151
2152                // Only consider hard forks <= this bank's slot to avoid prematurely applying
2153                // a hard fork that is set to occur in the future.
2154                hard_forks_r
2155                    .iter()
2156                    .rev()
2157                    .find(|(hard_fork, _)| *hard_fork <= slot)
2158                    .map(|(slot, _)| *slot)
2159                    .unwrap_or(0)
2160            };
2161
2162            // Only need to write if the last restart has changed
2163            if current_last_restart_slot != Some(last_restart_slot) {
2164                self.update_sysvar_account(&sysvar::last_restart_slot::id(), |account| {
2165                    create_account(
2166                        &LastRestartSlot { last_restart_slot },
2167                        self.inherit_specially_retained_account_fields(account),
2168                    )
2169                });
2170            }
2171        }
2172    }
2173
2174    pub fn set_sysvar_for_tests<T>(&self, sysvar: &T)
2175    where
2176        T: Sysvar + SysvarId,
2177    {
2178        self.update_sysvar_account(&T::id(), |account| {
2179            create_account(
2180                sysvar,
2181                self.inherit_specially_retained_account_fields(account),
2182            )
2183        });
2184        // Simply force fill sysvar cache rather than checking which sysvar was
2185        // actually updated since tests don't need to be optimized for performance.
2186        self.transaction_processor.reset_sysvar_cache();
2187        self.transaction_processor
2188            .fill_missing_sysvar_cache_entries(self);
2189    }
2190
2191    fn update_slot_history(&self) {
2192        self.update_sysvar_account(&sysvar::slot_history::id(), |account| {
2193            let mut slot_history = account
2194                .as_ref()
2195                .map(|account| from_account::<SlotHistory, _>(account).unwrap())
2196                .unwrap_or_default();
2197            slot_history.add(self.slot());
2198            create_account(
2199                &slot_history,
2200                self.inherit_specially_retained_account_fields(account),
2201            )
2202        });
2203    }
2204
2205    fn update_slot_hashes(&self) {
2206        self.update_sysvar_account(&sysvar::slot_hashes::id(), |account| {
2207            let mut slot_hashes = account
2208                .as_ref()
2209                .map(|account| from_account::<SlotHashes, _>(account).unwrap())
2210                .unwrap_or_default();
2211            slot_hashes.add(self.parent_slot, self.parent_hash);
2212            create_account(
2213                &slot_hashes,
2214                self.inherit_specially_retained_account_fields(account),
2215            )
2216        });
2217    }
2218
2219    pub fn get_slot_history(&self) -> SlotHistory {
2220        from_account(&self.get_account(&sysvar::slot_history::id()).unwrap()).unwrap()
2221    }
2222
2223    fn update_epoch_stakes(&mut self, leader_schedule_epoch: Epoch) {
2224        // update epoch_stakes cache
2225        //  if my parent didn't populate for this staker's epoch, we've
2226        //  crossed a boundary
2227        if !self.epoch_stakes.contains_key(&leader_schedule_epoch) {
2228            self.epoch_stakes.retain(|&epoch, _| {
2229                epoch >= leader_schedule_epoch.saturating_sub(MAX_LEADER_SCHEDULE_STAKES)
2230            });
2231            let stakes = self.stakes_cache.stakes().clone();
2232            let stakes = Arc::new(StakesEnum::from(stakes));
2233            let new_epoch_stakes = EpochStakes::new(stakes, leader_schedule_epoch);
2234            info!(
2235                "new epoch stakes, epoch: {}, total_stake: {}",
2236                leader_schedule_epoch,
2237                new_epoch_stakes.total_stake(),
2238            );
2239
2240            // It is expensive to log the details of epoch stakes. Only log them at "trace"
2241            // level for debugging purpose.
2242            if log::log_enabled!(log::Level::Trace) {
2243                let vote_stakes: HashMap<_, _> = self
2244                    .stakes_cache
2245                    .stakes()
2246                    .vote_accounts()
2247                    .delegated_stakes()
2248                    .map(|(pubkey, stake)| (*pubkey, stake))
2249                    .collect();
2250                trace!("new epoch stakes, stakes: {vote_stakes:#?}");
2251            }
2252            self.epoch_stakes
2253                .insert(leader_schedule_epoch, new_epoch_stakes);
2254        }
2255    }
2256
2257    #[cfg(feature = "dev-context-only-utils")]
2258    pub fn set_epoch_stakes_for_test(&mut self, epoch: Epoch, stakes: EpochStakes) {
2259        self.epoch_stakes.insert(epoch, stakes);
2260    }
2261
2262    fn update_rent(&self) {
2263        self.update_sysvar_account(&sysvar::rent::id(), |account| {
2264            create_account(
2265                &self.rent_collector.rent,
2266                self.inherit_specially_retained_account_fields(account),
2267            )
2268        });
2269    }
2270
2271    fn update_epoch_schedule(&self) {
2272        self.update_sysvar_account(&sysvar::epoch_schedule::id(), |account| {
2273            create_account(
2274                self.epoch_schedule(),
2275                self.inherit_specially_retained_account_fields(account),
2276            )
2277        });
2278    }
2279
2280    fn update_stake_history(&self, epoch: Option<Epoch>) {
2281        if epoch == Some(self.epoch()) {
2282            return;
2283        }
2284        // if I'm the first Bank in an epoch, ensure stake_history is updated
2285        self.update_sysvar_account(&sysvar::stake_history::id(), |account| {
2286            create_account::<sysvar::stake_history::StakeHistory>(
2287                self.stakes_cache.stakes().history(),
2288                self.inherit_specially_retained_account_fields(account),
2289            )
2290        });
2291    }
2292
2293    pub fn epoch_duration_in_years(&self, prev_epoch: Epoch) -> f64 {
2294        // period: time that has passed as a fraction of a year, basically the length of
2295        //  an epoch as a fraction of a year
2296        //  calculated as: slots_elapsed / (slots / year)
2297        self.epoch_schedule().get_slots_in_epoch(prev_epoch) as f64 / self.slots_per_year
2298    }
2299
2300    // Calculates the starting-slot for inflation from the activation slot.
2301    // This method assumes that `pico_inflation` will be enabled before `full_inflation`, giving
2302    // precedence to the latter. However, since `pico_inflation` is fixed-rate Inflation, should
2303    // `pico_inflation` be enabled 2nd, the incorrect start slot provided here should have no
2304    // effect on the inflation calculation.
2305    fn get_inflation_start_slot(&self) -> Slot {
2306        let mut slots = self
2307            .feature_set
2308            .full_inflation_features_enabled()
2309            .iter()
2310            .filter_map(|id| self.feature_set.activated_slot(id))
2311            .collect::<Vec<_>>();
2312        slots.sort_unstable();
2313        slots.first().cloned().unwrap_or_else(|| {
2314            self.feature_set
2315                .activated_slot(&feature_set::pico_inflation::id())
2316                .unwrap_or(0)
2317        })
2318    }
2319
2320    fn get_inflation_num_slots(&self) -> u64 {
2321        let inflation_activation_slot = self.get_inflation_start_slot();
2322        // Normalize inflation_start to align with the start of rewards accrual.
2323        let inflation_start_slot = self.epoch_schedule().get_first_slot_in_epoch(
2324            self.epoch_schedule()
2325                .get_epoch(inflation_activation_slot)
2326                .saturating_sub(1),
2327        );
2328        self.epoch_schedule().get_first_slot_in_epoch(self.epoch()) - inflation_start_slot
2329    }
2330
2331    pub fn slot_in_year_for_inflation(&self) -> f64 {
2332        let num_slots = self.get_inflation_num_slots();
2333
2334        // calculated as: num_slots / (slots / year)
2335        num_slots as f64 / self.slots_per_year
2336    }
2337
2338    fn calculate_previous_epoch_inflation_rewards(
2339        &self,
2340        prev_epoch_capitalization: u64,
2341        prev_epoch: Epoch,
2342    ) -> PrevEpochInflationRewards {
2343        let slot_in_year = self.slot_in_year_for_inflation();
2344        let (validator_rate, foundation_rate) = {
2345            let inflation = self.inflation.read().unwrap();
2346            (
2347                (*inflation).validator(slot_in_year),
2348                (*inflation).foundation(slot_in_year),
2349            )
2350        };
2351
2352        let prev_epoch_duration_in_years = self.epoch_duration_in_years(prev_epoch);
2353        let validator_rewards = (validator_rate
2354            * prev_epoch_capitalization as f64
2355            * prev_epoch_duration_in_years) as u64;
2356
2357        PrevEpochInflationRewards {
2358            validator_rewards,
2359            prev_epoch_duration_in_years,
2360            validator_rate,
2361            foundation_rate,
2362        }
2363    }
2364
2365    fn assert_validator_rewards_paid(&self, validator_rewards_paid: u64) {
2366        assert_eq!(
2367            validator_rewards_paid,
2368            u64::try_from(
2369                self.rewards
2370                    .read()
2371                    .unwrap()
2372                    .par_iter()
2373                    .map(|(_address, reward_info)| {
2374                        match reward_info.reward_type {
2375                            RewardType::Voting | RewardType::Staking => reward_info.lamports,
2376                            _ => 0,
2377                        }
2378                    })
2379                    .sum::<i64>()
2380            )
2381            .unwrap()
2382        );
2383    }
2384
2385    fn filter_stake_delegations<'a>(
2386        &self,
2387        stakes: &'a Stakes<StakeAccount<Delegation>>,
2388    ) -> Vec<(&'a Pubkey, &'a StakeAccount<Delegation>)> {
2389        if self
2390            .feature_set
2391            .is_active(&feature_set::stake_minimum_delegation_for_rewards::id())
2392        {
2393            let num_stake_delegations = stakes.stake_delegations().len();
2394            let min_stake_delegation =
2395                solana_stake_program::get_minimum_delegation(&self.feature_set)
2396                    .max(LAMPORTS_PER_SOL);
2397
2398            let (stake_delegations, filter_time_us) = measure_us!(stakes
2399                .stake_delegations()
2400                .iter()
2401                .filter(|(_stake_pubkey, cached_stake_account)| {
2402                    cached_stake_account.delegation().stake >= min_stake_delegation
2403                })
2404                .collect::<Vec<_>>());
2405
2406            datapoint_info!(
2407                "stake_account_filter_time",
2408                ("filter_time_us", filter_time_us, i64),
2409                ("num_stake_delegations_before", num_stake_delegations, i64),
2410                ("num_stake_delegations_after", stake_delegations.len(), i64)
2411            );
2412            stake_delegations
2413        } else {
2414            stakes.stake_delegations().iter().collect()
2415        }
2416    }
2417
2418    /// return reward info for each vote account
2419    /// return account data for each vote account that needs to be stored
2420    /// This return value is a little awkward at the moment so that downstream existing code in the non-partitioned rewards code path can be re-used without duplication or modification.
2421    /// This function is copied from the existing code path's `store_vote_accounts`.
2422    /// The primary differences:
2423    /// - we want this fn to have no side effects (such as actually storing vote accounts) so that we
2424    ///   can compare the expected results with the current code path
2425    /// - we want to be able to batch store the vote accounts later for improved performance/cache updating
2426    fn calc_vote_accounts_to_store(
2427        vote_account_rewards: DashMap<Pubkey, VoteReward>,
2428    ) -> VoteRewardsAccounts {
2429        let len = vote_account_rewards.len();
2430        let mut result = VoteRewardsAccounts {
2431            rewards: Vec::with_capacity(len),
2432            accounts_to_store: Vec::with_capacity(len),
2433        };
2434        vote_account_rewards.into_iter().for_each(
2435            |(
2436                vote_pubkey,
2437                VoteReward {
2438                    mut vote_account,
2439                    commission,
2440                    vote_rewards,
2441                    vote_needs_store,
2442                },
2443            )| {
2444                if let Err(err) = vote_account.checked_add_lamports(vote_rewards) {
2445                    debug!("reward redemption failed for {}: {:?}", vote_pubkey, err);
2446                    return;
2447                }
2448
2449                result.rewards.push((
2450                    vote_pubkey,
2451                    RewardInfo {
2452                        reward_type: RewardType::Voting,
2453                        lamports: vote_rewards as i64,
2454                        post_balance: vote_account.lamports(),
2455                        commission: Some(commission),
2456                    },
2457                ));
2458                result
2459                    .accounts_to_store
2460                    .push(vote_needs_store.then_some(vote_account));
2461            },
2462        );
2463        result
2464    }
2465
2466    fn update_reward_history(
2467        &self,
2468        stake_rewards: StakeRewards,
2469        mut vote_rewards: Vec<(Pubkey, RewardInfo)>,
2470    ) {
2471        let additional_reserve = stake_rewards.len() + vote_rewards.len();
2472        let mut rewards = self.rewards.write().unwrap();
2473        rewards.reserve(additional_reserve);
2474        rewards.append(&mut vote_rewards);
2475        stake_rewards
2476            .into_iter()
2477            .filter(|x| x.get_stake_reward() > 0)
2478            .for_each(|x| rewards.push((x.stake_pubkey, x.stake_reward_info)));
2479    }
2480
2481    fn update_recent_blockhashes_locked(&self, locked_blockhash_queue: &BlockhashQueue) {
2482        #[allow(deprecated)]
2483        self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |account| {
2484            let recent_blockhash_iter = locked_blockhash_queue.get_recent_blockhashes();
2485            recent_blockhashes_account::create_account_with_data_and_fields(
2486                recent_blockhash_iter,
2487                self.inherit_specially_retained_account_fields(account),
2488            )
2489        });
2490    }
2491
2492    pub fn update_recent_blockhashes(&self) {
2493        let blockhash_queue = self.blockhash_queue.read().unwrap();
2494        self.update_recent_blockhashes_locked(&blockhash_queue);
2495    }
2496
2497    fn get_timestamp_estimate(
2498        &self,
2499        max_allowable_drift: MaxAllowableDrift,
2500        epoch_start_timestamp: Option<(Slot, UnixTimestamp)>,
2501    ) -> Option<UnixTimestamp> {
2502        let mut get_timestamp_estimate_time = Measure::start("get_timestamp_estimate");
2503        let slots_per_epoch = self.epoch_schedule().slots_per_epoch;
2504        let vote_accounts = self.vote_accounts();
2505        let recent_timestamps = vote_accounts.iter().filter_map(|(pubkey, (_, account))| {
2506            let vote_state = account.vote_state();
2507            let slot_delta = self.slot().checked_sub(vote_state.last_timestamp.slot)?;
2508            (slot_delta <= slots_per_epoch).then_some({
2509                (
2510                    *pubkey,
2511                    (
2512                        vote_state.last_timestamp.slot,
2513                        vote_state.last_timestamp.timestamp,
2514                    ),
2515                )
2516            })
2517        });
2518        let slot_duration = Duration::from_nanos(self.ns_per_slot as u64);
2519        let epoch = self.epoch_schedule().get_epoch(self.slot());
2520        let stakes = self.epoch_vote_accounts(epoch)?;
2521        let stake_weighted_timestamp = calculate_stake_weighted_timestamp(
2522            recent_timestamps,
2523            stakes,
2524            self.slot(),
2525            slot_duration,
2526            epoch_start_timestamp,
2527            max_allowable_drift,
2528            self.feature_set
2529                .is_active(&feature_set::warp_timestamp_again::id()),
2530        );
2531        get_timestamp_estimate_time.stop();
2532        datapoint_info!(
2533            "bank-timestamp",
2534            (
2535                "get_timestamp_estimate_us",
2536                get_timestamp_estimate_time.as_us(),
2537                i64
2538            ),
2539        );
2540        stake_weighted_timestamp
2541    }
2542
2543    /// Recalculates the bank hash
2544    ///
2545    /// This is used by ledger-tool when creating a snapshot, which
2546    /// recalcuates the bank hash.
2547    ///
2548    /// Note that the account state is *not* allowed to change by rehashing.
2549    /// If modifying accounts in ledger-tool is needed, create a new bank.
2550    pub fn rehash(&self) {
2551        let get_delta_hash = || {
2552            (!self
2553                .feature_set
2554                .is_active(&feature_set::remove_accounts_delta_hash::id()))
2555            .then(|| {
2556                self.rc
2557                    .accounts
2558                    .accounts_db
2559                    .get_accounts_delta_hash(self.slot())
2560            })
2561            .flatten()
2562        };
2563
2564        let mut hash = self.hash.write().unwrap();
2565        let curr_accounts_delta_hash = get_delta_hash();
2566        let new = self.hash_internal_state();
2567        if let Some(curr_accounts_delta_hash) = curr_accounts_delta_hash {
2568            let new_accounts_delta_hash = get_delta_hash().unwrap();
2569            assert_eq!(
2570                new_accounts_delta_hash, curr_accounts_delta_hash,
2571                "rehashing is not allowed to change the account state",
2572            );
2573        }
2574        if new != *hash {
2575            warn!("Updating bank hash to {new}");
2576            *hash = new;
2577        }
2578    }
2579
2580    pub fn freeze(&self) {
2581        // This lock prevents any new commits from BankingStage
2582        // `Consumer::execute_and_commit_transactions_locked()` from
2583        // coming in after the last tick is observed. This is because in
2584        // BankingStage, any transaction successfully recorded in
2585        // `record_transactions()` is recorded after this `hash` lock
2586        // is grabbed. At the time of the successful record,
2587        // this means the PoH has not yet reached the last tick,
2588        // so this means freeze() hasn't been called yet. And because
2589        // BankingStage doesn't release this hash lock until both
2590        // record and commit are finished, those transactions will be
2591        // committed before this write lock can be obtained here.
2592        let mut hash = self.hash.write().unwrap();
2593        if *hash == Hash::default() {
2594            // finish up any deferred changes to account state
2595            self.collect_rent_eagerly();
2596            if self.feature_set.is_active(&reward_full_priority_fee::id()) {
2597                self.distribute_transaction_fee_details();
2598            } else {
2599                self.distribute_transaction_fees();
2600            }
2601            self.distribute_rent_fees();
2602            self.update_slot_history();
2603            self.run_incinerator();
2604
2605            // freeze is a one-way trip, idempotent
2606            self.freeze_started.store(true, Relaxed);
2607            if self.is_accounts_lt_hash_enabled() {
2608                // updating the accounts lt hash must happen *outside* of hash_internal_state() so
2609                // that rehash() can be called and *not* modify self.accounts_lt_hash.
2610                self.update_accounts_lt_hash();
2611
2612                // For lattice-hash R&D, we have a CLI arg to do extra verfication.  If set, we'll
2613                // re-calculate the accounts lt hash every slot and compare it against the value
2614                // already stored in the bank.
2615                if self
2616                    .rc
2617                    .accounts
2618                    .accounts_db
2619                    .verify_experimental_accumulator_hash
2620                {
2621                    let slot = self.slot();
2622                    info!("Verifying the accounts lt hash for slot {slot}...");
2623                    let (calculated_accounts_lt_hash, duration) = meas_dur!({
2624                        self.rc
2625                            .accounts
2626                            .accounts_db
2627                            .calculate_accounts_lt_hash_at_startup_from_index(&self.ancestors, slot)
2628                    });
2629                    let actual_accounts_lt_hash = self.accounts_lt_hash.lock().unwrap();
2630                    assert_eq!(
2631                        calculated_accounts_lt_hash,
2632                        *actual_accounts_lt_hash,
2633                        "Verifying the accounts lt hash for slot {slot} failed! calculated checksum: {}, actual checksum: {}",
2634                        calculated_accounts_lt_hash.0.checksum(),
2635                        actual_accounts_lt_hash.0.checksum(),
2636                    );
2637                    info!("Verifying the accounts lt hash for slot {slot}... Done successfully in {duration:?}");
2638                }
2639            }
2640            *hash = self.hash_internal_state();
2641            self.rc.accounts.accounts_db.mark_slot_frozen(self.slot());
2642        }
2643    }
2644
2645    // dangerous; don't use this; this is only needed for ledger-tool's special command
2646    #[cfg(feature = "dev-context-only-utils")]
2647    pub fn unfreeze_for_ledger_tool(&self) {
2648        self.freeze_started.store(false, Relaxed);
2649    }
2650
2651    pub fn epoch_schedule(&self) -> &EpochSchedule {
2652        &self.epoch_schedule
2653    }
2654
2655    /// squash the parent's state up into this Bank,
2656    ///   this Bank becomes a root
2657    /// Note that this function is not thread-safe. If it is called concurrently on the same bank
2658    /// by multiple threads, the end result could be inconsistent.
2659    /// Calling code does not currently call this concurrently.
2660    pub fn squash(&self) -> SquashTiming {
2661        self.freeze();
2662
2663        //this bank and all its parents are now on the rooted path
2664        let mut roots = vec![self.slot()];
2665        roots.append(&mut self.parents().iter().map(|p| p.slot()).collect());
2666
2667        let mut total_index_us = 0;
2668        let mut total_cache_us = 0;
2669        let mut total_store_us = 0;
2670
2671        let mut squash_accounts_time = Measure::start("squash_accounts_time");
2672        for slot in roots.iter().rev() {
2673            // root forks cannot be purged
2674            let add_root_timing = self.rc.accounts.add_root(*slot);
2675            total_index_us += add_root_timing.index_us;
2676            total_cache_us += add_root_timing.cache_us;
2677            total_store_us += add_root_timing.store_us;
2678        }
2679        squash_accounts_time.stop();
2680
2681        *self.rc.parent.write().unwrap() = None;
2682
2683        let mut squash_cache_time = Measure::start("squash_cache_time");
2684        roots
2685            .iter()
2686            .for_each(|slot| self.status_cache.write().unwrap().add_root(*slot));
2687        squash_cache_time.stop();
2688
2689        SquashTiming {
2690            squash_accounts_ms: squash_accounts_time.as_ms(),
2691            squash_accounts_index_ms: total_index_us / 1000,
2692            squash_accounts_cache_ms: total_cache_us / 1000,
2693            squash_accounts_store_ms: total_store_us / 1000,
2694
2695            squash_cache_ms: squash_cache_time.as_ms(),
2696        }
2697    }
2698
2699    /// Return the more recent checkpoint of this bank instance.
2700    pub fn parent(&self) -> Option<Arc<Bank>> {
2701        self.rc.parent.read().unwrap().clone()
2702    }
2703
2704    pub fn parent_slot(&self) -> Slot {
2705        self.parent_slot
2706    }
2707
2708    pub fn parent_hash(&self) -> Hash {
2709        self.parent_hash
2710    }
2711
2712    fn process_genesis_config(
2713        &mut self,
2714        genesis_config: &GenesisConfig,
2715        #[cfg(feature = "dev-context-only-utils")] collector_id_for_tests: Option<Pubkey>,
2716        #[cfg(feature = "dev-context-only-utils")] genesis_hash: Option<Hash>,
2717    ) {
2718        // Bootstrap validator collects fees until `new_from_parent` is called.
2719        self.fee_rate_governor = genesis_config.fee_rate_governor.clone();
2720
2721        for (pubkey, account) in genesis_config.accounts.iter() {
2722            assert!(
2723                self.get_account(pubkey).is_none(),
2724                "{pubkey} repeated in genesis config"
2725            );
2726            self.store_account(pubkey, &account.to_account_shared_data());
2727            self.capitalization.fetch_add(account.lamports(), Relaxed);
2728            self.accounts_data_size_initial += account.data().len() as u64;
2729        }
2730
2731        for (pubkey, account) in genesis_config.rewards_pools.iter() {
2732            assert!(
2733                self.get_account(pubkey).is_none(),
2734                "{pubkey} repeated in genesis config"
2735            );
2736            self.store_account(pubkey, &account.to_account_shared_data());
2737            self.accounts_data_size_initial += account.data().len() as u64;
2738        }
2739
2740        // After storing genesis accounts, the bank stakes cache will be warmed
2741        // up and can be used to set the collector id to the highest staked
2742        // node. If no staked nodes exist, allow fallback to an unstaked test
2743        // collector id during tests.
2744        let collector_id = self.stakes_cache.stakes().highest_staked_node().copied();
2745        #[cfg(feature = "dev-context-only-utils")]
2746        let collector_id = collector_id.or(collector_id_for_tests);
2747        self.collector_id =
2748            collector_id.expect("genesis processing failed because no staked nodes exist");
2749
2750        #[cfg(not(feature = "dev-context-only-utils"))]
2751        let genesis_hash = genesis_config.hash();
2752        #[cfg(feature = "dev-context-only-utils")]
2753        let genesis_hash = genesis_hash.unwrap_or(genesis_config.hash());
2754
2755        self.blockhash_queue
2756            .write()
2757            .unwrap()
2758            .genesis_hash(&genesis_hash, self.fee_rate_governor.lamports_per_signature);
2759
2760        self.hashes_per_tick = genesis_config.hashes_per_tick();
2761        self.ticks_per_slot = genesis_config.ticks_per_slot();
2762        self.ns_per_slot = genesis_config.ns_per_slot();
2763        self.genesis_creation_time = genesis_config.creation_time;
2764        self.max_tick_height = (self.slot + 1) * self.ticks_per_slot;
2765        self.slots_per_year = genesis_config.slots_per_year();
2766
2767        self.epoch_schedule = genesis_config.epoch_schedule.clone();
2768
2769        self.inflation = Arc::new(RwLock::new(genesis_config.inflation));
2770
2771        self.rent_collector = RentCollector::new(
2772            self.epoch,
2773            self.epoch_schedule().clone(),
2774            self.slots_per_year,
2775            genesis_config.rent.clone(),
2776        );
2777
2778        // Add additional builtin programs specified in the genesis config
2779        for (name, program_id) in &genesis_config.native_instruction_processors {
2780            self.add_builtin_account(name, program_id);
2781        }
2782    }
2783
2784    fn burn_and_purge_account(&self, program_id: &Pubkey, mut account: AccountSharedData) {
2785        let old_data_size = account.data().len();
2786        self.capitalization.fetch_sub(account.lamports(), Relaxed);
2787        // Both resetting account balance to 0 and zeroing the account data
2788        // is needed to really purge from AccountsDb and flush the Stakes cache
2789        account.set_lamports(0);
2790        account.data_as_mut_slice().fill(0);
2791        self.store_account(program_id, &account);
2792        self.calculate_and_update_accounts_data_size_delta_off_chain(old_data_size, 0);
2793    }
2794
2795    /// Add a precompiled program account
2796    pub fn add_precompiled_account(&self, program_id: &Pubkey) {
2797        self.add_precompiled_account_with_owner(program_id, native_loader::id())
2798    }
2799
2800    // Used by tests to simulate clusters with precompiles that aren't owned by the native loader
2801    fn add_precompiled_account_with_owner(&self, program_id: &Pubkey, owner: Pubkey) {
2802        if let Some(account) = self.get_account_with_fixed_root(program_id) {
2803            if account.executable() {
2804                return;
2805            } else {
2806                // malicious account is pre-occupying at program_id
2807                self.burn_and_purge_account(program_id, account);
2808            }
2809        };
2810
2811        assert!(
2812            !self.freeze_started(),
2813            "Can't change frozen bank by adding not-existing new precompiled program ({program_id}). \
2814                Maybe, inconsistent program activation is detected on snapshot restore?"
2815        );
2816
2817        // Add a bogus executable account, which will be loaded and ignored.
2818        let (lamports, rent_epoch) = self.inherit_specially_retained_account_fields(&None);
2819
2820        let account = AccountSharedData::from(Account {
2821            lamports,
2822            owner,
2823            data: vec![],
2824            executable: true,
2825            rent_epoch,
2826        });
2827        self.store_account_and_update_capitalization(program_id, &account);
2828    }
2829
2830    pub fn set_rent_burn_percentage(&mut self, burn_percent: u8) {
2831        self.rent_collector.rent.burn_percent = burn_percent;
2832    }
2833
2834    pub fn set_hashes_per_tick(&mut self, hashes_per_tick: Option<u64>) {
2835        self.hashes_per_tick = hashes_per_tick;
2836    }
2837
2838    /// Return the last block hash registered.
2839    pub fn last_blockhash(&self) -> Hash {
2840        self.blockhash_queue.read().unwrap().last_hash()
2841    }
2842
2843    pub fn last_blockhash_and_lamports_per_signature(&self) -> (Hash, u64) {
2844        let blockhash_queue = self.blockhash_queue.read().unwrap();
2845        let last_hash = blockhash_queue.last_hash();
2846        let last_lamports_per_signature = blockhash_queue
2847            .get_lamports_per_signature(&last_hash)
2848            .unwrap(); // safe so long as the BlockhashQueue is consistent
2849        (last_hash, last_lamports_per_signature)
2850    }
2851
2852    pub fn is_blockhash_valid(&self, hash: &Hash) -> bool {
2853        let blockhash_queue = self.blockhash_queue.read().unwrap();
2854        blockhash_queue.is_hash_valid_for_age(hash, MAX_PROCESSING_AGE)
2855    }
2856
2857    pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> u64 {
2858        self.rent_collector.rent.minimum_balance(data_len).max(1)
2859    }
2860
2861    pub fn get_lamports_per_signature(&self) -> u64 {
2862        self.fee_rate_governor.lamports_per_signature
2863    }
2864
2865    pub fn get_lamports_per_signature_for_blockhash(&self, hash: &Hash) -> Option<u64> {
2866        let blockhash_queue = self.blockhash_queue.read().unwrap();
2867        blockhash_queue.get_lamports_per_signature(hash)
2868    }
2869
2870    pub fn get_fee_for_message(&self, message: &SanitizedMessage) -> Option<u64> {
2871        let lamports_per_signature = {
2872            let blockhash_queue = self.blockhash_queue.read().unwrap();
2873            blockhash_queue.get_lamports_per_signature(message.recent_blockhash())
2874        }
2875        .or_else(|| {
2876            self.load_message_nonce_account(message).map(
2877                |(_nonce_address, _nonce_account, nonce_data)| {
2878                    nonce_data.get_lamports_per_signature()
2879                },
2880            )
2881        })?;
2882        Some(self.get_fee_for_message_with_lamports_per_signature(message, lamports_per_signature))
2883    }
2884
2885    /// Returns true when startup accounts hash verification has completed or never had to run in background.
2886    pub fn get_startup_verification_complete(&self) -> &Arc<AtomicBool> {
2887        &self
2888            .rc
2889            .accounts
2890            .accounts_db
2891            .verify_accounts_hash_in_bg
2892            .verified
2893    }
2894
2895    /// return true if bg hash verification is complete
2896    /// return false if bg hash verification has not completed yet
2897    /// if hash verification failed, a panic will occur
2898    pub fn is_startup_verification_complete(&self) -> bool {
2899        self.has_initial_accounts_hash_verification_completed()
2900    }
2901
2902    /// This can occur because it completed in the background
2903    /// or if the verification was run in the foreground.
2904    pub fn set_startup_verification_complete(&self) {
2905        self.set_initial_accounts_hash_verification_completed();
2906    }
2907
2908    pub fn get_fee_for_message_with_lamports_per_signature(
2909        &self,
2910        message: &impl SVMMessage,
2911        lamports_per_signature: u64,
2912    ) -> u64 {
2913        let fee_budget_limits = FeeBudgetLimits::from(
2914            process_compute_budget_instructions(
2915                message.program_instructions_iter(),
2916                &self.feature_set,
2917            )
2918            .unwrap_or_default(),
2919        );
2920        solana_fee::calculate_fee(
2921            message,
2922            lamports_per_signature == 0,
2923            self.fee_structure().lamports_per_signature,
2924            fee_budget_limits.prioritization_fee,
2925            FeeFeatures::from(self.feature_set.as_ref()),
2926        )
2927    }
2928
2929    pub fn get_blockhash_last_valid_block_height(&self, blockhash: &Hash) -> Option<Slot> {
2930        let blockhash_queue = self.blockhash_queue.read().unwrap();
2931        // This calculation will need to be updated to consider epoch boundaries if BlockhashQueue
2932        // length is made variable by epoch
2933        blockhash_queue
2934            .get_hash_age(blockhash)
2935            .map(|age| self.block_height + MAX_PROCESSING_AGE as u64 - age)
2936    }
2937
2938    pub fn confirmed_last_blockhash(&self) -> Hash {
2939        const NUM_BLOCKHASH_CONFIRMATIONS: usize = 3;
2940
2941        let parents = self.parents();
2942        if parents.is_empty() {
2943            self.last_blockhash()
2944        } else {
2945            let index = NUM_BLOCKHASH_CONFIRMATIONS.min(parents.len() - 1);
2946            parents[index].last_blockhash()
2947        }
2948    }
2949
2950    /// Forget all signatures. Useful for benchmarking.
2951    pub fn clear_signatures(&self) {
2952        self.status_cache.write().unwrap().clear();
2953    }
2954
2955    pub fn clear_slot_signatures(&self, slot: Slot) {
2956        self.status_cache.write().unwrap().clear_slot_entries(slot);
2957    }
2958
2959    fn update_transaction_statuses(
2960        &self,
2961        sanitized_txs: &[impl TransactionWithMeta],
2962        processing_results: &[TransactionProcessingResult],
2963    ) {
2964        let mut status_cache = self.status_cache.write().unwrap();
2965        assert_eq!(sanitized_txs.len(), processing_results.len());
2966        for (tx, processing_result) in sanitized_txs.iter().zip(processing_results) {
2967            if let Ok(processed_tx) = &processing_result {
2968                // Add the message hash to the status cache to ensure that this message
2969                // won't be processed again with a different signature.
2970                status_cache.insert(
2971                    tx.recent_blockhash(),
2972                    tx.message_hash(),
2973                    self.slot(),
2974                    processed_tx.status(),
2975                );
2976                // Add the transaction signature to the status cache so that transaction status
2977                // can be queried by transaction signature over RPC. In the future, this should
2978                // only be added for API nodes because voting validators don't need to do this.
2979                status_cache.insert(
2980                    tx.recent_blockhash(),
2981                    tx.signature(),
2982                    self.slot(),
2983                    processed_tx.status(),
2984                );
2985            }
2986        }
2987    }
2988
2989    /// Register a new recent blockhash in the bank's recent blockhash queue. Called when a bank
2990    /// reaches its max tick height. Can be called by tests to get new blockhashes for transaction
2991    /// processing without advancing to a new bank slot.
2992    fn register_recent_blockhash(&self, blockhash: &Hash, scheduler: &InstalledSchedulerRwLock) {
2993        // This is needed because recent_blockhash updates necessitate synchronizations for
2994        // consistent tx check_age handling.
2995        BankWithScheduler::wait_for_paused_scheduler(self, scheduler);
2996
2997        // Only acquire the write lock for the blockhash queue on block boundaries because
2998        // readers can starve this write lock acquisition and ticks would be slowed down too
2999        // much if the write lock is acquired for each tick.
3000        let mut w_blockhash_queue = self.blockhash_queue.write().unwrap();
3001
3002        #[cfg(feature = "dev-context-only-utils")]
3003        let blockhash_override = self
3004            .hash_overrides
3005            .lock()
3006            .unwrap()
3007            .get_blockhash_override(self.slot())
3008            .copied()
3009            .inspect(|blockhash_override| {
3010                if blockhash_override != blockhash {
3011                    info!(
3012                        "bank: slot: {}: overrode blockhash: {} with {}",
3013                        self.slot(),
3014                        blockhash,
3015                        blockhash_override
3016                    );
3017                }
3018            });
3019        #[cfg(feature = "dev-context-only-utils")]
3020        let blockhash = blockhash_override.as_ref().unwrap_or(blockhash);
3021
3022        w_blockhash_queue.register_hash(blockhash, self.fee_rate_governor.lamports_per_signature);
3023        self.update_recent_blockhashes_locked(&w_blockhash_queue);
3024    }
3025
3026    // gating this under #[cfg(feature = "dev-context-only-utils")] isn't easy due to
3027    // solana-program-test's usage...
3028    pub fn register_unique_recent_blockhash_for_test(&self) {
3029        self.register_recent_blockhash(
3030            &Hash::new_unique(),
3031            &BankWithScheduler::no_scheduler_available(),
3032        )
3033    }
3034
3035    #[cfg(feature = "dev-context-only-utils")]
3036    pub fn register_recent_blockhash_for_test(
3037        &self,
3038        blockhash: &Hash,
3039        lamports_per_signature: Option<u64>,
3040    ) {
3041        // Only acquire the write lock for the blockhash queue on block boundaries because
3042        // readers can starve this write lock acquisition and ticks would be slowed down too
3043        // much if the write lock is acquired for each tick.
3044        let mut w_blockhash_queue = self.blockhash_queue.write().unwrap();
3045        if let Some(lamports_per_signature) = lamports_per_signature {
3046            w_blockhash_queue.register_hash(blockhash, lamports_per_signature);
3047        } else {
3048            w_blockhash_queue
3049                .register_hash(blockhash, self.fee_rate_governor.lamports_per_signature);
3050        }
3051    }
3052
3053    /// Tell the bank which Entry IDs exist on the ledger. This function assumes subsequent calls
3054    /// correspond to later entries, and will boot the oldest ones once its internal cache is full.
3055    /// Once boot, the bank will reject transactions using that `hash`.
3056    ///
3057    /// This is NOT thread safe because if tick height is updated by two different threads, the
3058    /// block boundary condition could be missed.
3059    pub fn register_tick(&self, hash: &Hash, scheduler: &InstalledSchedulerRwLock) {
3060        assert!(
3061            !self.freeze_started(),
3062            "register_tick() working on a bank that is already frozen or is undergoing freezing!"
3063        );
3064
3065        if self.is_block_boundary(self.tick_height.load(Relaxed) + 1) {
3066            self.register_recent_blockhash(hash, scheduler);
3067        }
3068
3069        // ReplayStage will start computing the accounts delta hash when it
3070        // detects the tick height has reached the boundary, so the system
3071        // needs to guarantee all account updates for the slot have been
3072        // committed before this tick height is incremented (like the blockhash
3073        // sysvar above)
3074        self.tick_height.fetch_add(1, Relaxed);
3075    }
3076
3077    #[cfg(feature = "dev-context-only-utils")]
3078    pub fn register_tick_for_test(&self, hash: &Hash) {
3079        self.register_tick(hash, &BankWithScheduler::no_scheduler_available())
3080    }
3081
3082    #[cfg(feature = "dev-context-only-utils")]
3083    pub fn register_default_tick_for_test(&self) {
3084        self.register_tick_for_test(&Hash::default())
3085    }
3086
3087    #[cfg(feature = "dev-context-only-utils")]
3088    pub fn register_unique_tick(&self) {
3089        self.register_tick_for_test(&Hash::new_unique())
3090    }
3091
3092    pub fn is_complete(&self) -> bool {
3093        self.tick_height() == self.max_tick_height()
3094    }
3095
3096    pub fn is_block_boundary(&self, tick_height: u64) -> bool {
3097        tick_height == self.max_tick_height
3098    }
3099
3100    /// Get the max number of accounts that a transaction may lock in this block
3101    pub fn get_transaction_account_lock_limit(&self) -> usize {
3102        if let Some(transaction_account_lock_limit) = self.transaction_account_lock_limit {
3103            transaction_account_lock_limit
3104        } else if self
3105            .feature_set
3106            .is_active(&feature_set::increase_tx_account_lock_limit::id())
3107        {
3108            MAX_TX_ACCOUNT_LOCKS
3109        } else {
3110            64
3111        }
3112    }
3113
3114    /// Prepare a transaction batch from a list of versioned transactions from
3115    /// an entry. Used for tests only.
3116    pub fn prepare_entry_batch(
3117        &self,
3118        txs: Vec<VersionedTransaction>,
3119    ) -> Result<TransactionBatch<RuntimeTransaction<SanitizedTransaction>>> {
3120        let sanitized_txs = txs
3121            .into_iter()
3122            .map(|tx| {
3123                RuntimeTransaction::try_create(
3124                    tx,
3125                    MessageHash::Compute,
3126                    None,
3127                    self,
3128                    self.get_reserved_account_keys(),
3129                )
3130            })
3131            .collect::<Result<Vec<_>>>()?;
3132        let tx_account_lock_limit = self.get_transaction_account_lock_limit();
3133        let lock_results = self
3134            .rc
3135            .accounts
3136            .lock_accounts(sanitized_txs.iter(), tx_account_lock_limit);
3137        Ok(TransactionBatch::new(
3138            lock_results,
3139            self,
3140            OwnedOrBorrowed::Owned(sanitized_txs),
3141        ))
3142    }
3143
3144    /// Attempt to take locks on the accounts in a transaction batch
3145    pub fn try_lock_accounts(&self, txs: &[impl SVMMessage]) -> Vec<Result<()>> {
3146        let tx_account_lock_limit = self.get_transaction_account_lock_limit();
3147        self.rc
3148            .accounts
3149            .lock_accounts(txs.iter(), tx_account_lock_limit)
3150    }
3151
3152    /// Prepare a locked transaction batch from a list of sanitized transactions.
3153    pub fn prepare_sanitized_batch<'a, 'b, Tx: SVMMessage>(
3154        &'a self,
3155        txs: &'b [Tx],
3156    ) -> TransactionBatch<'a, 'b, Tx> {
3157        TransactionBatch::new(
3158            self.try_lock_accounts(txs),
3159            self,
3160            OwnedOrBorrowed::Borrowed(txs),
3161        )
3162    }
3163
3164    /// Prepare a locked transaction batch from a list of sanitized transactions, and their cost
3165    /// limited packing status
3166    pub fn prepare_sanitized_batch_with_results<'a, 'b, Tx: SVMMessage>(
3167        &'a self,
3168        transactions: &'b [Tx],
3169        transaction_results: impl Iterator<Item = Result<()>>,
3170    ) -> TransactionBatch<'a, 'b, Tx> {
3171        // this lock_results could be: Ok, AccountInUse, WouldExceedBlockMaxLimit or WouldExceedAccountMaxLimit
3172        let tx_account_lock_limit = self.get_transaction_account_lock_limit();
3173        let lock_results = self.rc.accounts.lock_accounts_with_results(
3174            transactions.iter(),
3175            transaction_results,
3176            tx_account_lock_limit,
3177        );
3178        TransactionBatch::new(lock_results, self, OwnedOrBorrowed::Borrowed(transactions))
3179    }
3180
3181    /// Prepare a transaction batch from a single transaction without locking accounts
3182    pub fn prepare_unlocked_batch_from_single_tx<'a, Tx: SVMMessage>(
3183        &'a self,
3184        transaction: &'a Tx,
3185    ) -> TransactionBatch<'a, 'a, Tx> {
3186        let tx_account_lock_limit = self.get_transaction_account_lock_limit();
3187        let lock_result = validate_account_locks(transaction.account_keys(), tx_account_lock_limit);
3188        let mut batch = TransactionBatch::new(
3189            vec![lock_result],
3190            self,
3191            OwnedOrBorrowed::Borrowed(slice::from_ref(transaction)),
3192        );
3193        batch.set_needs_unlock(false);
3194        batch
3195    }
3196
3197    /// Run transactions against a frozen bank without committing the results
3198    pub fn simulate_transaction(
3199        &self,
3200        transaction: &impl TransactionWithMeta,
3201        enable_cpi_recording: bool,
3202    ) -> TransactionSimulationResult {
3203        assert!(self.is_frozen(), "simulation bank must be frozen");
3204
3205        self.simulate_transaction_unchecked(transaction, enable_cpi_recording)
3206    }
3207
3208    /// Run transactions against a bank without committing the results; does not check if the bank
3209    /// is frozen, enabling use in single-Bank test frameworks
3210    pub fn simulate_transaction_unchecked(
3211        &self,
3212        transaction: &impl TransactionWithMeta,
3213        enable_cpi_recording: bool,
3214    ) -> TransactionSimulationResult {
3215        let account_keys = transaction.account_keys();
3216        let number_of_accounts = account_keys.len();
3217        let account_overrides = self.get_account_overrides_for_simulation(&account_keys);
3218        let batch = self.prepare_unlocked_batch_from_single_tx(transaction);
3219        let mut timings = ExecuteTimings::default();
3220
3221        let LoadAndExecuteTransactionsOutput {
3222            mut processing_results,
3223            ..
3224        } = self.load_and_execute_transactions(
3225            &batch,
3226            // After simulation, transactions will need to be forwarded to the leader
3227            // for processing. During forwarding, the transaction could expire if the
3228            // delay is not accounted for.
3229            MAX_PROCESSING_AGE - MAX_TRANSACTION_FORWARDING_DELAY,
3230            &mut timings,
3231            &mut TransactionErrorMetrics::default(),
3232            TransactionProcessingConfig {
3233                account_overrides: Some(&account_overrides),
3234                check_program_modification_slot: self.check_program_modification_slot,
3235                compute_budget: self.compute_budget(),
3236                log_messages_bytes_limit: None,
3237                limit_to_load_programs: true,
3238                recording_config: ExecutionRecordingConfig {
3239                    enable_cpi_recording,
3240                    enable_log_recording: true,
3241                    enable_return_data_recording: true,
3242                },
3243                transaction_account_lock_limit: Some(self.get_transaction_account_lock_limit()),
3244            },
3245        );
3246
3247        let units_consumed =
3248            timings
3249                .details
3250                .per_program_timings
3251                .iter()
3252                .fold(0, |acc: u64, (_, program_timing)| {
3253                    (std::num::Saturating(acc)
3254                        + program_timing.accumulated_units
3255                        + program_timing.total_errored_units)
3256                        .0
3257                });
3258
3259        debug!("simulate_transaction: {:?}", timings);
3260
3261        let processing_result = processing_results
3262            .pop()
3263            .unwrap_or(Err(TransactionError::InvalidProgramForExecution));
3264        let (post_simulation_accounts, result, logs, return_data, inner_instructions) =
3265            match processing_result {
3266                Ok(processed_tx) => match processed_tx {
3267                    ProcessedTransaction::Executed(executed_tx) => {
3268                        let details = executed_tx.execution_details;
3269                        let post_simulation_accounts = executed_tx
3270                            .loaded_transaction
3271                            .accounts
3272                            .into_iter()
3273                            .take(number_of_accounts)
3274                            .collect::<Vec<_>>();
3275                        (
3276                            post_simulation_accounts,
3277                            details.status,
3278                            details.log_messages,
3279                            details.return_data,
3280                            details.inner_instructions,
3281                        )
3282                    }
3283                    ProcessedTransaction::FeesOnly(fees_only_tx) => {
3284                        (vec![], Err(fees_only_tx.load_error), None, None, None)
3285                    }
3286                },
3287                Err(error) => (vec![], Err(error), None, None, None),
3288            };
3289        let logs = logs.unwrap_or_default();
3290
3291        TransactionSimulationResult {
3292            result,
3293            logs,
3294            post_simulation_accounts,
3295            units_consumed,
3296            return_data,
3297            inner_instructions,
3298        }
3299    }
3300
3301    fn get_account_overrides_for_simulation(&self, account_keys: &AccountKeys) -> AccountOverrides {
3302        let mut account_overrides = AccountOverrides::default();
3303        let slot_history_id = sysvar::slot_history::id();
3304        if account_keys.iter().any(|pubkey| *pubkey == slot_history_id) {
3305            let current_account = self.get_account_with_fixed_root(&slot_history_id);
3306            let slot_history = current_account
3307                .as_ref()
3308                .map(|account| from_account::<SlotHistory, _>(account).unwrap())
3309                .unwrap_or_default();
3310            if slot_history.check(self.slot()) == Check::Found {
3311                let ancestors = Ancestors::from(self.proper_ancestors().collect::<Vec<_>>());
3312                if let Some((account, _)) =
3313                    self.load_slow_with_fixed_root(&ancestors, &slot_history_id)
3314                {
3315                    account_overrides.set_slot_history(Some(account));
3316                }
3317            }
3318        }
3319        account_overrides
3320    }
3321
3322    pub fn unlock_accounts<'a, Tx: SVMMessage + 'a>(
3323        &self,
3324        txs_and_results: impl Iterator<Item = (&'a Tx, &'a Result<()>)> + Clone,
3325    ) {
3326        self.rc.accounts.unlock_accounts(txs_and_results)
3327    }
3328
3329    pub fn remove_unrooted_slots(&self, slots: &[(Slot, BankId)]) {
3330        self.rc.accounts.accounts_db.remove_unrooted_slots(slots)
3331    }
3332
3333    pub fn get_hash_age(&self, hash: &Hash) -> Option<u64> {
3334        self.blockhash_queue.read().unwrap().get_hash_age(hash)
3335    }
3336
3337    pub fn is_hash_valid_for_age(&self, hash: &Hash, max_age: usize) -> bool {
3338        self.blockhash_queue
3339            .read()
3340            .unwrap()
3341            .is_hash_valid_for_age(hash, max_age)
3342    }
3343
3344    pub fn collect_balances(
3345        &self,
3346        batch: &TransactionBatch<impl SVMMessage>,
3347    ) -> TransactionBalances {
3348        let mut balances: TransactionBalances = vec![];
3349        for transaction in batch.sanitized_transactions() {
3350            let mut transaction_balances: Vec<u64> = vec![];
3351            for account_key in transaction.account_keys().iter() {
3352                transaction_balances.push(self.get_balance(account_key));
3353            }
3354            balances.push(transaction_balances);
3355        }
3356        balances
3357    }
3358
3359    pub fn load_and_execute_transactions(
3360        &self,
3361        batch: &TransactionBatch<impl TransactionWithMeta>,
3362        max_age: usize,
3363        timings: &mut ExecuteTimings,
3364        error_counters: &mut TransactionErrorMetrics,
3365        processing_config: TransactionProcessingConfig,
3366    ) -> LoadAndExecuteTransactionsOutput {
3367        let sanitized_txs = batch.sanitized_transactions();
3368
3369        let (check_results, check_us) = measure_us!(self.check_transactions(
3370            sanitized_txs,
3371            batch.lock_results(),
3372            max_age,
3373            error_counters,
3374        ));
3375        timings.saturating_add_in_place(ExecuteTimingType::CheckUs, check_us);
3376
3377        let (blockhash, blockhash_lamports_per_signature) =
3378            self.last_blockhash_and_lamports_per_signature();
3379        let rent_collector_with_metrics =
3380            RentCollectorWithMetrics::new(self.rent_collector.clone());
3381        let processing_environment = TransactionProcessingEnvironment {
3382            blockhash,
3383            blockhash_lamports_per_signature,
3384            epoch_total_stake: self.get_current_epoch_total_stake(),
3385            feature_set: Arc::clone(&self.feature_set),
3386            fee_lamports_per_signature: self.fee_structure.lamports_per_signature,
3387            rent_collector: Some(&rent_collector_with_metrics),
3388        };
3389
3390        let sanitized_output = self
3391            .transaction_processor
3392            .load_and_execute_sanitized_transactions(
3393                self,
3394                sanitized_txs,
3395                check_results,
3396                &processing_environment,
3397                &processing_config,
3398            );
3399
3400        // Accumulate the errors returned by the batch processor.
3401        error_counters.accumulate(&sanitized_output.error_metrics);
3402
3403        // Accumulate the transaction batch execution timings.
3404        timings.accumulate(&sanitized_output.execute_timings);
3405
3406        let ((), collect_logs_us) =
3407            measure_us!(self.collect_logs(sanitized_txs, &sanitized_output.processing_results));
3408        timings.saturating_add_in_place(ExecuteTimingType::CollectLogsUs, collect_logs_us);
3409
3410        let mut processed_counts = ProcessedTransactionCounts::default();
3411        let err_count = &mut error_counters.total;
3412
3413        for (processing_result, tx) in sanitized_output
3414            .processing_results
3415            .iter()
3416            .zip(sanitized_txs)
3417        {
3418            if let Some(debug_keys) = &self.transaction_debug_keys {
3419                for key in tx.account_keys().iter() {
3420                    if debug_keys.contains(key) {
3421                        let result = processing_result.flattened_result();
3422                        info!("slot: {} result: {:?} tx: {:?}", self.slot, result, tx);
3423                        break;
3424                    }
3425                }
3426            }
3427
3428            if processing_result.was_processed() {
3429                // Signature count must be accumulated only if the transaction
3430                // is processed, otherwise a mismatched count between banking
3431                // and replay could occur
3432                processed_counts.signature_count +=
3433                    tx.signature_details().num_transaction_signatures();
3434                processed_counts.processed_transactions_count += 1;
3435
3436                if !tx.is_simple_vote_transaction() {
3437                    processed_counts.processed_non_vote_transactions_count += 1;
3438                }
3439            }
3440
3441            match processing_result.flattened_result() {
3442                Ok(()) => {
3443                    processed_counts.processed_with_successful_result_count += 1;
3444                }
3445                Err(err) => {
3446                    if err_count.0 == 0 {
3447                        debug!("tx error: {:?} {:?}", err, tx);
3448                    }
3449                    *err_count += 1;
3450                }
3451            }
3452        }
3453
3454        LoadAndExecuteTransactionsOutput {
3455            processing_results: sanitized_output.processing_results,
3456            processed_counts,
3457        }
3458    }
3459
3460    fn collect_logs(
3461        &self,
3462        transactions: &[impl TransactionWithMeta],
3463        processing_results: &[TransactionProcessingResult],
3464    ) {
3465        let transaction_log_collector_config =
3466            self.transaction_log_collector_config.read().unwrap();
3467        if transaction_log_collector_config.filter == TransactionLogCollectorFilter::None {
3468            return;
3469        }
3470
3471        let collected_logs: Vec<_> = processing_results
3472            .iter()
3473            .zip(transactions)
3474            .filter_map(|(processing_result, transaction)| {
3475                // Skip log collection for unprocessed transactions
3476                let processed_tx = processing_result.processed_transaction()?;
3477                // Skip log collection for unexecuted transactions
3478                let execution_details = processed_tx.execution_details()?;
3479                Self::collect_transaction_logs(
3480                    &transaction_log_collector_config,
3481                    transaction,
3482                    execution_details,
3483                )
3484            })
3485            .collect();
3486
3487        if !collected_logs.is_empty() {
3488            let mut transaction_log_collector = self.transaction_log_collector.write().unwrap();
3489            for (log, filtered_mentioned_addresses) in collected_logs {
3490                let transaction_log_index = transaction_log_collector.logs.len();
3491                transaction_log_collector.logs.push(log);
3492                for key in filtered_mentioned_addresses.into_iter() {
3493                    transaction_log_collector
3494                        .mentioned_address_map
3495                        .entry(key)
3496                        .or_default()
3497                        .push(transaction_log_index);
3498                }
3499            }
3500        }
3501    }
3502
3503    fn collect_transaction_logs(
3504        transaction_log_collector_config: &TransactionLogCollectorConfig,
3505        transaction: &impl TransactionWithMeta,
3506        execution_details: &TransactionExecutionDetails,
3507    ) -> Option<(TransactionLogInfo, Vec<Pubkey>)> {
3508        // Skip log collection if no log messages were recorded
3509        let log_messages = execution_details.log_messages.as_ref()?;
3510
3511        let mut filtered_mentioned_addresses = Vec::new();
3512        if !transaction_log_collector_config
3513            .mentioned_addresses
3514            .is_empty()
3515        {
3516            for key in transaction.account_keys().iter() {
3517                if transaction_log_collector_config
3518                    .mentioned_addresses
3519                    .contains(key)
3520                {
3521                    filtered_mentioned_addresses.push(*key);
3522                }
3523            }
3524        }
3525
3526        let is_vote = transaction.is_simple_vote_transaction();
3527        let store = match transaction_log_collector_config.filter {
3528            TransactionLogCollectorFilter::All => {
3529                !is_vote || !filtered_mentioned_addresses.is_empty()
3530            }
3531            TransactionLogCollectorFilter::AllWithVotes => true,
3532            TransactionLogCollectorFilter::None => false,
3533            TransactionLogCollectorFilter::OnlyMentionedAddresses => {
3534                !filtered_mentioned_addresses.is_empty()
3535            }
3536        };
3537
3538        if store {
3539            Some((
3540                TransactionLogInfo {
3541                    signature: *transaction.signature(),
3542                    result: execution_details.status.clone(),
3543                    is_vote,
3544                    log_messages: log_messages.clone(),
3545                },
3546                filtered_mentioned_addresses,
3547            ))
3548        } else {
3549            None
3550        }
3551    }
3552
3553    /// Load the accounts data size, in bytes
3554    pub fn load_accounts_data_size(&self) -> u64 {
3555        self.accounts_data_size_initial
3556            .saturating_add_signed(self.load_accounts_data_size_delta())
3557    }
3558
3559    /// Load the change in accounts data size in this Bank, in bytes
3560    pub fn load_accounts_data_size_delta(&self) -> i64 {
3561        let delta_on_chain = self.load_accounts_data_size_delta_on_chain();
3562        let delta_off_chain = self.load_accounts_data_size_delta_off_chain();
3563        delta_on_chain.saturating_add(delta_off_chain)
3564    }
3565
3566    /// Load the change in accounts data size in this Bank, in bytes, from on-chain events
3567    /// i.e. transactions
3568    pub fn load_accounts_data_size_delta_on_chain(&self) -> i64 {
3569        self.accounts_data_size_delta_on_chain.load(Acquire)
3570    }
3571
3572    /// Load the change in accounts data size in this Bank, in bytes, from off-chain events
3573    /// i.e. rent collection
3574    pub fn load_accounts_data_size_delta_off_chain(&self) -> i64 {
3575        self.accounts_data_size_delta_off_chain.load(Acquire)
3576    }
3577
3578    /// Update the accounts data size delta from on-chain events by adding `amount`.
3579    /// The arithmetic saturates.
3580    fn update_accounts_data_size_delta_on_chain(&self, amount: i64) {
3581        if amount == 0 {
3582            return;
3583        }
3584
3585        self.accounts_data_size_delta_on_chain
3586            .fetch_update(AcqRel, Acquire, |accounts_data_size_delta_on_chain| {
3587                Some(accounts_data_size_delta_on_chain.saturating_add(amount))
3588            })
3589            // SAFETY: unwrap() is safe since our update fn always returns `Some`
3590            .unwrap();
3591    }
3592
3593    /// Update the accounts data size delta from off-chain events by adding `amount`.
3594    /// The arithmetic saturates.
3595    fn update_accounts_data_size_delta_off_chain(&self, amount: i64) {
3596        if amount == 0 {
3597            return;
3598        }
3599
3600        self.accounts_data_size_delta_off_chain
3601            .fetch_update(AcqRel, Acquire, |accounts_data_size_delta_off_chain| {
3602                Some(accounts_data_size_delta_off_chain.saturating_add(amount))
3603            })
3604            // SAFETY: unwrap() is safe since our update fn always returns `Some`
3605            .unwrap();
3606    }
3607
3608    /// Calculate the data size delta and update the off-chain accounts data size delta
3609    fn calculate_and_update_accounts_data_size_delta_off_chain(
3610        &self,
3611        old_data_size: usize,
3612        new_data_size: usize,
3613    ) {
3614        let data_size_delta = calculate_data_size_delta(old_data_size, new_data_size);
3615        self.update_accounts_data_size_delta_off_chain(data_size_delta);
3616    }
3617
3618    fn filter_program_errors_and_collect_fee(
3619        &self,
3620        processing_results: &[TransactionProcessingResult],
3621    ) {
3622        let mut fees = 0;
3623
3624        processing_results.iter().for_each(|processing_result| {
3625            if let Ok(processed_tx) = processing_result {
3626                fees += processed_tx.fee_details().total_fee();
3627            }
3628        });
3629
3630        self.collector_fees.fetch_add(fees, Relaxed);
3631    }
3632
3633    // Note: this function is not yet used; next PR will call it behind a feature gate
3634    fn filter_program_errors_and_collect_fee_details(
3635        &self,
3636        processing_results: &[TransactionProcessingResult],
3637    ) {
3638        let mut accumulated_fee_details = FeeDetails::default();
3639
3640        processing_results.iter().for_each(|processing_result| {
3641            if let Ok(processed_tx) = processing_result {
3642                accumulated_fee_details.accumulate(&processed_tx.fee_details());
3643            }
3644        });
3645
3646        self.collector_fee_details
3647            .write()
3648            .unwrap()
3649            .accumulate(&accumulated_fee_details);
3650    }
3651
3652    fn update_bank_hash_stats<'a>(&self, accounts: &impl StorableAccounts<'a>) {
3653        let mut stats = BankHashStats::default();
3654        (0..accounts.len()).for_each(|i| {
3655            accounts.account(i, |account| {
3656                stats.update(&account);
3657            })
3658        });
3659        self.bank_hash_stats.accumulate(&stats);
3660    }
3661
3662    pub fn commit_transactions(
3663        &self,
3664        sanitized_txs: &[impl TransactionWithMeta],
3665        processing_results: Vec<TransactionProcessingResult>,
3666        processed_counts: &ProcessedTransactionCounts,
3667        timings: &mut ExecuteTimings,
3668    ) -> Vec<TransactionCommitResult> {
3669        assert!(
3670            !self.freeze_started(),
3671            "commit_transactions() working on a bank that is already frozen or is undergoing freezing!"
3672        );
3673
3674        let ProcessedTransactionCounts {
3675            processed_transactions_count,
3676            processed_non_vote_transactions_count,
3677            processed_with_successful_result_count,
3678            signature_count,
3679        } = *processed_counts;
3680
3681        self.increment_transaction_count(processed_transactions_count);
3682        self.increment_non_vote_transaction_count_since_restart(
3683            processed_non_vote_transactions_count,
3684        );
3685        self.increment_signature_count(signature_count);
3686
3687        let processed_with_failure_result_count =
3688            processed_transactions_count.saturating_sub(processed_with_successful_result_count);
3689        self.transaction_error_count
3690            .fetch_add(processed_with_failure_result_count, Relaxed);
3691
3692        if processed_transactions_count > 0 {
3693            self.is_delta.store(true, Relaxed);
3694            self.transaction_entries_count.fetch_add(1, Relaxed);
3695            self.transactions_per_entry_max
3696                .fetch_max(processed_transactions_count, Relaxed);
3697        }
3698
3699        let ((), store_accounts_us) = measure_us!({
3700            // If geyser is present, we must collect `SanitizedTransaction`
3701            // references in order to comply with that interface - until it
3702            // is changed.
3703            let maybe_transaction_refs = self
3704                .accounts()
3705                .accounts_db
3706                .has_accounts_update_notifier()
3707                .then(|| {
3708                    sanitized_txs
3709                        .iter()
3710                        .map(|tx| tx.as_sanitized_transaction())
3711                        .collect::<Vec<_>>()
3712                });
3713
3714            let (accounts_to_store, transactions) = collect_accounts_to_store(
3715                sanitized_txs,
3716                &maybe_transaction_refs,
3717                &processing_results,
3718            );
3719
3720            let to_store = (self.slot(), accounts_to_store.as_slice());
3721            self.update_bank_hash_stats(&to_store);
3722            self.rc
3723                .accounts
3724                .store_cached(to_store, transactions.as_deref());
3725        });
3726
3727        self.collect_rent(&processing_results);
3728
3729        // Cached vote and stake accounts are synchronized with accounts-db
3730        // after each transaction.
3731        let ((), update_stakes_cache_us) =
3732            measure_us!(self.update_stakes_cache(sanitized_txs, &processing_results));
3733
3734        let ((), update_executors_us) = measure_us!({
3735            let mut cache = None;
3736            for processing_result in &processing_results {
3737                if let Some(ProcessedTransaction::Executed(executed_tx)) =
3738                    processing_result.processed_transaction()
3739                {
3740                    let programs_modified_by_tx = &executed_tx.programs_modified_by_tx;
3741                    if executed_tx.was_successful() && !programs_modified_by_tx.is_empty() {
3742                        cache
3743                            .get_or_insert_with(|| {
3744                                self.transaction_processor.program_cache.write().unwrap()
3745                            })
3746                            .merge(programs_modified_by_tx);
3747                    }
3748                }
3749            }
3750        });
3751
3752        let accounts_data_len_delta = processing_results
3753            .iter()
3754            .filter_map(|processing_result| processing_result.processed_transaction())
3755            .filter_map(|processed_tx| processed_tx.execution_details())
3756            .filter_map(|details| {
3757                details
3758                    .status
3759                    .is_ok()
3760                    .then_some(details.accounts_data_len_delta)
3761            })
3762            .sum();
3763        self.update_accounts_data_size_delta_on_chain(accounts_data_len_delta);
3764
3765        let ((), update_transaction_statuses_us) =
3766            measure_us!(self.update_transaction_statuses(sanitized_txs, &processing_results));
3767
3768        if self.feature_set.is_active(&reward_full_priority_fee::id()) {
3769            self.filter_program_errors_and_collect_fee_details(&processing_results)
3770        } else {
3771            self.filter_program_errors_and_collect_fee(&processing_results)
3772        };
3773
3774        timings.saturating_add_in_place(ExecuteTimingType::StoreUs, store_accounts_us);
3775        timings.saturating_add_in_place(
3776            ExecuteTimingType::UpdateStakesCacheUs,
3777            update_stakes_cache_us,
3778        );
3779        timings.saturating_add_in_place(ExecuteTimingType::UpdateExecutorsUs, update_executors_us);
3780        timings.saturating_add_in_place(
3781            ExecuteTimingType::UpdateTransactionStatuses,
3782            update_transaction_statuses_us,
3783        );
3784
3785        Self::create_commit_results(processing_results)
3786    }
3787
3788    fn create_commit_results(
3789        processing_results: Vec<TransactionProcessingResult>,
3790    ) -> Vec<TransactionCommitResult> {
3791        processing_results
3792            .into_iter()
3793            .map(|processing_result| {
3794                let processing_result = processing_result?;
3795                let executed_units = processing_result.executed_units();
3796                let loaded_accounts_data_size = processing_result.loaded_accounts_data_size();
3797
3798                match processing_result {
3799                    ProcessedTransaction::Executed(executed_tx) => {
3800                        let execution_details = executed_tx.execution_details;
3801                        let LoadedTransaction {
3802                            rent_debits,
3803                            accounts: loaded_accounts,
3804                            fee_details,
3805                            ..
3806                        } = executed_tx.loaded_transaction;
3807
3808                        // Rent is only collected for successfully executed transactions
3809                        let rent_debits = if execution_details.was_successful() {
3810                            rent_debits
3811                        } else {
3812                            RentDebits::default()
3813                        };
3814
3815                        Ok(CommittedTransaction {
3816                            status: execution_details.status,
3817                            log_messages: execution_details.log_messages,
3818                            inner_instructions: execution_details.inner_instructions,
3819                            return_data: execution_details.return_data,
3820                            executed_units,
3821                            fee_details,
3822                            rent_debits,
3823                            loaded_account_stats: TransactionLoadedAccountsStats {
3824                                loaded_accounts_count: loaded_accounts.len(),
3825                                loaded_accounts_data_size,
3826                            },
3827                        })
3828                    }
3829                    ProcessedTransaction::FeesOnly(fees_only_tx) => Ok(CommittedTransaction {
3830                        status: Err(fees_only_tx.load_error),
3831                        log_messages: None,
3832                        inner_instructions: None,
3833                        return_data: None,
3834                        executed_units,
3835                        rent_debits: RentDebits::default(),
3836                        fee_details: fees_only_tx.fee_details,
3837                        loaded_account_stats: TransactionLoadedAccountsStats {
3838                            loaded_accounts_count: fees_only_tx.rollback_accounts.count(),
3839                            loaded_accounts_data_size,
3840                        },
3841                    }),
3842                }
3843            })
3844            .collect()
3845    }
3846
3847    fn collect_rent(&self, processing_results: &[TransactionProcessingResult]) {
3848        let collected_rent = processing_results
3849            .iter()
3850            .filter_map(|processing_result| processing_result.processed_transaction())
3851            .filter_map(|processed_tx| processed_tx.executed_transaction())
3852            .filter(|executed_tx| executed_tx.was_successful())
3853            .map(|executed_tx| executed_tx.loaded_transaction.rent)
3854            .sum();
3855        self.collected_rent.fetch_add(collected_rent, Relaxed);
3856    }
3857
3858    fn run_incinerator(&self) {
3859        if let Some((account, _)) =
3860            self.get_account_modified_since_parent_with_fixed_root(&incinerator::id())
3861        {
3862            self.capitalization.fetch_sub(account.lamports(), Relaxed);
3863            self.store_account(&incinerator::id(), &AccountSharedData::default());
3864        }
3865    }
3866
3867    /// Get stake and stake node accounts
3868    pub(crate) fn get_stake_accounts(&self, minimized_account_set: &DashSet<Pubkey>) {
3869        self.stakes_cache
3870            .stakes()
3871            .stake_delegations()
3872            .iter()
3873            .for_each(|(pubkey, _)| {
3874                minimized_account_set.insert(*pubkey);
3875            });
3876
3877        self.stakes_cache
3878            .stakes()
3879            .staked_nodes()
3880            .par_iter()
3881            .for_each(|(pubkey, _)| {
3882                minimized_account_set.insert(*pubkey);
3883            });
3884    }
3885
3886    /// After deserialize, populate skipped rewrites with accounts that would normally
3887    /// have had their data rewritten in this slot due to rent collection (but didn't).
3888    ///
3889    /// This is required when starting up from a snapshot to verify the bank hash.
3890    ///
3891    /// A second usage is from the `bank_to_xxx_snapshot_archive()` functions.  These fns call
3892    /// `Bank::rehash()` to handle if the user manually modified any accounts and thus requires
3893    /// calculating the bank hash again.  Since calculating the bank hash *takes* the skipped
3894    /// rewrites, this second time will not have any skipped rewrites, and thus the hash would be
3895    /// updated to the wrong value.  So, rebuild the skipped rewrites before rehashing.
3896    fn rebuild_skipped_rewrites(&self) {
3897        // If the feature gate to *not* add rent collection rewrites to the bank hash is enabled,
3898        // then do *not* add anything to our skipped_rewrites.
3899        if self.bank_hash_skips_rent_rewrites() {
3900            return;
3901        }
3902
3903        let (skipped_rewrites, measure_skipped_rewrites) =
3904            measure_time!(self.calculate_skipped_rewrites());
3905        info!(
3906            "Rebuilding skipped rewrites of {} accounts{measure_skipped_rewrites}",
3907            skipped_rewrites.len()
3908        );
3909
3910        *self.skipped_rewrites.lock().unwrap() = skipped_rewrites;
3911    }
3912
3913    /// Calculates (and returns) skipped rewrites for this bank
3914    ///
3915    /// Refer to `rebuild_skipped_rewrites()` for more documentation.
3916    /// This implementation is purposely separate to facilitate testing.
3917    ///
3918    /// The key observation is that accounts in Bank::skipped_rewrites are only used IFF the
3919    /// specific account is *not* already in the accounts delta hash.  If an account is not in
3920    /// the accounts delta hash, then it means the account was not modified.  Since (basically)
3921    /// all accounts are rent exempt, this means (basically) all accounts are unmodified by rent
3922    /// collection.  So we just need to load the accounts that would've been checked for rent
3923    /// collection, hash them, and add them to Bank::skipped_rewrites.
3924    ///
3925    /// As of this writing, there are ~350 million acounts on mainnet-beta.
3926    /// Rent collection almost always collects a single slot at a time.
3927    /// So 1 slot of 432,000, of 350 million accounts, is ~800 accounts per slot.
3928    /// Since we haven't started processing anything yet, it should be fast enough to simply
3929    /// load the accounts directly.
3930    /// Empirically, this takes about 3-4 milliseconds.
3931    fn calculate_skipped_rewrites(&self) -> HashMap<Pubkey, AccountHash> {
3932        // The returned skipped rewrites may include accounts that were actually *not* skipped!
3933        // (This is safe, as per the fn's documentation above.)
3934        self.get_accounts_for_skipped_rewrites()
3935            .map(|(pubkey, account_hash, _account)| (pubkey, account_hash))
3936            .collect()
3937    }
3938
3939    /// Loads accounts that were selected for rent collection this slot.
3940    /// After loading the accounts, also calculate and return the account hashes.
3941    /// This is used when dealing with skipped rewrites.
3942    fn get_accounts_for_skipped_rewrites(
3943        &self,
3944    ) -> impl Iterator<Item = (Pubkey, AccountHash, AccountSharedData)> + '_ {
3945        self.rent_collection_partitions()
3946            .into_iter()
3947            .map(accounts_partition::pubkey_range_from_partition)
3948            .flat_map(|pubkey_range| {
3949                self.rc
3950                    .accounts
3951                    .load_to_collect_rent_eagerly(&self.ancestors, pubkey_range)
3952            })
3953            .map(|(pubkey, account, _slot)| {
3954                let account_hash = AccountsDb::hash_account(&account, &pubkey);
3955                (pubkey, account_hash, account)
3956            })
3957    }
3958
3959    /// Returns the accounts, sorted by pubkey, that were part of accounts delta hash calculation
3960    /// This is used when writing a bank hash details file.
3961    pub(crate) fn get_accounts_for_bank_hash_details(&self) -> Vec<PubkeyHashAccount> {
3962        let accounts_db = &self.rc.accounts.accounts_db;
3963
3964        let mut accounts_written_this_slot =
3965            accounts_db.get_pubkey_hash_account_for_slot(self.slot());
3966
3967        // If we are skipping rewrites but also include them in the accounts delta hash, then we
3968        // need to go load those accounts and add them to the list of accounts written this slot.
3969        if !self.bank_hash_skips_rent_rewrites()
3970            && accounts_db.test_skip_rewrites_but_include_in_bank_hash
3971        {
3972            let pubkeys_written_this_slot: HashSet<_> = accounts_written_this_slot
3973                .iter()
3974                .map(|pubkey_hash_account| pubkey_hash_account.pubkey)
3975                .collect();
3976
3977            let rent_collection_accounts = self.get_accounts_for_skipped_rewrites();
3978            for (pubkey, hash, account) in rent_collection_accounts {
3979                if !pubkeys_written_this_slot.contains(&pubkey) {
3980                    accounts_written_this_slot.push(PubkeyHashAccount {
3981                        pubkey,
3982                        hash,
3983                        account,
3984                    });
3985                }
3986            }
3987        }
3988
3989        // Sort the accounts by pubkey to match the order of the accounts delta hash.
3990        // This also makes comparison of files from different nodes deterministic.
3991        accounts_written_this_slot.sort_unstable_by_key(|account| account.pubkey);
3992        accounts_written_this_slot
3993    }
3994
3995    fn collect_rent_eagerly(&self) {
3996        if self.lazy_rent_collection.load(Relaxed) {
3997            return;
3998        }
3999
4000        if self
4001            .feature_set
4002            .is_active(&feature_set::disable_partitioned_rent_collection::id())
4003        {
4004            return;
4005        }
4006
4007        let mut measure = Measure::start("collect_rent_eagerly-ms");
4008        let partitions = self.rent_collection_partitions();
4009        let count = partitions.len();
4010        let rent_metrics = RentMetrics::default();
4011        // partitions will usually be 1, but could be more if we skip slots
4012        let mut parallel = count > 1;
4013        if parallel {
4014            let ranges = partitions
4015                .iter()
4016                .map(|partition| {
4017                    (
4018                        *partition,
4019                        accounts_partition::pubkey_range_from_partition(*partition),
4020                    )
4021                })
4022                .collect::<Vec<_>>();
4023            // test every range to make sure ranges are not overlapping
4024            // some tests collect rent from overlapping ranges
4025            // example: [(0, 31, 32), (0, 0, 128), (0, 27, 128)]
4026            // read-modify-write of an account for rent collection cannot be done in parallel
4027            'outer: for i in 0..ranges.len() {
4028                for j in 0..ranges.len() {
4029                    if i == j {
4030                        continue;
4031                    }
4032
4033                    let i = &ranges[i].1;
4034                    let j = &ranges[j].1;
4035                    // make sure i doesn't contain j
4036                    if i.contains(j.start()) || i.contains(j.end()) {
4037                        parallel = false;
4038                        break 'outer;
4039                    }
4040                }
4041            }
4042
4043            if parallel {
4044                let thread_pool = &self.rc.accounts.accounts_db.thread_pool;
4045                thread_pool.install(|| {
4046                    ranges.into_par_iter().for_each(|range| {
4047                        self.collect_rent_in_range(range.0, range.1, &rent_metrics)
4048                    });
4049                });
4050            }
4051        }
4052        if !parallel {
4053            // collect serially
4054            partitions
4055                .into_iter()
4056                .for_each(|partition| self.collect_rent_in_partition(partition, &rent_metrics));
4057        }
4058        measure.stop();
4059        datapoint_info!(
4060            "collect_rent_eagerly",
4061            ("accounts", rent_metrics.count.load(Relaxed), i64),
4062            ("partitions", count, i64),
4063            ("total_time_us", measure.as_us(), i64),
4064            (
4065                "hold_range_us",
4066                rent_metrics.hold_range_us.load(Relaxed),
4067                i64
4068            ),
4069            ("load_us", rent_metrics.load_us.load(Relaxed), i64),
4070            ("collect_us", rent_metrics.collect_us.load(Relaxed), i64),
4071            ("hash_us", rent_metrics.hash_us.load(Relaxed), i64),
4072            ("store_us", rent_metrics.store_us.load(Relaxed), i64),
4073        );
4074    }
4075
4076    fn rent_collection_partitions(&self) -> Vec<Partition> {
4077        if !self.use_fixed_collection_cycle() {
4078            // This mode is for production/development/testing.
4079            // In this mode, we iterate over the whole pubkey value range for each epochs
4080            // including warm-up epochs.
4081            // The only exception is the situation where normal epochs are relatively short
4082            // (currently less than 2 day). In that case, we arrange a single collection
4083            // cycle to be multiple of epochs so that a cycle could be greater than the 2 day.
4084            self.variable_cycle_partitions()
4085        } else {
4086            // This mode is mainly for benchmarking only.
4087            // In this mode, we always iterate over the whole pubkey value range with
4088            // <slot_count_in_two_day> slots as a collection cycle, regardless warm-up or
4089            // alignment between collection cycles and epochs.
4090            // Thus, we can simulate stable processing load of eager rent collection,
4091            // strictly proportional to the number of pubkeys since genesis.
4092            self.fixed_cycle_partitions()
4093        }
4094    }
4095
4096    /// true if rent collection does NOT rewrite accounts whose pubkey indicates
4097    ///  it is time for rent collection, but the account is rent exempt.
4098    /// false if rent collection DOES rewrite accounts if the account is rent exempt
4099    /// This is the default behavior historically.
4100    fn bank_hash_skips_rent_rewrites(&self) -> bool {
4101        self.feature_set
4102            .is_active(&feature_set::skip_rent_rewrites::id())
4103    }
4104
4105    /// true if rent fees should be collected (i.e. disable_rent_fees_collection is NOT enabled)
4106    fn should_collect_rent(&self) -> bool {
4107        !self
4108            .feature_set
4109            .is_active(&feature_set::disable_rent_fees_collection::id())
4110    }
4111
4112    /// Collect rent from `accounts`
4113    ///
4114    /// This fn is called inside a parallel loop from `collect_rent_in_partition()`.  Avoid adding
4115    /// any code that causes contention on shared memory/data (i.e. do not update atomic metrics).
4116    ///
4117    /// The return value is a struct of computed values that `collect_rent_in_partition()` will
4118    /// reduce at the end of its parallel loop.  If possible, place data/computation that cause
4119    /// contention/take locks in the return struct and process them in
4120    /// `collect_rent_from_partition()` after reducing the parallel loop.
4121    fn collect_rent_from_accounts(
4122        &self,
4123        mut accounts: Vec<(Pubkey, AccountSharedData, Slot)>,
4124        rent_paying_pubkeys: Option<&HashSet<Pubkey>>,
4125        partition_index: PartitionIndex,
4126    ) -> CollectRentFromAccountsInfo {
4127        let mut rent_debits = RentDebits::default();
4128        let mut total_rent_collected_info = CollectedInfo::default();
4129        let mut accounts_to_store =
4130            Vec::<(&Pubkey, &AccountSharedData)>::with_capacity(accounts.len());
4131        let mut time_collecting_rent_us = 0;
4132        let mut time_storing_accounts_us = 0;
4133        let can_skip_rewrites = self.bank_hash_skips_rent_rewrites();
4134        let test_skip_rewrites_but_include_in_bank_hash = self
4135            .rc
4136            .accounts
4137            .accounts_db
4138            .test_skip_rewrites_but_include_in_bank_hash;
4139        let mut skipped_rewrites = Vec::default();
4140        for (pubkey, account, _loaded_slot) in accounts.iter_mut() {
4141            let rent_epoch_pre = account.rent_epoch();
4142            let (rent_collected_info, collect_rent_us) = measure_us!(collect_rent_from_account(
4143                &self.feature_set,
4144                &self.rent_collector,
4145                pubkey,
4146                account
4147            ));
4148            time_collecting_rent_us += collect_rent_us;
4149            let rent_epoch_post = account.rent_epoch();
4150
4151            // did the account change in any way due to rent collection?
4152            let rent_epoch_changed = rent_epoch_post != rent_epoch_pre;
4153            let account_changed = rent_collected_info.rent_amount != 0 || rent_epoch_changed;
4154
4155            // always store the account, regardless if it changed or not
4156            let always_store_accounts =
4157                !can_skip_rewrites && !test_skip_rewrites_but_include_in_bank_hash;
4158
4159            // only store accounts where we collected rent
4160            // but get the hash for all these accounts even if collected rent is 0 (= not updated).
4161            // Also, there's another subtle side-effect from rewrites: this
4162            // ensures we verify the whole on-chain state (= all accounts)
4163            // via the bank delta hash slowly once per an epoch.
4164            if account_changed || always_store_accounts {
4165                if rent_collected_info.rent_amount > 0 {
4166                    if let Some(rent_paying_pubkeys) = rent_paying_pubkeys {
4167                        if !rent_paying_pubkeys.contains(pubkey) {
4168                            let partition_from_pubkey = accounts_partition::partition_from_pubkey(
4169                                pubkey,
4170                                self.epoch_schedule.slots_per_epoch,
4171                            );
4172                            // Submit datapoint instead of assert while we verify this is correct
4173                            datapoint_warn!(
4174                                "bank-unexpected_rent_paying_pubkey",
4175                                ("slot", self.slot(), i64),
4176                                ("pubkey", pubkey.to_string(), String),
4177                                ("partition_index", partition_index, i64),
4178                                ("partition_from_pubkey", partition_from_pubkey, i64)
4179                            );
4180                            warn!(
4181                                "Collecting rent from unexpected pubkey: {}, slot: {}, parent_slot: {:?}, \
4182                                partition_index: {}, partition_from_pubkey: {}",
4183                                pubkey,
4184                                self.slot(),
4185                                self.parent().map(|bank| bank.slot()),
4186                                partition_index,
4187                                partition_from_pubkey,
4188                            );
4189                        }
4190                    }
4191                } else {
4192                    debug_assert_eq!(rent_collected_info.rent_amount, 0);
4193                    if rent_epoch_changed {
4194                        datapoint_info!(
4195                            "bank-rent_collection_updated_only_rent_epoch",
4196                            ("slot", self.slot(), i64),
4197                            ("pubkey", pubkey.to_string(), String),
4198                            ("rent_epoch_pre", rent_epoch_pre, i64),
4199                            ("rent_epoch_post", rent_epoch_post, i64),
4200                        );
4201                    }
4202                }
4203                total_rent_collected_info += rent_collected_info;
4204                accounts_to_store.push((pubkey, account));
4205            } else if !account_changed
4206                && !can_skip_rewrites
4207                && test_skip_rewrites_but_include_in_bank_hash
4208            {
4209                // include rewrites that we skipped in the accounts delta hash.
4210                // This is what consensus requires prior to activation of bank_hash_skips_rent_rewrites.
4211                // This code path exists to allow us to test the long term effects on validators when the skipped rewrites
4212                // feature is enabled.
4213                let hash = AccountsDb::hash_account(account, pubkey);
4214                skipped_rewrites.push((*pubkey, hash));
4215            }
4216            rent_debits.insert(pubkey, rent_collected_info.rent_amount, account.lamports());
4217        }
4218
4219        if !accounts_to_store.is_empty() {
4220            // TODO: Maybe do not call `store_accounts()` here.  Instead return `accounts_to_store`
4221            // and have `collect_rent_in_partition()` perform all the stores.
4222            let (_, store_accounts_us) =
4223                measure_us!(self.store_accounts((self.slot(), &accounts_to_store[..])));
4224            time_storing_accounts_us += store_accounts_us;
4225        }
4226
4227        CollectRentFromAccountsInfo {
4228            skipped_rewrites,
4229            rent_collected_info: total_rent_collected_info,
4230            rent_rewards: rent_debits.into_unordered_rewards_iter().collect(),
4231            time_collecting_rent_us,
4232            time_storing_accounts_us,
4233            num_accounts: accounts.len(),
4234        }
4235    }
4236
4237    /// convert 'partition' to a pubkey range and 'collect_rent_in_range'
4238    fn collect_rent_in_partition(&self, partition: Partition, metrics: &RentMetrics) {
4239        let subrange_full = accounts_partition::pubkey_range_from_partition(partition);
4240        self.collect_rent_in_range(partition, subrange_full, metrics)
4241    }
4242
4243    /// get all pubkeys that we expect to be rent-paying or None, if this was not initialized at load time (that should only exist in test cases)
4244    fn get_rent_paying_pubkeys(&self, partition: &Partition) -> Option<HashSet<Pubkey>> {
4245        self.rc
4246            .accounts
4247            .accounts_db
4248            .accounts_index
4249            .rent_paying_accounts_by_partition
4250            .get()
4251            .and_then(|rent_paying_accounts| {
4252                rent_paying_accounts.is_initialized().then(|| {
4253                    accounts_partition::get_partition_end_indexes(partition)
4254                        .into_iter()
4255                        .flat_map(|end_index| {
4256                            rent_paying_accounts.get_pubkeys_in_partition_index(end_index)
4257                        })
4258                        .cloned()
4259                        .collect::<HashSet<_>>()
4260                })
4261            })
4262    }
4263
4264    /// load accounts with pubkeys in 'subrange_full'
4265    /// collect rent and update 'account.rent_epoch' as necessary
4266    /// store accounts, whether rent was collected or not (depending on whether we skipping rewrites is enabled)
4267    /// update bank's rewrites set for all rewrites that were skipped
4268    fn collect_rent_in_range(
4269        &self,
4270        partition: Partition,
4271        subrange_full: RangeInclusive<Pubkey>,
4272        metrics: &RentMetrics,
4273    ) {
4274        let mut hold_range = Measure::start("hold_range");
4275        let thread_pool = &self.rc.accounts.accounts_db.thread_pool;
4276        thread_pool.install(|| {
4277            self.rc
4278                .accounts
4279                .hold_range_in_memory(&subrange_full, true, thread_pool);
4280            hold_range.stop();
4281            metrics.hold_range_us.fetch_add(hold_range.as_us(), Relaxed);
4282
4283            let rent_paying_pubkeys_ = self.get_rent_paying_pubkeys(&partition);
4284            let rent_paying_pubkeys = rent_paying_pubkeys_.as_ref();
4285
4286            // divide the range into num_threads smaller ranges and process in parallel
4287            // Note that 'pubkey_range_from_partition' cannot easily be re-used here to break the range smaller.
4288            // It has special handling of 0..0 and partition_count changes affect all ranges unevenly.
4289            let num_threads = solana_accounts_db::accounts_db::quarter_thread_count() as u64;
4290            let sz = std::mem::size_of::<u64>();
4291            let start_prefix = accounts_partition::prefix_from_pubkey(subrange_full.start());
4292            let end_prefix_inclusive = accounts_partition::prefix_from_pubkey(subrange_full.end());
4293            let range = end_prefix_inclusive - start_prefix;
4294            let increment = range / num_threads;
4295            let mut results = (0..num_threads)
4296                .into_par_iter()
4297                .map(|chunk| {
4298                    let offset = |chunk| start_prefix + chunk * increment;
4299                    let start = offset(chunk);
4300                    let last = chunk == num_threads - 1;
4301                    let merge_prefix = |prefix: u64, mut bound: Pubkey| {
4302                        bound.as_mut()[0..sz].copy_from_slice(&prefix.to_be_bytes());
4303                        bound
4304                    };
4305                    let start = merge_prefix(start, *subrange_full.start());
4306                    let (accounts, measure_load_accounts) = measure_time!(if last {
4307                        let end = *subrange_full.end();
4308                        let subrange = start..=end; // IN-clusive
4309                        self.rc
4310                            .accounts
4311                            .load_to_collect_rent_eagerly(&self.ancestors, subrange)
4312                    } else {
4313                        let end = merge_prefix(offset(chunk + 1), *subrange_full.start());
4314                        let subrange = start..end; // EX-clusive, the next 'start' will be this same value
4315                        self.rc
4316                            .accounts
4317                            .load_to_collect_rent_eagerly(&self.ancestors, subrange)
4318                    });
4319                    CollectRentInPartitionInfo::new(
4320                        self.collect_rent_from_accounts(accounts, rent_paying_pubkeys, partition.1),
4321                        Duration::from_nanos(measure_load_accounts.as_ns()),
4322                    )
4323                })
4324                .reduce(
4325                    CollectRentInPartitionInfo::default,
4326                    CollectRentInPartitionInfo::reduce,
4327                );
4328
4329            self.skipped_rewrites
4330                .lock()
4331                .unwrap()
4332                .extend(results.skipped_rewrites);
4333
4334            // We cannot assert here that we collected from all expected keys.
4335            // Some accounts may have been topped off or may have had all funds removed and gone to 0 lamports.
4336
4337            self.rc
4338                .accounts
4339                .hold_range_in_memory(&subrange_full, false, thread_pool);
4340
4341            self.collected_rent
4342                .fetch_add(results.rent_collected, Relaxed);
4343            self.update_accounts_data_size_delta_off_chain(
4344                -(results.accounts_data_size_reclaimed as i64),
4345            );
4346            self.rewards
4347                .write()
4348                .unwrap()
4349                .append(&mut results.rent_rewards);
4350
4351            metrics
4352                .load_us
4353                .fetch_add(results.time_loading_accounts_us, Relaxed);
4354            metrics
4355                .collect_us
4356                .fetch_add(results.time_collecting_rent_us, Relaxed);
4357            metrics
4358                .store_us
4359                .fetch_add(results.time_storing_accounts_us, Relaxed);
4360            metrics.count.fetch_add(results.num_accounts, Relaxed);
4361        });
4362    }
4363
4364    pub(crate) fn fixed_cycle_partitions_between_slots(
4365        &self,
4366        starting_slot: Slot,
4367        ending_slot: Slot,
4368    ) -> Vec<Partition> {
4369        let slot_count_in_two_day = self.slot_count_in_two_day();
4370        accounts_partition::get_partitions(ending_slot, starting_slot, slot_count_in_two_day)
4371    }
4372
4373    fn fixed_cycle_partitions(&self) -> Vec<Partition> {
4374        self.fixed_cycle_partitions_between_slots(self.parent_slot(), self.slot())
4375    }
4376
4377    pub(crate) fn variable_cycle_partitions_between_slots(
4378        &self,
4379        starting_slot: Slot,
4380        ending_slot: Slot,
4381    ) -> Vec<Partition> {
4382        let (starting_epoch, mut starting_slot_index) =
4383            self.get_epoch_and_slot_index(starting_slot);
4384        let (ending_epoch, ending_slot_index) = self.get_epoch_and_slot_index(ending_slot);
4385
4386        let mut partitions = vec![];
4387        if starting_epoch < ending_epoch {
4388            let slot_skipped = (ending_slot - starting_slot) > 1;
4389            if slot_skipped {
4390                // Generate special partitions because there are skipped slots
4391                // exactly at the epoch transition.
4392
4393                let parent_last_slot_index = self.get_slots_in_epoch(starting_epoch) - 1;
4394
4395                // ... for parent epoch
4396                partitions.push(self.partition_from_slot_indexes_with_gapped_epochs(
4397                    starting_slot_index,
4398                    parent_last_slot_index,
4399                    starting_epoch,
4400                ));
4401
4402                if ending_slot_index > 0 {
4403                    // ... for current epoch
4404                    partitions.push(self.partition_from_slot_indexes_with_gapped_epochs(
4405                        0,
4406                        0,
4407                        ending_epoch,
4408                    ));
4409                }
4410            }
4411            starting_slot_index = 0;
4412        }
4413
4414        partitions.push(self.partition_from_normal_slot_indexes(
4415            starting_slot_index,
4416            ending_slot_index,
4417            ending_epoch,
4418        ));
4419
4420        partitions
4421    }
4422
4423    fn variable_cycle_partitions(&self) -> Vec<Partition> {
4424        self.variable_cycle_partitions_between_slots(self.parent_slot(), self.slot())
4425    }
4426
4427    fn do_partition_from_slot_indexes(
4428        &self,
4429        start_slot_index: SlotIndex,
4430        end_slot_index: SlotIndex,
4431        epoch: Epoch,
4432        generated_for_gapped_epochs: bool,
4433    ) -> Partition {
4434        let slot_count_per_epoch = self.get_slots_in_epoch(epoch);
4435
4436        let cycle_params = if !self.use_multi_epoch_collection_cycle(epoch) {
4437            // mnb should always go through this code path
4438            accounts_partition::rent_single_epoch_collection_cycle_params(
4439                epoch,
4440                slot_count_per_epoch,
4441            )
4442        } else {
4443            accounts_partition::rent_multi_epoch_collection_cycle_params(
4444                epoch,
4445                slot_count_per_epoch,
4446                self.first_normal_epoch(),
4447                self.slot_count_in_two_day() / slot_count_per_epoch,
4448            )
4449        };
4450        accounts_partition::get_partition_from_slot_indexes(
4451            cycle_params,
4452            start_slot_index,
4453            end_slot_index,
4454            generated_for_gapped_epochs,
4455        )
4456    }
4457
4458    fn partition_from_normal_slot_indexes(
4459        &self,
4460        start_slot_index: SlotIndex,
4461        end_slot_index: SlotIndex,
4462        epoch: Epoch,
4463    ) -> Partition {
4464        self.do_partition_from_slot_indexes(start_slot_index, end_slot_index, epoch, false)
4465    }
4466
4467    fn partition_from_slot_indexes_with_gapped_epochs(
4468        &self,
4469        start_slot_index: SlotIndex,
4470        end_slot_index: SlotIndex,
4471        epoch: Epoch,
4472    ) -> Partition {
4473        self.do_partition_from_slot_indexes(start_slot_index, end_slot_index, epoch, true)
4474    }
4475
4476    // Given short epochs, it's too costly to collect rent eagerly
4477    // within an epoch, so lower the frequency of it.
4478    // These logic isn't strictly eager anymore and should only be used
4479    // for development/performance purpose.
4480    // Absolutely not under ClusterType::MainnetBeta!!!!
4481    fn use_multi_epoch_collection_cycle(&self, epoch: Epoch) -> bool {
4482        // Force normal behavior, disabling multi epoch collection cycle for manual local testing
4483        #[cfg(not(test))]
4484        if self.slot_count_per_normal_epoch() == solana_sdk::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH
4485        {
4486            return false;
4487        }
4488
4489        epoch >= self.first_normal_epoch()
4490            && self.slot_count_per_normal_epoch() < self.slot_count_in_two_day()
4491    }
4492
4493    pub(crate) fn use_fixed_collection_cycle(&self) -> bool {
4494        // Force normal behavior, disabling fixed collection cycle for manual local testing
4495        #[cfg(not(test))]
4496        if self.slot_count_per_normal_epoch() == solana_sdk::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH
4497        {
4498            return false;
4499        }
4500
4501        self.cluster_type() != ClusterType::MainnetBeta
4502            && self.slot_count_per_normal_epoch() < self.slot_count_in_two_day()
4503    }
4504
4505    fn slot_count_in_two_day(&self) -> SlotCount {
4506        Self::slot_count_in_two_day_helper(self.ticks_per_slot)
4507    }
4508
4509    // This value is specially chosen to align with slots per epoch in mainnet-beta and testnet
4510    // Also, assume 500GB account data set as the extreme, then for 2 day (=48 hours) to collect
4511    // rent eagerly, we'll consume 5.7 MB/s IO bandwidth, bidirectionally.
4512    pub fn slot_count_in_two_day_helper(ticks_per_slot: SlotCount) -> SlotCount {
4513        2 * DEFAULT_TICKS_PER_SECOND * SECONDS_PER_DAY / ticks_per_slot
4514    }
4515
4516    fn slot_count_per_normal_epoch(&self) -> SlotCount {
4517        self.get_slots_in_epoch(self.first_normal_epoch())
4518    }
4519
4520    pub fn cluster_type(&self) -> ClusterType {
4521        // unwrap is safe; self.cluster_type is ensured to be Some() always...
4522        // we only using Option here for ABI compatibility...
4523        self.cluster_type.unwrap()
4524    }
4525
4526    /// Process a batch of transactions.
4527    #[must_use]
4528    pub fn load_execute_and_commit_transactions(
4529        &self,
4530        batch: &TransactionBatch<impl TransactionWithMeta>,
4531        max_age: usize,
4532        collect_balances: bool,
4533        recording_config: ExecutionRecordingConfig,
4534        timings: &mut ExecuteTimings,
4535        log_messages_bytes_limit: Option<usize>,
4536    ) -> (Vec<TransactionCommitResult>, TransactionBalancesSet) {
4537        self.do_load_execute_and_commit_transactions_with_pre_commit_callback(
4538            batch,
4539            max_age,
4540            collect_balances,
4541            recording_config,
4542            timings,
4543            log_messages_bytes_limit,
4544            None::<fn(&mut _, &_) -> _>,
4545        )
4546        .unwrap()
4547    }
4548
4549    pub fn load_execute_and_commit_transactions_with_pre_commit_callback<'a>(
4550        &'a self,
4551        batch: &TransactionBatch<impl TransactionWithMeta>,
4552        max_age: usize,
4553        collect_balances: bool,
4554        recording_config: ExecutionRecordingConfig,
4555        timings: &mut ExecuteTimings,
4556        log_messages_bytes_limit: Option<usize>,
4557        pre_commit_callback: impl FnOnce(
4558            &mut ExecuteTimings,
4559            &[TransactionProcessingResult],
4560        ) -> PreCommitResult<'a>,
4561    ) -> Result<(Vec<TransactionCommitResult>, TransactionBalancesSet)> {
4562        self.do_load_execute_and_commit_transactions_with_pre_commit_callback(
4563            batch,
4564            max_age,
4565            collect_balances,
4566            recording_config,
4567            timings,
4568            log_messages_bytes_limit,
4569            Some(pre_commit_callback),
4570        )
4571    }
4572
4573    fn do_load_execute_and_commit_transactions_with_pre_commit_callback<'a>(
4574        &'a self,
4575        batch: &TransactionBatch<impl TransactionWithMeta>,
4576        max_age: usize,
4577        collect_balances: bool,
4578        recording_config: ExecutionRecordingConfig,
4579        timings: &mut ExecuteTimings,
4580        log_messages_bytes_limit: Option<usize>,
4581        pre_commit_callback: Option<
4582            impl FnOnce(&mut ExecuteTimings, &[TransactionProcessingResult]) -> PreCommitResult<'a>,
4583        >,
4584    ) -> Result<(Vec<TransactionCommitResult>, TransactionBalancesSet)> {
4585        let pre_balances = if collect_balances {
4586            self.collect_balances(batch)
4587        } else {
4588            vec![]
4589        };
4590
4591        let LoadAndExecuteTransactionsOutput {
4592            processing_results,
4593            processed_counts,
4594        } = self.load_and_execute_transactions(
4595            batch,
4596            max_age,
4597            timings,
4598            &mut TransactionErrorMetrics::default(),
4599            TransactionProcessingConfig {
4600                account_overrides: None,
4601                check_program_modification_slot: self.check_program_modification_slot,
4602                compute_budget: self.compute_budget(),
4603                log_messages_bytes_limit,
4604                limit_to_load_programs: false,
4605                recording_config,
4606                transaction_account_lock_limit: Some(self.get_transaction_account_lock_limit()),
4607            },
4608        );
4609
4610        // pre_commit_callback could initiate an atomic operation (i.e. poh recording with block
4611        // producing unified scheduler). in that case, it returns Some(freeze_lock), which should
4612        // unlocked only after calling commit_transactions() immediately after calling the
4613        // callback.
4614        let freeze_lock = if let Some(pre_commit_callback) = pre_commit_callback {
4615            pre_commit_callback(timings, &processing_results)?
4616        } else {
4617            None
4618        };
4619        let commit_results = self.commit_transactions(
4620            batch.sanitized_transactions(),
4621            processing_results,
4622            &processed_counts,
4623            timings,
4624        );
4625        drop(freeze_lock);
4626        let post_balances = if collect_balances {
4627            self.collect_balances(batch)
4628        } else {
4629            vec![]
4630        };
4631        Ok((
4632            commit_results,
4633            TransactionBalancesSet::new(pre_balances, post_balances),
4634        ))
4635    }
4636
4637    /// Process a Transaction. This is used for unit tests and simply calls the vector
4638    /// Bank::process_transactions method.
4639    pub fn process_transaction(&self, tx: &Transaction) -> Result<()> {
4640        self.try_process_transactions(std::iter::once(tx))?[0].clone()?;
4641        tx.signatures
4642            .first()
4643            .map_or(Ok(()), |sig| self.get_signature_status(sig).unwrap())
4644    }
4645
4646    /// Process a Transaction and store metadata. This is used for tests and the banks services. It
4647    /// replicates the vector Bank::process_transaction method with metadata recording enabled.
4648    pub fn process_transaction_with_metadata(
4649        &self,
4650        tx: impl Into<VersionedTransaction>,
4651    ) -> Result<CommittedTransaction> {
4652        let txs = vec![tx.into()];
4653        let batch = self.prepare_entry_batch(txs)?;
4654
4655        let (mut commit_results, ..) = self.load_execute_and_commit_transactions(
4656            &batch,
4657            MAX_PROCESSING_AGE,
4658            false, // collect_balances
4659            ExecutionRecordingConfig {
4660                enable_cpi_recording: false,
4661                enable_log_recording: true,
4662                enable_return_data_recording: true,
4663            },
4664            &mut ExecuteTimings::default(),
4665            Some(1000 * 1000),
4666        );
4667
4668        commit_results.remove(0)
4669    }
4670
4671    /// Process multiple transaction in a single batch. This is used for benches and unit tests.
4672    /// Short circuits if any of the transactions do not pass sanitization checks.
4673    pub fn try_process_transactions<'a>(
4674        &self,
4675        txs: impl Iterator<Item = &'a Transaction>,
4676    ) -> Result<Vec<Result<()>>> {
4677        let txs = txs
4678            .map(|tx| VersionedTransaction::from(tx.clone()))
4679            .collect();
4680        self.try_process_entry_transactions(txs)
4681    }
4682
4683    /// Process multiple transaction in a single batch. This is used for benches and unit tests.
4684    /// Short circuits if any of the transactions do not pass sanitization checks.
4685    pub fn try_process_entry_transactions(
4686        &self,
4687        txs: Vec<VersionedTransaction>,
4688    ) -> Result<Vec<Result<()>>> {
4689        let batch = self.prepare_entry_batch(txs)?;
4690        Ok(self.process_transaction_batch(&batch))
4691    }
4692
4693    #[must_use]
4694    fn process_transaction_batch(
4695        &self,
4696        batch: &TransactionBatch<impl TransactionWithMeta>,
4697    ) -> Vec<Result<()>> {
4698        self.load_execute_and_commit_transactions(
4699            batch,
4700            MAX_PROCESSING_AGE,
4701            false,
4702            ExecutionRecordingConfig::new_single_setting(false),
4703            &mut ExecuteTimings::default(),
4704            None,
4705        )
4706        .0
4707        .into_iter()
4708        .map(|commit_result| commit_result.map(|_| ()))
4709        .collect()
4710    }
4711
4712    /// Create, sign, and process a Transaction from `keypair` to `to` of
4713    /// `n` lamports where `blockhash` is the last Entry ID observed by the client.
4714    pub fn transfer(&self, n: u64, keypair: &Keypair, to: &Pubkey) -> Result<Signature> {
4715        let blockhash = self.last_blockhash();
4716        let tx = system_transaction::transfer(keypair, to, n, blockhash);
4717        let signature = tx.signatures[0];
4718        self.process_transaction(&tx).map(|_| signature)
4719    }
4720
4721    pub fn read_balance(account: &AccountSharedData) -> u64 {
4722        account.lamports()
4723    }
4724    /// Each program would need to be able to introspect its own state
4725    /// this is hard-coded to the Budget language
4726    pub fn get_balance(&self, pubkey: &Pubkey) -> u64 {
4727        self.get_account(pubkey)
4728            .map(|x| Self::read_balance(&x))
4729            .unwrap_or(0)
4730    }
4731
4732    /// Compute all the parents of the bank in order
4733    pub fn parents(&self) -> Vec<Arc<Bank>> {
4734        let mut parents = vec![];
4735        let mut bank = self.parent();
4736        while let Some(parent) = bank {
4737            parents.push(parent.clone());
4738            bank = parent.parent();
4739        }
4740        parents
4741    }
4742
4743    /// Compute all the parents of the bank including this bank itself
4744    pub fn parents_inclusive(self: Arc<Self>) -> Vec<Arc<Bank>> {
4745        let mut parents = self.parents();
4746        parents.insert(0, self);
4747        parents
4748    }
4749
4750    /// fn store the single `account` with `pubkey`.
4751    /// Uses `store_accounts`, which works on a vector of accounts.
4752    pub fn store_account(&self, pubkey: &Pubkey, account: &AccountSharedData) {
4753        self.store_accounts((self.slot(), &[(pubkey, account)][..]))
4754    }
4755
4756    pub fn store_accounts<'a>(&self, accounts: impl StorableAccounts<'a>) {
4757        assert!(!self.freeze_started());
4758        let mut m = Measure::start("stakes_cache.check_and_store");
4759        let new_warmup_cooldown_rate_epoch = self.new_warmup_cooldown_rate_epoch();
4760
4761        (0..accounts.len()).for_each(|i| {
4762            accounts.account(i, |account| {
4763                self.stakes_cache.check_and_store(
4764                    account.pubkey(),
4765                    &account,
4766                    new_warmup_cooldown_rate_epoch,
4767                )
4768            })
4769        });
4770        self.update_bank_hash_stats(&accounts);
4771        self.rc.accounts.store_accounts_cached(accounts);
4772        m.stop();
4773        self.rc
4774            .accounts
4775            .accounts_db
4776            .stats
4777            .stakes_cache_check_and_store_us
4778            .fetch_add(m.as_us(), Relaxed);
4779    }
4780
4781    pub fn force_flush_accounts_cache(&self) {
4782        self.rc
4783            .accounts
4784            .accounts_db
4785            .flush_accounts_cache(true, Some(self.slot()))
4786    }
4787
4788    pub fn flush_accounts_cache_if_needed(&self) {
4789        self.rc
4790            .accounts
4791            .accounts_db
4792            .flush_accounts_cache(false, Some(self.slot()))
4793    }
4794
4795    /// Technically this issues (or even burns!) new lamports,
4796    /// so be extra careful for its usage
4797    fn store_account_and_update_capitalization(
4798        &self,
4799        pubkey: &Pubkey,
4800        new_account: &AccountSharedData,
4801    ) {
4802        let old_account_data_size =
4803            if let Some(old_account) = self.get_account_with_fixed_root_no_cache(pubkey) {
4804                match new_account.lamports().cmp(&old_account.lamports()) {
4805                    std::cmp::Ordering::Greater => {
4806                        let increased = new_account.lamports() - old_account.lamports();
4807                        trace!(
4808                            "store_account_and_update_capitalization: increased: {} {}",
4809                            pubkey,
4810                            increased
4811                        );
4812                        self.capitalization.fetch_add(increased, Relaxed);
4813                    }
4814                    std::cmp::Ordering::Less => {
4815                        let decreased = old_account.lamports() - new_account.lamports();
4816                        trace!(
4817                            "store_account_and_update_capitalization: decreased: {} {}",
4818                            pubkey,
4819                            decreased
4820                        );
4821                        self.capitalization.fetch_sub(decreased, Relaxed);
4822                    }
4823                    std::cmp::Ordering::Equal => {}
4824                }
4825                old_account.data().len()
4826            } else {
4827                trace!(
4828                    "store_account_and_update_capitalization: created: {} {}",
4829                    pubkey,
4830                    new_account.lamports()
4831                );
4832                self.capitalization
4833                    .fetch_add(new_account.lamports(), Relaxed);
4834                0
4835            };
4836
4837        self.store_account(pubkey, new_account);
4838        self.calculate_and_update_accounts_data_size_delta_off_chain(
4839            old_account_data_size,
4840            new_account.data().len(),
4841        );
4842    }
4843
4844    pub fn accounts(&self) -> Arc<Accounts> {
4845        self.rc.accounts.clone()
4846    }
4847
4848    fn finish_init(
4849        &mut self,
4850        genesis_config: &GenesisConfig,
4851        additional_builtins: Option<&[BuiltinPrototype]>,
4852        debug_do_not_add_builtins: bool,
4853    ) {
4854        self.rewards_pool_pubkeys =
4855            Arc::new(genesis_config.rewards_pools.keys().cloned().collect());
4856
4857        self.apply_feature_activations(
4858            ApplyFeatureActivationsCaller::FinishInit,
4859            debug_do_not_add_builtins,
4860        );
4861
4862        // Cost-Tracker is not serialized in snapshot or any configs.
4863        // We must apply previously activated features related to limits here
4864        // so that the initial bank state is consistent with the feature set.
4865        // Cost-tracker limits are propagated through children banks.
4866        if self
4867            .feature_set
4868            .is_active(&feature_set::raise_block_limits_to_50m::id())
4869        {
4870            let (account_cost_limit, block_cost_limit, vote_cost_limit) = simd_0207_block_limits();
4871            self.write_cost_tracker().unwrap().set_limits(
4872                account_cost_limit,
4873                block_cost_limit,
4874                vote_cost_limit,
4875            );
4876        }
4877
4878        // If the accounts delta hash is still in use, start the background account hasher
4879        if !self
4880            .feature_set
4881            .is_active(&feature_set::remove_accounts_delta_hash::id())
4882        {
4883            self.rc.accounts.accounts_db.start_background_hasher();
4884        }
4885
4886        if !debug_do_not_add_builtins {
4887            for builtin in BUILTINS
4888                .iter()
4889                .chain(additional_builtins.unwrap_or(&[]).iter())
4890            {
4891                // The builtin should be added if it has no enable feature ID
4892                // and it has not been migrated to Core BPF.
4893                //
4894                // If a program was previously migrated to Core BPF, accountsDB
4895                // from snapshot should contain the BPF program accounts.
4896                let builtin_is_bpf = |program_id: &Pubkey| {
4897                    self.get_account(program_id)
4898                        .map(|a| a.owner() == &bpf_loader_upgradeable::id())
4899                        .unwrap_or(false)
4900                };
4901                if builtin.enable_feature_id.is_none() && !builtin_is_bpf(&builtin.program_id) {
4902                    self.transaction_processor.add_builtin(
4903                        self,
4904                        builtin.program_id,
4905                        builtin.name,
4906                        ProgramCacheEntry::new_builtin(0, builtin.name.len(), builtin.entrypoint),
4907                    );
4908                }
4909            }
4910            for precompile in get_precompiles() {
4911                if precompile.feature.is_none() {
4912                    self.add_precompile(&precompile.program_id);
4913                }
4914            }
4915        }
4916
4917        self.transaction_processor
4918            .configure_program_runtime_environments(
4919                Some(Arc::new(
4920                    create_program_runtime_environment_v1(
4921                        &self.feature_set,
4922                        &self.compute_budget().unwrap_or_default(),
4923                        false, /* deployment */
4924                        false, /* debugging_features */
4925                    )
4926                    .unwrap(),
4927                )),
4928                Some(Arc::new(create_program_runtime_environment_v2(
4929                    &self.compute_budget().unwrap_or_default(),
4930                    false, /* debugging_features */
4931                ))),
4932            );
4933    }
4934
4935    pub fn set_inflation(&self, inflation: Inflation) {
4936        *self.inflation.write().unwrap() = inflation;
4937    }
4938
4939    /// Get a snapshot of the current set of hard forks
4940    pub fn hard_forks(&self) -> HardForks {
4941        self.hard_forks.read().unwrap().clone()
4942    }
4943
4944    pub fn register_hard_fork(&self, new_hard_fork_slot: Slot) {
4945        let bank_slot = self.slot();
4946
4947        let lock = self.freeze_lock();
4948        let bank_frozen = *lock != Hash::default();
4949        if new_hard_fork_slot < bank_slot {
4950            warn!(
4951                "Hard fork at slot {new_hard_fork_slot} ignored, the hard fork is older \
4952                than the bank at slot {bank_slot} that attempted to register it."
4953            );
4954        } else if (new_hard_fork_slot == bank_slot) && bank_frozen {
4955            warn!(
4956                "Hard fork at slot {new_hard_fork_slot} ignored, the hard fork is the same \
4957                slot as the bank at slot {bank_slot} that attempted to register it, but that \
4958                bank is already frozen."
4959            );
4960        } else {
4961            self.hard_forks
4962                .write()
4963                .unwrap()
4964                .register(new_hard_fork_slot);
4965        }
4966    }
4967
4968    pub fn get_account_with_fixed_root_no_cache(
4969        &self,
4970        pubkey: &Pubkey,
4971    ) -> Option<AccountSharedData> {
4972        self.load_account_with(pubkey, |_| false)
4973            .map(|(acc, _slot)| acc)
4974    }
4975
4976    fn load_account_with(
4977        &self,
4978        pubkey: &Pubkey,
4979        callback: impl for<'local> Fn(&'local AccountSharedData) -> bool,
4980    ) -> Option<(AccountSharedData, Slot)> {
4981        self.rc
4982            .accounts
4983            .accounts_db
4984            .load_account_with(&self.ancestors, pubkey, callback)
4985    }
4986
4987    // Hi! leaky abstraction here....
4988    // try to use get_account_with_fixed_root() if it's called ONLY from on-chain runtime account
4989    // processing. That alternative fn provides more safety.
4990    pub fn get_account(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
4991        self.get_account_modified_slot(pubkey)
4992            .map(|(acc, _slot)| acc)
4993    }
4994
4995    // Hi! leaky abstraction here....
4996    // use this over get_account() if it's called ONLY from on-chain runtime account
4997    // processing (i.e. from in-band replay/banking stage; that ensures root is *fixed* while
4998    // running).
4999    // pro: safer assertion can be enabled inside AccountsDb
5000    // con: panics!() if called from off-chain processing
5001    pub fn get_account_with_fixed_root(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
5002        self.get_account_modified_slot_with_fixed_root(pubkey)
5003            .map(|(acc, _slot)| acc)
5004    }
5005
5006    // See note above get_account_with_fixed_root() about when to prefer this function
5007    pub fn get_account_modified_slot_with_fixed_root(
5008        &self,
5009        pubkey: &Pubkey,
5010    ) -> Option<(AccountSharedData, Slot)> {
5011        self.load_slow_with_fixed_root(&self.ancestors, pubkey)
5012    }
5013
5014    pub fn get_account_modified_slot(&self, pubkey: &Pubkey) -> Option<(AccountSharedData, Slot)> {
5015        self.load_slow(&self.ancestors, pubkey)
5016    }
5017
5018    fn load_slow(
5019        &self,
5020        ancestors: &Ancestors,
5021        pubkey: &Pubkey,
5022    ) -> Option<(AccountSharedData, Slot)> {
5023        // get_account (= primary this fn caller) may be called from on-chain Bank code even if we
5024        // try hard to use get_account_with_fixed_root for that purpose...
5025        // so pass safer LoadHint:Unspecified here as a fallback
5026        self.rc.accounts.load_without_fixed_root(ancestors, pubkey)
5027    }
5028
5029    fn load_slow_with_fixed_root(
5030        &self,
5031        ancestors: &Ancestors,
5032        pubkey: &Pubkey,
5033    ) -> Option<(AccountSharedData, Slot)> {
5034        self.rc.accounts.load_with_fixed_root(ancestors, pubkey)
5035    }
5036
5037    pub fn get_program_accounts(
5038        &self,
5039        program_id: &Pubkey,
5040        config: &ScanConfig,
5041    ) -> ScanResult<Vec<TransactionAccount>> {
5042        self.rc
5043            .accounts
5044            .load_by_program(&self.ancestors, self.bank_id, program_id, config)
5045    }
5046
5047    pub fn get_filtered_program_accounts<F: Fn(&AccountSharedData) -> bool>(
5048        &self,
5049        program_id: &Pubkey,
5050        filter: F,
5051        config: &ScanConfig,
5052    ) -> ScanResult<Vec<TransactionAccount>> {
5053        self.rc.accounts.load_by_program_with_filter(
5054            &self.ancestors,
5055            self.bank_id,
5056            program_id,
5057            filter,
5058            config,
5059        )
5060    }
5061
5062    pub fn get_filtered_indexed_accounts<F: Fn(&AccountSharedData) -> bool>(
5063        &self,
5064        index_key: &IndexKey,
5065        filter: F,
5066        config: &ScanConfig,
5067        byte_limit_for_scan: Option<usize>,
5068    ) -> ScanResult<Vec<TransactionAccount>> {
5069        self.rc.accounts.load_by_index_key_with_filter(
5070            &self.ancestors,
5071            self.bank_id,
5072            index_key,
5073            filter,
5074            config,
5075            byte_limit_for_scan,
5076        )
5077    }
5078
5079    pub fn account_indexes_include_key(&self, key: &Pubkey) -> bool {
5080        self.rc.accounts.account_indexes_include_key(key)
5081    }
5082
5083    /// Returns all the accounts this bank can load
5084    pub fn get_all_accounts(&self, sort_results: bool) -> ScanResult<Vec<PubkeyAccountSlot>> {
5085        self.rc
5086            .accounts
5087            .load_all(&self.ancestors, self.bank_id, sort_results)
5088    }
5089
5090    // Scans all the accounts this bank can load, applying `scan_func`
5091    pub fn scan_all_accounts<F>(&self, scan_func: F, sort_results: bool) -> ScanResult<()>
5092    where
5093        F: FnMut(Option<(&Pubkey, AccountSharedData, Slot)>),
5094    {
5095        self.rc
5096            .accounts
5097            .scan_all(&self.ancestors, self.bank_id, scan_func, sort_results)
5098    }
5099
5100    pub fn get_program_accounts_modified_since_parent(
5101        &self,
5102        program_id: &Pubkey,
5103    ) -> Vec<TransactionAccount> {
5104        self.rc
5105            .accounts
5106            .load_by_program_slot(self.slot(), Some(program_id))
5107    }
5108
5109    pub fn get_transaction_logs(
5110        &self,
5111        address: Option<&Pubkey>,
5112    ) -> Option<Vec<TransactionLogInfo>> {
5113        self.transaction_log_collector
5114            .read()
5115            .unwrap()
5116            .get_logs_for_address(address)
5117    }
5118
5119    /// Returns all the accounts stored in this slot
5120    pub fn get_all_accounts_modified_since_parent(&self) -> Vec<TransactionAccount> {
5121        self.rc.accounts.load_by_program_slot(self.slot(), None)
5122    }
5123
5124    // if you want get_account_modified_since_parent without fixed_root, please define so...
5125    fn get_account_modified_since_parent_with_fixed_root(
5126        &self,
5127        pubkey: &Pubkey,
5128    ) -> Option<(AccountSharedData, Slot)> {
5129        let just_self: Ancestors = Ancestors::from(vec![self.slot()]);
5130        if let Some((account, slot)) = self.load_slow_with_fixed_root(&just_self, pubkey) {
5131            if slot == self.slot() {
5132                return Some((account, slot));
5133            }
5134        }
5135        None
5136    }
5137
5138    pub fn get_largest_accounts(
5139        &self,
5140        num: usize,
5141        filter_by_address: &HashSet<Pubkey>,
5142        filter: AccountAddressFilter,
5143        sort_results: bool,
5144    ) -> ScanResult<Vec<(Pubkey, u64)>> {
5145        self.rc.accounts.load_largest_accounts(
5146            &self.ancestors,
5147            self.bank_id,
5148            num,
5149            filter_by_address,
5150            filter,
5151            sort_results,
5152        )
5153    }
5154
5155    /// Return the accumulated executed transaction count
5156    pub fn transaction_count(&self) -> u64 {
5157        self.transaction_count.load(Relaxed)
5158    }
5159
5160    /// Returns the number of non-vote transactions processed without error
5161    /// since the most recent boot from snapshot or genesis.
5162    /// This value is not shared though the network, nor retained
5163    /// within snapshots, but is preserved in `Bank::new_from_parent`.
5164    pub fn non_vote_transaction_count_since_restart(&self) -> u64 {
5165        self.non_vote_transaction_count_since_restart.load(Relaxed)
5166    }
5167
5168    /// Return the transaction count executed only in this bank
5169    pub fn executed_transaction_count(&self) -> u64 {
5170        self.transaction_count()
5171            .saturating_sub(self.parent().map_or(0, |parent| parent.transaction_count()))
5172    }
5173
5174    pub fn transaction_error_count(&self) -> u64 {
5175        self.transaction_error_count.load(Relaxed)
5176    }
5177
5178    pub fn transaction_entries_count(&self) -> u64 {
5179        self.transaction_entries_count.load(Relaxed)
5180    }
5181
5182    pub fn transactions_per_entry_max(&self) -> u64 {
5183        self.transactions_per_entry_max.load(Relaxed)
5184    }
5185
5186    fn increment_transaction_count(&self, tx_count: u64) {
5187        self.transaction_count.fetch_add(tx_count, Relaxed);
5188    }
5189
5190    fn increment_non_vote_transaction_count_since_restart(&self, tx_count: u64) {
5191        self.non_vote_transaction_count_since_restart
5192            .fetch_add(tx_count, Relaxed);
5193    }
5194
5195    pub fn signature_count(&self) -> u64 {
5196        self.signature_count.load(Relaxed)
5197    }
5198
5199    fn increment_signature_count(&self, signature_count: u64) {
5200        self.signature_count.fetch_add(signature_count, Relaxed);
5201    }
5202
5203    pub fn get_signature_status_processed_since_parent(
5204        &self,
5205        signature: &Signature,
5206    ) -> Option<Result<()>> {
5207        if let Some((slot, status)) = self.get_signature_status_slot(signature) {
5208            if slot <= self.slot() {
5209                return Some(status);
5210            }
5211        }
5212        None
5213    }
5214
5215    pub fn get_signature_status_with_blockhash(
5216        &self,
5217        signature: &Signature,
5218        blockhash: &Hash,
5219    ) -> Option<Result<()>> {
5220        let rcache = self.status_cache.read().unwrap();
5221        rcache
5222            .get_status(signature, blockhash, &self.ancestors)
5223            .map(|v| v.1)
5224    }
5225
5226    pub fn get_signature_status_slot(&self, signature: &Signature) -> Option<(Slot, Result<()>)> {
5227        let rcache = self.status_cache.read().unwrap();
5228        rcache.get_status_any_blockhash(signature, &self.ancestors)
5229    }
5230
5231    pub fn get_signature_status(&self, signature: &Signature) -> Option<Result<()>> {
5232        self.get_signature_status_slot(signature).map(|v| v.1)
5233    }
5234
5235    pub fn has_signature(&self, signature: &Signature) -> bool {
5236        self.get_signature_status_slot(signature).is_some()
5237    }
5238
5239    /// Hash the `accounts` HashMap. This represents a validator's interpretation
5240    ///  of the delta of the ledger since the last vote and up to now
5241    fn hash_internal_state(&self) -> Hash {
5242        let measure_total = Measure::start("");
5243        let slot = self.slot();
5244
5245        let delta_hash_info = (!self
5246            .feature_set
5247            .is_active(&feature_set::remove_accounts_delta_hash::id()))
5248        .then(|| {
5249            measure_us!({
5250                self.rc
5251                    .accounts
5252                    .accounts_db
5253                    .calculate_accounts_delta_hash_internal(
5254                        slot,
5255                        None,
5256                        self.skipped_rewrites.lock().unwrap().clone(),
5257                    )
5258            })
5259        });
5260
5261        let mut hash = if let Some((accounts_delta_hash, _measure)) = delta_hash_info.as_ref() {
5262            hashv(&[
5263                self.parent_hash.as_ref(),
5264                accounts_delta_hash.0.as_ref(),
5265                &self.signature_count().to_le_bytes(),
5266                self.last_blockhash().as_ref(),
5267            ])
5268        } else {
5269            hashv(&[
5270                self.parent_hash.as_ref(),
5271                &self.signature_count().to_le_bytes(),
5272                self.last_blockhash().as_ref(),
5273            ])
5274        };
5275
5276        let accounts_hash_info = if self
5277            .feature_set
5278            .is_active(&feature_set::accounts_lt_hash::id())
5279        {
5280            let accounts_lt_hash = &*self.accounts_lt_hash.lock().unwrap();
5281            let lt_hash_bytes = bytemuck::must_cast_slice(&accounts_lt_hash.0 .0);
5282            hash = hashv(&[hash.as_ref(), lt_hash_bytes]);
5283            let checksum = accounts_lt_hash.0.checksum();
5284            Some(format!(", accounts_lt_hash checksum: {checksum}"))
5285        } else {
5286            let epoch_accounts_hash = self.wait_get_epoch_accounts_hash();
5287            epoch_accounts_hash.map(|epoch_accounts_hash| {
5288                hash = hashv(&[hash.as_ref(), epoch_accounts_hash.as_ref().as_ref()]);
5289                format!(", epoch_accounts_hash: {:?}", epoch_accounts_hash.as_ref())
5290            })
5291        };
5292
5293        let buf = self
5294            .hard_forks
5295            .read()
5296            .unwrap()
5297            .get_hash_data(slot, self.parent_slot());
5298        if let Some(buf) = buf {
5299            let hard_forked_hash = extend_and_hash(&hash, &buf);
5300            warn!("hard fork at slot {slot} by hashing {buf:?}: {hash} => {hard_forked_hash}");
5301            hash = hard_forked_hash;
5302        }
5303
5304        #[cfg(feature = "dev-context-only-utils")]
5305        let hash_override = self
5306            .hash_overrides
5307            .lock()
5308            .unwrap()
5309            .get_bank_hash_override(slot)
5310            .copied()
5311            .inspect(|&hash_override| {
5312                if hash_override != hash {
5313                    info!(
5314                        "bank: slot: {}: overrode bank hash: {} with {}",
5315                        self.slot(),
5316                        hash,
5317                        hash_override
5318                    );
5319                }
5320            });
5321        // Avoid to optimize out `hash` along with the whole computation by super smart rustc.
5322        // hash_override is used by ledger-tool's simulate-block-production, which prefers
5323        // the actual bank freezing processing for accurate simulation.
5324        #[cfg(feature = "dev-context-only-utils")]
5325        let hash = hash_override.unwrap_or(std::hint::black_box(hash));
5326
5327        let bank_hash_stats = self.bank_hash_stats.load();
5328
5329        let total_us = measure_total.end_as_us();
5330
5331        let (accounts_delta_hash_us, accounts_delta_hash_log) = delta_hash_info
5332            .map(|(hash, us)| (us, format!(" accounts_delta: {}", hash.0)))
5333            .unzip();
5334        datapoint_info!(
5335            "bank-hash_internal_state",
5336            ("slot", slot, i64),
5337            ("total_us", total_us, i64),
5338            ("accounts_delta_hash_us", accounts_delta_hash_us, Option<i64>),
5339        );
5340        info!(
5341            "bank frozen: {slot} hash: {hash}{} signature_count: {} last_blockhash: {} capitalization: {}{}, stats: {bank_hash_stats:?}",
5342            accounts_delta_hash_log.unwrap_or_default(),
5343            self.signature_count(),
5344            self.last_blockhash(),
5345            self.capitalization(),
5346            accounts_hash_info.unwrap_or_default(),
5347        );
5348        hash
5349    }
5350
5351    pub fn collector_fees(&self) -> u64 {
5352        self.collector_fees.load(Relaxed)
5353    }
5354
5355    /// The epoch accounts hash is hashed into the bank's hash once per epoch at a predefined slot.
5356    /// Should it be included in *this* bank?
5357    fn should_include_epoch_accounts_hash(&self) -> bool {
5358        if !epoch_accounts_hash_utils::is_enabled_this_epoch(self) {
5359            return false;
5360        }
5361
5362        let stop_slot = epoch_accounts_hash_utils::calculation_stop(self);
5363        self.parent_slot() < stop_slot && self.slot() >= stop_slot
5364    }
5365
5366    /// If the epoch accounts hash should be included in this Bank, then fetch it. If the EAH
5367    /// calculation has not completed yet, this fn will block until it does complete.
5368    fn wait_get_epoch_accounts_hash(&self) -> Option<EpochAccountsHash> {
5369        if !self.should_include_epoch_accounts_hash() {
5370            return None;
5371        }
5372
5373        let (epoch_accounts_hash, waiting_time_us) = measure_us!(self
5374            .rc
5375            .accounts
5376            .accounts_db
5377            .epoch_accounts_hash_manager
5378            .wait_get_epoch_accounts_hash());
5379
5380        datapoint_info!(
5381            "bank-wait_get_epoch_accounts_hash",
5382            ("slot", self.slot(), i64),
5383            ("waiting-time-us", waiting_time_us, i64),
5384        );
5385        Some(epoch_accounts_hash)
5386    }
5387
5388    /// Used by ledger tool to run a final hash calculation once all ledger replay has completed.
5389    /// This should not be called by validator code.
5390    pub fn run_final_hash_calc(&self, on_halt_store_hash_raw_data_for_debug: bool) {
5391        self.force_flush_accounts_cache();
5392        // note that this slot may not be a root
5393        _ = self.verify_accounts_hash(
5394            None,
5395            VerifyAccountsHashConfig {
5396                test_hash_calculation: false,
5397                ignore_mismatch: true,
5398                require_rooted_bank: false,
5399                run_in_background: false,
5400                store_hash_raw_data_for_debug: on_halt_store_hash_raw_data_for_debug,
5401            },
5402            None,
5403        );
5404    }
5405
5406    /// Recalculate the accounts hash from the account stores. Used to verify a snapshot.
5407    /// return true if all is good
5408    /// Only called from startup or test code.
5409    #[must_use]
5410    fn verify_accounts_hash(
5411        &self,
5412        base: Option<(Slot, /*capitalization*/ u64)>,
5413        mut config: VerifyAccountsHashConfig,
5414        duplicates_lt_hash: Option<Box<DuplicatesLtHash>>,
5415    ) -> bool {
5416        #[derive(Debug, Eq, PartialEq)]
5417        enum VerifyKind {
5418            Merkle,
5419            Lattice,
5420        }
5421
5422        let accounts = &self.rc.accounts;
5423        // Wait until initial hash calc is complete before starting a new hash calc.
5424        // This should only occur when we halt at a slot in ledger-tool.
5425        accounts
5426            .accounts_db
5427            .verify_accounts_hash_in_bg
5428            .join_background_thread();
5429
5430        let slot = self.slot();
5431
5432        let verify_kind = match (
5433            duplicates_lt_hash.is_some(),
5434            self.rc
5435                .accounts
5436                .accounts_db
5437                .is_experimental_accumulator_hash_enabled(),
5438        ) {
5439            (true, _) => VerifyKind::Lattice,
5440            (false, false) => VerifyKind::Merkle,
5441            (false, true) => {
5442                // Calculating the accounts lt hash from storages *requires* a duplicates_lt_hash.
5443                // If it is None here, then we must use the index instead, which also means we
5444                // cannot run in the background.
5445                config.run_in_background = false;
5446                VerifyKind::Lattice
5447            }
5448        };
5449
5450        if config.require_rooted_bank && !accounts.accounts_db.accounts_index.is_alive_root(slot) {
5451            if let Some(parent) = self.parent() {
5452                info!(
5453                    "slot {slot} is not a root, so verify accounts hash on parent bank at slot {}",
5454                    parent.slot(),
5455                );
5456                if verify_kind == VerifyKind::Lattice {
5457                    // The duplicates_lt_hash is only valid for the current slot, so we must fall
5458                    // back to verifying the accounts lt hash with the index (which also means we
5459                    // cannot run in the background).
5460                    config.run_in_background = false;
5461                }
5462                return parent.verify_accounts_hash(base, config, None);
5463            } else {
5464                // this will result in mismatch errors
5465                // accounts hash calc doesn't include unrooted slots
5466                panic!("cannot verify accounts hash because slot {slot} is not a root");
5467            }
5468        }
5469
5470        // The snapshot storages must be captured *before* starting the background verification.
5471        // Otherwise, it is possible that a delayed call to `get_snapshot_storages()` will *not*
5472        // get the correct storages required to calculate and verify the accounts hashes.
5473        let snapshot_storages = self.rc.accounts.accounts_db.get_storages(RangeFull);
5474        let capitalization = self.capitalization();
5475        let verify_config = VerifyAccountsHashAndLamportsConfig {
5476            ancestors: &self.ancestors,
5477            epoch_schedule: self.epoch_schedule(),
5478            rent_collector: self.rent_collector(),
5479            test_hash_calculation: config.test_hash_calculation,
5480            ignore_mismatch: config.ignore_mismatch,
5481            store_detailed_debug_info: config.store_hash_raw_data_for_debug,
5482            use_bg_thread_pool: config.run_in_background,
5483        };
5484
5485        info!(
5486            "Verifying accounts, in background? {}, verify kind: {verify_kind:?}",
5487            config.run_in_background,
5488        );
5489        if config.run_in_background {
5490            let accounts = Arc::clone(accounts);
5491            let accounts_ = Arc::clone(&accounts);
5492            let ancestors = self.ancestors.clone();
5493            let epoch_schedule = self.epoch_schedule().clone();
5494            let rent_collector = self.rent_collector().clone();
5495            let expected_accounts_lt_hash = self.accounts_lt_hash.lock().unwrap().clone();
5496            accounts.accounts_db.verify_accounts_hash_in_bg.start(|| {
5497                Builder::new()
5498                    .name("solBgHashVerify".into())
5499                    .spawn(move || {
5500                        info!("Initial background accounts hash verification has started");
5501                        let start = Instant::now();
5502                        let mut lattice_verify_time = None;
5503                        let mut merkle_verify_time = None;
5504                        let is_ok = match verify_kind {
5505                            VerifyKind::Lattice => {
5506                                // accounts lt hash is *enabled* so use lattice-based verification
5507                                let accounts_db = &accounts_.accounts_db;
5508                                let (calculated_accounts_lt_hash, duration) =
5509                                    meas_dur!(accounts_db.thread_pool_hash.install(|| {
5510                                        accounts_db
5511                                            .calculate_accounts_lt_hash_at_startup_from_storages(
5512                                                snapshot_storages.0.as_slice(),
5513                                                &duplicates_lt_hash.unwrap(),
5514                                            )
5515                                    }));
5516                                let is_ok =
5517                                    calculated_accounts_lt_hash == expected_accounts_lt_hash;
5518                                if !is_ok {
5519                                    let expected = expected_accounts_lt_hash.0.checksum();
5520                                    let calculated = calculated_accounts_lt_hash.0.checksum();
5521                                    error!(
5522                                        "Verifying accounts failed: accounts lattice hashes do not \
5523                                         match, expected: {expected}, calculated: {calculated}",
5524                                    );
5525                                }
5526                                lattice_verify_time = Some(duration);
5527                                is_ok
5528                            }
5529                            VerifyKind::Merkle => {
5530                                // accounts lt hash is *disabled* so use merkle-based verification
5531                                let snapshot_storages_and_slots = (
5532                                    snapshot_storages.0.as_slice(),
5533                                    snapshot_storages.1.as_slice(),
5534                                );
5535                                let (is_ok, duration) = meas_dur!(accounts_
5536                                    .verify_accounts_hash_and_lamports(
5537                                        snapshot_storages_and_slots,
5538                                        slot,
5539                                        capitalization,
5540                                        base,
5541                                        VerifyAccountsHashAndLamportsConfig {
5542                                            ancestors: &ancestors,
5543                                            epoch_schedule: &epoch_schedule,
5544                                            rent_collector: &rent_collector,
5545                                            ..verify_config
5546                                        },
5547                                    ));
5548                                merkle_verify_time = Some(duration);
5549                                is_ok
5550                            }
5551                        };
5552                        accounts_
5553                            .accounts_db
5554                            .verify_accounts_hash_in_bg
5555                            .background_finished();
5556                        let total_time = start.elapsed();
5557                        datapoint_info!(
5558                            "startup_verify_accounts",
5559                            ("total_us", total_time.as_micros(), i64),
5560                            (
5561                                "verify_accounts_lt_hash_us",
5562                                lattice_verify_time.as_ref().map(Duration::as_micros),
5563                                Option<i64>
5564                            ),
5565                            ("verify_accounts_hash_us",
5566                                merkle_verify_time.as_ref().map(Duration::as_micros),
5567                                Option<i64>
5568                            ),
5569                        );
5570                        info!("Initial background accounts hash verification has stopped");
5571                        is_ok
5572                    })
5573                    .unwrap()
5574            });
5575            true // initial result is true. We haven't failed yet. If verification fails, we'll panic from bg thread.
5576        } else {
5577            match verify_kind {
5578                VerifyKind::Lattice => {
5579                    let expected_accounts_lt_hash = self.accounts_lt_hash.lock().unwrap().clone();
5580                    let calculated_accounts_lt_hash = if let Some(duplicates_lt_hash) =
5581                        duplicates_lt_hash
5582                    {
5583                        accounts
5584                            .accounts_db
5585                            .calculate_accounts_lt_hash_at_startup_from_storages(
5586                                snapshot_storages.0.as_slice(),
5587                                &duplicates_lt_hash,
5588                            )
5589                    } else {
5590                        accounts
5591                            .accounts_db
5592                            .calculate_accounts_lt_hash_at_startup_from_index(&self.ancestors, slot)
5593                    };
5594                    let is_ok = calculated_accounts_lt_hash == expected_accounts_lt_hash;
5595                    if !is_ok {
5596                        let expected = expected_accounts_lt_hash.0.checksum();
5597                        let calculated = calculated_accounts_lt_hash.0.checksum();
5598                        error!(
5599                            "Verifying accounts failed: accounts lattice hashes do not \
5600                             match, expected: {expected}, calculated: {calculated}",
5601                        );
5602                    }
5603                    is_ok
5604                }
5605                VerifyKind::Merkle => {
5606                    let snapshot_storages_and_slots = (
5607                        snapshot_storages.0.as_slice(),
5608                        snapshot_storages.1.as_slice(),
5609                    );
5610                    let is_ok = accounts.verify_accounts_hash_and_lamports(
5611                        snapshot_storages_and_slots,
5612                        slot,
5613                        capitalization,
5614                        base,
5615                        verify_config,
5616                    );
5617                    self.set_initial_accounts_hash_verification_completed();
5618                    is_ok
5619                }
5620            }
5621        }
5622    }
5623
5624    /// Specify that initial verification has completed.
5625    /// Called internally when verification runs in the foreground thread.
5626    /// Also has to be called by some tests which don't do verification on startup.
5627    pub fn set_initial_accounts_hash_verification_completed(&self) {
5628        self.rc
5629            .accounts
5630            .accounts_db
5631            .verify_accounts_hash_in_bg
5632            .verification_complete();
5633    }
5634
5635    /// return true if bg hash verification is complete
5636    /// return false if bg hash verification has not completed yet
5637    /// if hash verification failed, a panic will occur
5638    pub fn has_initial_accounts_hash_verification_completed(&self) -> bool {
5639        self.rc
5640            .accounts
5641            .accounts_db
5642            .verify_accounts_hash_in_bg
5643            .check_complete()
5644    }
5645
5646    /// Get this bank's storages to use for snapshots.
5647    ///
5648    /// If a base slot is provided, return only the storages that are *higher* than this slot.
5649    pub fn get_snapshot_storages(&self, base_slot: Option<Slot>) -> Vec<Arc<AccountStorageEntry>> {
5650        // if a base slot is provided, request storages starting at the slot *after*
5651        let start_slot = base_slot.map_or(0, |slot| slot.saturating_add(1));
5652        // we want to *include* the storage at our slot
5653        let requested_slots = start_slot..=self.slot();
5654
5655        self.rc.accounts.accounts_db.get_storages(requested_slots).0
5656    }
5657
5658    #[must_use]
5659    fn verify_hash(&self) -> bool {
5660        assert!(self.is_frozen());
5661        let calculated_hash = self.hash_internal_state();
5662        let expected_hash = self.hash();
5663
5664        if calculated_hash == expected_hash {
5665            true
5666        } else {
5667            warn!(
5668                "verify failed: slot: {}, {} (calculated) != {} (expected)",
5669                self.slot(),
5670                calculated_hash,
5671                expected_hash
5672            );
5673            false
5674        }
5675    }
5676
5677    pub fn verify_transaction(
5678        &self,
5679        tx: VersionedTransaction,
5680        verification_mode: TransactionVerificationMode,
5681    ) -> Result<RuntimeTransaction<SanitizedTransaction>> {
5682        let sanitized_tx = {
5683            let size =
5684                bincode::serialized_size(&tx).map_err(|_| TransactionError::SanitizeFailure)?;
5685            if size > PACKET_DATA_SIZE as u64 {
5686                return Err(TransactionError::SanitizeFailure);
5687            }
5688            let message_hash = if verification_mode == TransactionVerificationMode::FullVerification
5689            {
5690                tx.verify_and_hash_message()?
5691            } else {
5692                tx.message.hash()
5693            };
5694
5695            RuntimeTransaction::try_create(
5696                tx,
5697                MessageHash::Precomputed(message_hash),
5698                None,
5699                self,
5700                self.get_reserved_account_keys(),
5701            )
5702        }?;
5703
5704        let move_precompile_verification_to_svm = self
5705            .feature_set
5706            .is_active(&feature_set::move_precompile_verification_to_svm::id());
5707        if !move_precompile_verification_to_svm && {
5708            verification_mode == TransactionVerificationMode::HashAndVerifyPrecompiles
5709                || verification_mode == TransactionVerificationMode::FullVerification
5710        } {
5711            verify_precompiles(&sanitized_tx, &self.feature_set)?;
5712        }
5713
5714        Ok(sanitized_tx)
5715    }
5716
5717    pub fn fully_verify_transaction(
5718        &self,
5719        tx: VersionedTransaction,
5720    ) -> Result<RuntimeTransaction<SanitizedTransaction>> {
5721        self.verify_transaction(tx, TransactionVerificationMode::FullVerification)
5722    }
5723
5724    /// Checks if the transaction violates the bank's reserved keys.
5725    /// This needs to be checked upon epoch boundary crosses because the
5726    /// reserved key set may have changed since the initial sanitization.
5727    pub fn check_reserved_keys(&self, tx: &impl SVMMessage) -> Result<()> {
5728        // Check keys against the reserved set - these failures simply require us
5729        // to re-sanitize the transaction. We do not need to drop the transaction.
5730        let reserved_keys = self.get_reserved_account_keys();
5731        for (index, key) in tx.account_keys().iter().enumerate() {
5732            if tx.is_writable(index) && reserved_keys.contains(key) {
5733                return Err(TransactionError::ResanitizationNeeded);
5734            }
5735        }
5736
5737        Ok(())
5738    }
5739
5740    /// only called from ledger-tool or tests
5741    fn calculate_capitalization(&self, debug_verify: bool) -> u64 {
5742        let is_startup = true;
5743        self.rc
5744            .accounts
5745            .accounts_db
5746            .verify_accounts_hash_in_bg
5747            .join_background_thread();
5748        self.rc
5749            .accounts
5750            .accounts_db
5751            .update_accounts_hash_with_verify_from(
5752                // we have to use the index since the slot could be in the write cache still
5753                CalcAccountsHashDataSource::IndexForTests,
5754                debug_verify,
5755                self.slot(),
5756                &self.ancestors,
5757                None,
5758                self.epoch_schedule(),
5759                &self.rent_collector,
5760                is_startup,
5761            )
5762            .1
5763    }
5764
5765    /// only called from tests or ledger tool
5766    pub fn calculate_and_verify_capitalization(&self, debug_verify: bool) -> bool {
5767        let calculated = self.calculate_capitalization(debug_verify);
5768        let expected = self.capitalization();
5769        if calculated == expected {
5770            true
5771        } else {
5772            warn!(
5773                "Capitalization mismatch: calculated: {} != expected: {}",
5774                calculated, expected
5775            );
5776            false
5777        }
5778    }
5779
5780    /// Forcibly overwrites current capitalization by actually recalculating accounts' balances.
5781    /// This should only be used for developing purposes.
5782    pub fn set_capitalization(&self) -> u64 {
5783        let old = self.capitalization();
5784        // We cannot debug verify the hash calculation here because calculate_capitalization will use the index calculation due to callers using the write cache.
5785        // debug_verify only exists as an extra debugging step under the assumption that this code path is only used for tests. But, this is used by ledger-tool create-snapshot
5786        // for example.
5787        let debug_verify = false;
5788        self.capitalization
5789            .store(self.calculate_capitalization(debug_verify), Relaxed);
5790        old
5791    }
5792
5793    /// Returns the `AccountsHash` that was calculated for this bank's slot
5794    ///
5795    /// This fn is used when creating a snapshot with ledger-tool, or when
5796    /// packaging a snapshot into an archive (used to get the `SnapshotHash`).
5797    pub fn get_accounts_hash(&self) -> Option<AccountsHash> {
5798        self.rc
5799            .accounts
5800            .accounts_db
5801            .get_accounts_hash(self.slot())
5802            .map(|(accounts_hash, _)| accounts_hash)
5803    }
5804
5805    /// Returns the `IncrementalAccountsHash` that was calculated for this bank's slot
5806    ///
5807    /// This fn is used when creating an incremental snapshot with ledger-tool, or when
5808    /// packaging a snapshot into an archive (used to get the `SnapshotHash`).
5809    pub fn get_incremental_accounts_hash(&self) -> Option<IncrementalAccountsHash> {
5810        self.rc
5811            .accounts
5812            .accounts_db
5813            .get_incremental_accounts_hash(self.slot())
5814            .map(|(incremental_accounts_hash, _)| incremental_accounts_hash)
5815    }
5816
5817    /// Returns the `SnapshotHash` for this bank's slot
5818    ///
5819    /// This fn is used at startup to verify the bank was rebuilt correctly.
5820    ///
5821    /// # Panics
5822    ///
5823    /// If the snapshots lt hash feature is not enabled, panics if there is both-or-neither of an
5824    /// `AccountsHash` and an `IncrementalAccountsHash` for this bank's slot.  There may only be
5825    /// one or the other.
5826    pub fn get_snapshot_hash(&self) -> SnapshotHash {
5827        if self.is_snapshots_lt_hash_enabled() {
5828            self.get_lattice_snapshot_hash()
5829        } else {
5830            self.get_merkle_snapshot_hash()
5831        }
5832    }
5833
5834    /// Returns the merkle-based `SnapshotHash` for this bank's slot
5835    ///
5836    /// This fn is used at startup to verify the bank was rebuilt correctly.
5837    ///
5838    /// # Panics
5839    ///
5840    /// If the snapshots lt hash feature is not enabled, panics if there is both-or-neither of an
5841    /// `AccountsHash` and an `IncrementalAccountsHash` for this bank's slot.  There may only be
5842    /// one or the other.
5843    pub fn get_merkle_snapshot_hash(&self) -> SnapshotHash {
5844        let accounts_hash = self.get_accounts_hash();
5845        let incremental_accounts_hash = self.get_incremental_accounts_hash();
5846        let accounts_hash_kind = match (accounts_hash, incremental_accounts_hash) {
5847            (Some(_), Some(_)) => panic!("Both full and incremental accounts hashes are present for slot {}; it is ambiguous which one to use for the snapshot hash!", self.slot()),
5848            (Some(accounts_hash), None) => accounts_hash.into(),
5849            (None, Some(incremental_accounts_hash)) => incremental_accounts_hash.into(),
5850            (None, None) => panic!("accounts hash is required to get snapshot hash"),
5851        };
5852        let epoch_accounts_hash = self.get_epoch_accounts_hash_to_serialize();
5853        SnapshotHash::new(
5854            &MerkleOrLatticeAccountsHash::Merkle(accounts_hash_kind),
5855            epoch_accounts_hash.as_ref(),
5856            None,
5857        )
5858    }
5859
5860    /// Returns the lattice-based `SnapshotHash` for this bank's slot
5861    ///
5862    /// This fn is used at startup to verify the bank was rebuilt correctly.
5863    pub fn get_lattice_snapshot_hash(&self) -> SnapshotHash {
5864        SnapshotHash::new(
5865            &MerkleOrLatticeAccountsHash::Lattice,
5866            None,
5867            Some(self.accounts_lt_hash.lock().unwrap().0.checksum()),
5868        )
5869    }
5870
5871    pub fn load_account_into_read_cache(&self, key: &Pubkey) {
5872        self.rc
5873            .accounts
5874            .accounts_db
5875            .load_account_into_read_cache(&self.ancestors, key);
5876    }
5877
5878    pub fn update_accounts_hash(
5879        &self,
5880        data_source: CalcAccountsHashDataSource,
5881        mut debug_verify: bool,
5882        is_startup: bool,
5883    ) -> AccountsHash {
5884        let (accounts_hash, total_lamports) = self
5885            .rc
5886            .accounts
5887            .accounts_db
5888            .update_accounts_hash_with_verify_from(
5889                data_source,
5890                debug_verify,
5891                self.slot(),
5892                &self.ancestors,
5893                Some(self.capitalization()),
5894                self.epoch_schedule(),
5895                &self.rent_collector,
5896                is_startup,
5897            );
5898        if total_lamports != self.capitalization() {
5899            datapoint_info!(
5900                "capitalization_mismatch",
5901                ("slot", self.slot(), i64),
5902                ("calculated_lamports", total_lamports, i64),
5903                ("capitalization", self.capitalization(), i64),
5904            );
5905
5906            if !debug_verify {
5907                // cap mismatch detected. It has been logged to metrics above.
5908                // Run both versions of the calculation to attempt to get more info.
5909                debug_verify = true;
5910                self.rc
5911                    .accounts
5912                    .accounts_db
5913                    .update_accounts_hash_with_verify_from(
5914                        data_source,
5915                        debug_verify,
5916                        self.slot(),
5917                        &self.ancestors,
5918                        Some(self.capitalization()),
5919                        self.epoch_schedule(),
5920                        &self.rent_collector,
5921                        is_startup,
5922                    );
5923            }
5924
5925            panic!(
5926                "capitalization_mismatch. slot: {}, calculated_lamports: {}, capitalization: {}",
5927                self.slot(),
5928                total_lamports,
5929                self.capitalization()
5930            );
5931        }
5932        accounts_hash
5933    }
5934
5935    /// Calculate the incremental accounts hash from `base_slot` to `self`
5936    pub fn update_incremental_accounts_hash(&self, base_slot: Slot) -> IncrementalAccountsHash {
5937        let config = CalcAccountsHashConfig {
5938            use_bg_thread_pool: true,
5939            ancestors: None, // does not matter, will not be used
5940            epoch_schedule: &self.epoch_schedule,
5941            rent_collector: &self.rent_collector,
5942            store_detailed_debug_info_on_failure: false,
5943        };
5944        let storages = self.get_snapshot_storages(Some(base_slot));
5945        let sorted_storages = SortedStorages::new(&storages);
5946        self.rc
5947            .accounts
5948            .accounts_db
5949            .update_incremental_accounts_hash(
5950                &config,
5951                &sorted_storages,
5952                self.slot(),
5953                HashStats::default(),
5954            )
5955            .0
5956    }
5957
5958    /// A snapshot bank should be purged of 0 lamport accounts which are not part of the hash
5959    /// calculation and could shield other real accounts.
5960    pub fn verify_snapshot_bank(
5961        &self,
5962        test_hash_calculation: bool,
5963        skip_shrink: bool,
5964        force_clean: bool,
5965        latest_full_snapshot_slot: Slot,
5966        base: Option<(Slot, /*capitalization*/ u64)>,
5967        duplicates_lt_hash: Option<Box<DuplicatesLtHash>>,
5968    ) -> bool {
5969        // If we verify the accounts using the lattice-based hash *and* with storages (as opposed
5970        // to the index), then we rely on the DuplicatesLtHash as given by generate_index().  Since
5971        // the duplicates are based on a specific set of storages, we must use the exact same
5972        // storages to do the lattice-based accounts verification.  This means we must wait to
5973        // clean/shrink until *after* we've gotten Arcs to the storages (this prevents their
5974        // untimely removal).  Simply, we call `verify_accounts_hash()` before we call `clean` or
5975        // `shrink`.
5976        let (verified_accounts, verify_accounts_time_us) = measure_us!({
5977            let should_verify_accounts = !self.rc.accounts.accounts_db.skip_initial_hash_calc;
5978            if should_verify_accounts {
5979                info!("Verifying accounts...");
5980                let verified = self.verify_accounts_hash(
5981                    base,
5982                    VerifyAccountsHashConfig {
5983                        test_hash_calculation,
5984                        ignore_mismatch: false,
5985                        require_rooted_bank: false,
5986                        run_in_background: true,
5987                        store_hash_raw_data_for_debug: false,
5988                    },
5989                    duplicates_lt_hash,
5990                );
5991                info!("Verifying accounts... In background.");
5992                verified
5993            } else {
5994                info!("Verifying accounts... Skipped.");
5995                self.rc
5996                    .accounts
5997                    .accounts_db
5998                    .verify_accounts_hash_in_bg
5999                    .verification_complete();
6000                true
6001            }
6002        });
6003
6004        let (_, clean_time_us) = measure_us!({
6005            let should_clean = force_clean || (!skip_shrink && self.slot() > 0);
6006            if should_clean {
6007                info!("Cleaning...");
6008                // We cannot clean past the latest full snapshot's slot because we are about to
6009                // perform an accounts hash calculation *up to that slot*.  If we cleaned *past*
6010                // that slot, then accounts could be removed from older storages, which would
6011                // change the accounts hash.
6012                self.rc.accounts.accounts_db.clean_accounts(
6013                    Some(latest_full_snapshot_slot),
6014                    true,
6015                    self.epoch_schedule(),
6016                    self.clean_accounts_old_storages_policy(),
6017                );
6018                info!("Cleaning... Done.");
6019            } else {
6020                info!("Cleaning... Skipped.");
6021            }
6022        });
6023
6024        let (_, shrink_time_us) = measure_us!({
6025            let should_shrink = !skip_shrink && self.slot() > 0;
6026            if should_shrink {
6027                info!("Shrinking...");
6028                self.rc.accounts.accounts_db.shrink_all_slots(
6029                    true,
6030                    self.epoch_schedule(),
6031                    // we cannot allow the snapshot slot to be shrunk
6032                    Some(self.slot()),
6033                );
6034                info!("Shrinking... Done.");
6035            } else {
6036                info!("Shrinking... Skipped.");
6037            }
6038        });
6039
6040        info!("Verifying bank...");
6041        let (verified_bank, verify_bank_time_us) = measure_us!(self.verify_hash());
6042        info!("Verifying bank... Done.");
6043
6044        datapoint_info!(
6045            "verify_snapshot_bank",
6046            ("clean_us", clean_time_us, i64),
6047            ("shrink_us", shrink_time_us, i64),
6048            ("verify_accounts_us", verify_accounts_time_us, i64),
6049            ("verify_bank_us", verify_bank_time_us, i64),
6050        );
6051
6052        verified_accounts && verified_bank
6053    }
6054
6055    /// Return the number of hashes per tick
6056    pub fn hashes_per_tick(&self) -> &Option<u64> {
6057        &self.hashes_per_tick
6058    }
6059
6060    /// Return the number of ticks per slot
6061    pub fn ticks_per_slot(&self) -> u64 {
6062        self.ticks_per_slot
6063    }
6064
6065    /// Return the number of slots per year
6066    pub fn slots_per_year(&self) -> f64 {
6067        self.slots_per_year
6068    }
6069
6070    /// Return the number of ticks since genesis.
6071    pub fn tick_height(&self) -> u64 {
6072        self.tick_height.load(Relaxed)
6073    }
6074
6075    /// Return the inflation parameters of the Bank
6076    pub fn inflation(&self) -> Inflation {
6077        *self.inflation.read().unwrap()
6078    }
6079
6080    /// Return the rent collector for this Bank
6081    pub fn rent_collector(&self) -> &RentCollector {
6082        &self.rent_collector
6083    }
6084
6085    /// Return the total capitalization of the Bank
6086    pub fn capitalization(&self) -> u64 {
6087        self.capitalization.load(Relaxed)
6088    }
6089
6090    /// Return this bank's max_tick_height
6091    pub fn max_tick_height(&self) -> u64 {
6092        self.max_tick_height
6093    }
6094
6095    /// Return the block_height of this bank
6096    pub fn block_height(&self) -> u64 {
6097        self.block_height
6098    }
6099
6100    /// Return the number of slots per epoch for the given epoch
6101    pub fn get_slots_in_epoch(&self, epoch: Epoch) -> u64 {
6102        self.epoch_schedule().get_slots_in_epoch(epoch)
6103    }
6104
6105    /// returns the epoch for which this bank's leader_schedule_slot_offset and slot would
6106    ///  need to cache leader_schedule
6107    pub fn get_leader_schedule_epoch(&self, slot: Slot) -> Epoch {
6108        self.epoch_schedule().get_leader_schedule_epoch(slot)
6109    }
6110
6111    /// a bank-level cache of vote accounts and stake delegation info
6112    fn update_stakes_cache(
6113        &self,
6114        txs: &[impl SVMMessage],
6115        processing_results: &[TransactionProcessingResult],
6116    ) {
6117        debug_assert_eq!(txs.len(), processing_results.len());
6118        let new_warmup_cooldown_rate_epoch = self.new_warmup_cooldown_rate_epoch();
6119        txs.iter()
6120            .zip(processing_results)
6121            .filter_map(|(tx, processing_result)| {
6122                processing_result
6123                    .processed_transaction()
6124                    .map(|processed_tx| (tx, processed_tx))
6125            })
6126            .filter_map(|(tx, processed_tx)| {
6127                processed_tx
6128                    .executed_transaction()
6129                    .map(|executed_tx| (tx, executed_tx))
6130            })
6131            .filter(|(_, executed_tx)| executed_tx.was_successful())
6132            .flat_map(|(tx, executed_tx)| {
6133                let num_account_keys = tx.account_keys().len();
6134                let loaded_tx = &executed_tx.loaded_transaction;
6135                loaded_tx.accounts.iter().take(num_account_keys)
6136            })
6137            .for_each(|(pubkey, account)| {
6138                // note that this could get timed to: self.rc.accounts.accounts_db.stats.stakes_cache_check_and_store_us,
6139                //  but this code path is captured separately in ExecuteTimingType::UpdateStakesCacheUs
6140                self.stakes_cache
6141                    .check_and_store(pubkey, account, new_warmup_cooldown_rate_epoch);
6142            });
6143    }
6144
6145    /// current vote accounts for this bank along with the stake
6146    ///   attributed to each account
6147    pub fn vote_accounts(&self) -> Arc<VoteAccountsHashMap> {
6148        let stakes = self.stakes_cache.stakes();
6149        Arc::from(stakes.vote_accounts())
6150    }
6151
6152    /// Vote account for the given vote account pubkey.
6153    pub fn get_vote_account(&self, vote_account: &Pubkey) -> Option<VoteAccount> {
6154        let stakes = self.stakes_cache.stakes();
6155        let vote_account = stakes.vote_accounts().get(vote_account)?;
6156        Some(vote_account.clone())
6157    }
6158
6159    /// Get the EpochStakes for the current Bank::epoch
6160    pub fn current_epoch_stakes(&self) -> &EpochStakes {
6161        // The stakes for a given epoch (E) in self.epoch_stakes are keyed by leader schedule epoch
6162        // (E + 1) so the stakes for the current epoch are stored at self.epoch_stakes[E + 1]
6163        self.epoch_stakes
6164            .get(&self.epoch.saturating_add(1))
6165            .expect("Current epoch stakes must exist")
6166    }
6167
6168    /// Get the EpochStakes for a given epoch
6169    pub fn epoch_stakes(&self, epoch: Epoch) -> Option<&EpochStakes> {
6170        self.epoch_stakes.get(&epoch)
6171    }
6172
6173    pub fn epoch_stakes_map(&self) -> &HashMap<Epoch, EpochStakes> {
6174        &self.epoch_stakes
6175    }
6176
6177    /// Get the staked nodes map for the current Bank::epoch
6178    pub fn current_epoch_staked_nodes(&self) -> Arc<HashMap<Pubkey, u64>> {
6179        self.current_epoch_stakes().stakes().staked_nodes()
6180    }
6181
6182    pub fn epoch_staked_nodes(&self, epoch: Epoch) -> Option<Arc<HashMap<Pubkey, u64>>> {
6183        Some(self.epoch_stakes.get(&epoch)?.stakes().staked_nodes())
6184    }
6185
6186    /// Get the total epoch stake for the given epoch.
6187    pub fn epoch_total_stake(&self, epoch: Epoch) -> Option<u64> {
6188        self.epoch_stakes
6189            .get(&epoch)
6190            .map(|epoch_stakes| epoch_stakes.total_stake())
6191    }
6192
6193    /// Get the total epoch stake for the current Bank::epoch
6194    pub fn get_current_epoch_total_stake(&self) -> u64 {
6195        self.current_epoch_stakes().total_stake()
6196    }
6197
6198    /// vote accounts for the specific epoch along with the stake
6199    ///   attributed to each account
6200    pub fn epoch_vote_accounts(&self, epoch: Epoch) -> Option<&VoteAccountsHashMap> {
6201        let epoch_stakes = self.epoch_stakes.get(&epoch)?.stakes();
6202        Some(epoch_stakes.vote_accounts().as_ref())
6203    }
6204
6205    /// Get the vote accounts along with the stake attributed to each account
6206    /// for the current Bank::epoch
6207    pub fn get_current_epoch_vote_accounts(&self) -> &VoteAccountsHashMap {
6208        self.current_epoch_stakes()
6209            .stakes()
6210            .vote_accounts()
6211            .as_ref()
6212    }
6213
6214    /// Get the fixed authorized voter for the given vote account for the
6215    /// current epoch
6216    pub fn epoch_authorized_voter(&self, vote_account: &Pubkey) -> Option<&Pubkey> {
6217        self.epoch_stakes
6218            .get(&self.epoch)
6219            .expect("Epoch stakes for bank's own epoch must exist")
6220            .epoch_authorized_voters()
6221            .get(vote_account)
6222    }
6223
6224    /// Get the fixed set of vote accounts for the given node id for the
6225    /// current epoch
6226    pub fn epoch_vote_accounts_for_node_id(&self, node_id: &Pubkey) -> Option<&NodeVoteAccounts> {
6227        self.epoch_stakes
6228            .get(&self.epoch)
6229            .expect("Epoch stakes for bank's own epoch must exist")
6230            .node_id_to_vote_accounts()
6231            .get(node_id)
6232    }
6233
6234    /// Get the total stake belonging to vote accounts associated with the given node id for the
6235    /// given epoch.
6236    pub fn epoch_node_id_to_stake(&self, epoch: Epoch, node_id: &Pubkey) -> Option<u64> {
6237        self.epoch_stakes(epoch)
6238            .and_then(|epoch_stakes| epoch_stakes.node_id_to_stake(node_id))
6239    }
6240
6241    /// Get the fixed total stake of all vote accounts for current epoch
6242    pub fn total_epoch_stake(&self) -> u64 {
6243        self.epoch_stakes
6244            .get(&self.epoch)
6245            .expect("Epoch stakes for bank's own epoch must exist")
6246            .total_stake()
6247    }
6248
6249    /// Get the fixed stake of the given vote account for the current epoch
6250    pub fn epoch_vote_account_stake(&self, vote_account: &Pubkey) -> u64 {
6251        *self
6252            .epoch_vote_accounts(self.epoch())
6253            .expect("Bank epoch vote accounts must contain entry for the bank's own epoch")
6254            .get(vote_account)
6255            .map(|(stake, _)| stake)
6256            .unwrap_or(&0)
6257    }
6258
6259    /// given a slot, return the epoch and offset into the epoch this slot falls
6260    /// e.g. with a fixed number for slots_per_epoch, the calculation is simply:
6261    ///
6262    ///  ( slot/slots_per_epoch, slot % slots_per_epoch )
6263    ///
6264    pub fn get_epoch_and_slot_index(&self, slot: Slot) -> (Epoch, SlotIndex) {
6265        self.epoch_schedule().get_epoch_and_slot_index(slot)
6266    }
6267
6268    pub fn get_epoch_info(&self) -> EpochInfo {
6269        let absolute_slot = self.slot();
6270        let block_height = self.block_height();
6271        let (epoch, slot_index) = self.get_epoch_and_slot_index(absolute_slot);
6272        let slots_in_epoch = self.get_slots_in_epoch(epoch);
6273        let transaction_count = Some(self.transaction_count());
6274        EpochInfo {
6275            epoch,
6276            slot_index,
6277            slots_in_epoch,
6278            absolute_slot,
6279            block_height,
6280            transaction_count,
6281        }
6282    }
6283
6284    pub fn is_empty(&self) -> bool {
6285        !self.is_delta.load(Relaxed)
6286    }
6287
6288    pub fn add_mockup_builtin(
6289        &mut self,
6290        program_id: Pubkey,
6291        builtin_function: BuiltinFunctionWithContext,
6292    ) {
6293        self.transaction_processor.add_builtin(
6294            self,
6295            program_id,
6296            "mockup",
6297            ProgramCacheEntry::new_builtin(self.slot, 0, builtin_function),
6298        );
6299    }
6300
6301    pub fn add_precompile(&mut self, program_id: &Pubkey) {
6302        debug!("Adding precompiled program {}", program_id);
6303        self.add_precompiled_account(program_id);
6304        debug!("Added precompiled program {:?}", program_id);
6305    }
6306
6307    // Call AccountsDb::clean_accounts()
6308    //
6309    // This fn is meant to be called by the snapshot handler in Accounts Background Service.  If
6310    // calling from elsewhere, ensure the same invariants hold/expectations are met.
6311    pub(crate) fn clean_accounts(&self) {
6312        // Don't clean the slot we're snapshotting because it may have zero-lamport
6313        // accounts that were included in the bank delta hash when the bank was frozen,
6314        // and if we clean them here, any newly created snapshot's hash for this bank
6315        // may not match the frozen hash.
6316        //
6317        // So when we're snapshotting, the highest slot to clean is lowered by one.
6318        let highest_slot_to_clean = self.slot().saturating_sub(1);
6319
6320        self.rc.accounts.accounts_db.clean_accounts(
6321            Some(highest_slot_to_clean),
6322            false,
6323            self.epoch_schedule(),
6324            self.clean_accounts_old_storages_policy(),
6325        );
6326    }
6327
6328    pub fn print_accounts_stats(&self) {
6329        self.rc.accounts.accounts_db.print_accounts_stats("");
6330    }
6331
6332    pub fn shrink_candidate_slots(&self) -> usize {
6333        self.rc
6334            .accounts
6335            .accounts_db
6336            .shrink_candidate_slots(self.epoch_schedule())
6337    }
6338
6339    pub(crate) fn shrink_ancient_slots(&self) {
6340        // Invoke ancient slot shrinking only when the validator is
6341        // explicitly configured to do so. This condition may be
6342        // removed when the skip rewrites feature is enabled.
6343        if self.are_ancient_storages_enabled() {
6344            self.rc
6345                .accounts
6346                .accounts_db
6347                .shrink_ancient_slots(self.epoch_schedule())
6348        }
6349    }
6350
6351    /// Returns if ancient storages are enabled or not
6352    pub fn are_ancient_storages_enabled(&self) -> bool {
6353        let can_skip_rewrites = self.bank_hash_skips_rent_rewrites();
6354        let test_skip_rewrites_but_include_in_bank_hash = self
6355            .rc
6356            .accounts
6357            .accounts_db
6358            .test_skip_rewrites_but_include_in_bank_hash;
6359        can_skip_rewrites || test_skip_rewrites_but_include_in_bank_hash
6360    }
6361
6362    /// Returns how clean_accounts() should handle old storages
6363    fn clean_accounts_old_storages_policy(&self) -> OldStoragesPolicy {
6364        if self.are_ancient_storages_enabled() {
6365            OldStoragesPolicy::Leave
6366        } else {
6367            OldStoragesPolicy::Clean
6368        }
6369    }
6370
6371    pub fn read_cost_tracker(&self) -> LockResult<RwLockReadGuard<CostTracker>> {
6372        self.cost_tracker.read()
6373    }
6374
6375    pub fn write_cost_tracker(&self) -> LockResult<RwLockWriteGuard<CostTracker>> {
6376        self.cost_tracker.write()
6377    }
6378
6379    // Check if the wallclock time from bank creation to now has exceeded the allotted
6380    // time for transaction processing
6381    pub fn should_bank_still_be_processing_txs(
6382        bank_creation_time: &Instant,
6383        max_tx_ingestion_nanos: u128,
6384    ) -> bool {
6385        // Do this check outside of the PoH lock, hence not a method on PohRecorder
6386        bank_creation_time.elapsed().as_nanos() <= max_tx_ingestion_nanos
6387    }
6388
6389    pub fn deactivate_feature(&mut self, id: &Pubkey) {
6390        let mut feature_set = Arc::make_mut(&mut self.feature_set).clone();
6391        feature_set.active_mut().remove(id);
6392        feature_set.inactive_mut().insert(*id);
6393        self.feature_set = Arc::new(feature_set);
6394    }
6395
6396    pub fn activate_feature(&mut self, id: &Pubkey) {
6397        let mut feature_set = Arc::make_mut(&mut self.feature_set).clone();
6398        feature_set.inactive_mut().remove(id);
6399        feature_set.active_mut().insert(*id, 0);
6400        self.feature_set = Arc::new(feature_set);
6401    }
6402
6403    pub fn fill_bank_with_ticks_for_tests(&self) {
6404        self.do_fill_bank_with_ticks_for_tests(&BankWithScheduler::no_scheduler_available())
6405    }
6406
6407    pub(crate) fn do_fill_bank_with_ticks_for_tests(&self, scheduler: &InstalledSchedulerRwLock) {
6408        if self.tick_height.load(Relaxed) < self.max_tick_height {
6409            let last_blockhash = self.last_blockhash();
6410            while self.last_blockhash() == last_blockhash {
6411                self.register_tick(&Hash::new_unique(), scheduler)
6412            }
6413        } else {
6414            warn!("Bank already reached max tick height, cannot fill it with more ticks");
6415        }
6416    }
6417
6418    /// Get a set of all actively reserved account keys that are not allowed to
6419    /// be write-locked during transaction processing.
6420    pub fn get_reserved_account_keys(&self) -> &HashSet<Pubkey> {
6421        &self.reserved_account_keys.active
6422    }
6423
6424    // This is called from snapshot restore AND for each epoch boundary
6425    // The entire code path herein must be idempotent
6426    fn apply_feature_activations(
6427        &mut self,
6428        caller: ApplyFeatureActivationsCaller,
6429        debug_do_not_add_builtins: bool,
6430    ) {
6431        use ApplyFeatureActivationsCaller as Caller;
6432        let allow_new_activations = match caller {
6433            Caller::FinishInit => false,
6434            Caller::NewFromParent => true,
6435            Caller::WarpFromParent => false,
6436        };
6437        let (feature_set, new_feature_activations) =
6438            self.compute_active_feature_set(allow_new_activations);
6439        self.feature_set = Arc::new(feature_set);
6440
6441        // Update activation slot of features in `new_feature_activations`
6442        for feature_id in new_feature_activations.iter() {
6443            if let Some(mut account) = self.get_account_with_fixed_root(feature_id) {
6444                if let Some(mut feature) = feature::from_account(&account) {
6445                    feature.activated_at = Some(self.slot());
6446                    if feature::to_account(&feature, &mut account).is_some() {
6447                        self.store_account(feature_id, &account);
6448                    }
6449                    info!("Feature {} activated at slot {}", feature_id, self.slot());
6450                }
6451            }
6452        }
6453
6454        // Update active set of reserved account keys which are not allowed to be write locked
6455        self.reserved_account_keys = {
6456            let mut reserved_keys = ReservedAccountKeys::clone(&self.reserved_account_keys);
6457            reserved_keys.update_active_set(&self.feature_set);
6458            Arc::new(reserved_keys)
6459        };
6460
6461        if new_feature_activations.contains(&feature_set::pico_inflation::id()) {
6462            *self.inflation.write().unwrap() = Inflation::pico();
6463            self.fee_rate_governor.burn_percent = 50; // 50% fee burn
6464            self.rent_collector.rent.burn_percent = 50; // 50% rent burn
6465        }
6466
6467        if !new_feature_activations.is_disjoint(&self.feature_set.full_inflation_features_enabled())
6468        {
6469            *self.inflation.write().unwrap() = Inflation::full();
6470            self.fee_rate_governor.burn_percent = 50; // 50% fee burn
6471            self.rent_collector.rent.burn_percent = 50; // 50% rent burn
6472        }
6473
6474        if !debug_do_not_add_builtins {
6475            self.apply_builtin_program_feature_transitions(
6476                allow_new_activations,
6477                &new_feature_activations,
6478            );
6479        }
6480
6481        if new_feature_activations.contains(&feature_set::update_hashes_per_tick::id()) {
6482            self.apply_updated_hashes_per_tick(DEFAULT_HASHES_PER_TICK);
6483        }
6484
6485        if new_feature_activations.contains(&feature_set::update_hashes_per_tick2::id()) {
6486            self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK2);
6487        }
6488
6489        if new_feature_activations.contains(&feature_set::update_hashes_per_tick3::id()) {
6490            self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK3);
6491        }
6492
6493        if new_feature_activations.contains(&feature_set::update_hashes_per_tick4::id()) {
6494            self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK4);
6495        }
6496
6497        if new_feature_activations.contains(&feature_set::update_hashes_per_tick5::id()) {
6498            self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK5);
6499        }
6500
6501        if new_feature_activations.contains(&feature_set::update_hashes_per_tick6::id()) {
6502            self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK6);
6503        }
6504
6505        if new_feature_activations.contains(&feature_set::accounts_lt_hash::id()) {
6506            // Activating the accounts lt hash feature means we need to have an accounts lt hash
6507            // value at the end of this if-block.  If the cli arg has been used, that means we
6508            // already have an accounts lt hash and do not need to recalculate it.
6509            if self
6510                .rc
6511                .accounts
6512                .accounts_db
6513                .is_experimental_accumulator_hash_enabled()
6514            {
6515                // We already have an accounts lt hash value, so no need to recalculate it.
6516                // Nothing else to do here.
6517            } else {
6518                let parent_slot = self.parent_slot;
6519                info!(
6520                    "Calculating the accounts lt hash for slot {parent_slot} \
6521                     as part of feature activation; this may take some time...",
6522                );
6523                // We must calculate the accounts lt hash now as part of feature activation.
6524                // Note, this bank is *not* frozen yet, which means it will later call
6525                // `update_accounts_lt_hash()`.  Therefore, we calculate the accounts lt hash based
6526                // on *our parent*, not us!
6527                let parent_ancestors = {
6528                    let mut ancestors = self.ancestors.clone();
6529                    ancestors.remove(&self.slot());
6530                    ancestors
6531                };
6532                let (parent_accounts_lt_hash, duration) = meas_dur!({
6533                    self.rc
6534                        .accounts
6535                        .accounts_db
6536                        .calculate_accounts_lt_hash_at_startup_from_index(
6537                            &parent_ancestors,
6538                            parent_slot,
6539                        )
6540                });
6541                *self.accounts_lt_hash.get_mut().unwrap() = parent_accounts_lt_hash;
6542                info!(
6543                    "Calculating the accounts lt hash for slot {parent_slot} \
6544                     completed in {duration:?}, accounts_lt_hash checksum: {}",
6545                    self.accounts_lt_hash.get_mut().unwrap().0.checksum(),
6546                );
6547            }
6548        }
6549
6550        if new_feature_activations.contains(&feature_set::raise_block_limits_to_50m::id()) {
6551            let (account_cost_limit, block_cost_limit, vote_cost_limit) = simd_0207_block_limits();
6552            self.write_cost_tracker().unwrap().set_limits(
6553                account_cost_limit,
6554                block_cost_limit,
6555                vote_cost_limit,
6556            );
6557        }
6558
6559        if new_feature_activations.contains(&feature_set::remove_accounts_delta_hash::id()) {
6560            // If the accounts delta hash has been removed, then we no longer need to compute the
6561            // AccountHash for modified accounts, and can stop the background account hasher.
6562            self.rc.accounts.accounts_db.stop_background_hasher();
6563        }
6564    }
6565
6566    fn apply_updated_hashes_per_tick(&mut self, hashes_per_tick: u64) {
6567        info!(
6568            "Activating update_hashes_per_tick {} at slot {}",
6569            hashes_per_tick,
6570            self.slot(),
6571        );
6572        self.hashes_per_tick = Some(hashes_per_tick);
6573    }
6574
6575    fn adjust_sysvar_balance_for_rent(&self, account: &mut AccountSharedData) {
6576        account.set_lamports(
6577            self.get_minimum_balance_for_rent_exemption(account.data().len())
6578                .max(account.lamports()),
6579        );
6580    }
6581
6582    /// Compute the active feature set based on the current bank state,
6583    /// and return it together with the set of newly activated features.
6584    fn compute_active_feature_set(&self, include_pending: bool) -> (FeatureSet, AHashSet<Pubkey>) {
6585        let mut active = self.feature_set.active().clone();
6586        let mut inactive = AHashSet::new();
6587        let mut pending = AHashSet::new();
6588        let slot = self.slot();
6589
6590        for feature_id in self.feature_set.inactive() {
6591            let mut activated = None;
6592            if let Some(account) = self.get_account_with_fixed_root(feature_id) {
6593                if let Some(feature) = feature::from_account(&account) {
6594                    match feature.activated_at {
6595                        None if include_pending => {
6596                            // Feature activation is pending
6597                            pending.insert(*feature_id);
6598                            activated = Some(slot);
6599                        }
6600                        Some(activation_slot) if slot >= activation_slot => {
6601                            // Feature has been activated already
6602                            activated = Some(activation_slot);
6603                        }
6604                        _ => {}
6605                    }
6606                }
6607            }
6608            if let Some(slot) = activated {
6609                active.insert(*feature_id, slot);
6610            } else {
6611                inactive.insert(*feature_id);
6612            }
6613        }
6614
6615        (FeatureSet::new(active, inactive), pending)
6616    }
6617
6618    fn apply_builtin_program_feature_transitions(
6619        &mut self,
6620        only_apply_transitions_for_new_features: bool,
6621        new_feature_activations: &AHashSet<Pubkey>,
6622    ) {
6623        for builtin in BUILTINS.iter() {
6624            // The `builtin_is_bpf` flag is used to handle the case where a
6625            // builtin is scheduled to be enabled by one feature gate and
6626            // later migrated to Core BPF by another.
6627            //
6628            // There should never be a case where a builtin is set to be
6629            // migrated to Core BPF and is also set to be enabled on feature
6630            // activation on the same feature gate. However, the
6631            // `builtin_is_bpf` flag will handle this case as well, electing
6632            // to first attempt the migration to Core BPF.
6633            //
6634            // The migration to Core BPF will fail gracefully because the
6635            // program account will not exist. The builtin will subsequently
6636            // be enabled, but it will never be migrated to Core BPF.
6637            //
6638            // Using the same feature gate for both enabling and migrating a
6639            // builtin to Core BPF should be strictly avoided.
6640            let mut builtin_is_bpf = false;
6641            if let Some(core_bpf_migration_config) = &builtin.core_bpf_migration_config {
6642                // If the builtin is set to be migrated to Core BPF on feature
6643                // activation, perform the migration and do not add the program
6644                // to the bank's builtins. The migration will remove it from
6645                // the builtins list and the cache.
6646                if new_feature_activations.contains(&core_bpf_migration_config.feature_id) {
6647                    if let Err(e) = self
6648                        .migrate_builtin_to_core_bpf(&builtin.program_id, core_bpf_migration_config)
6649                    {
6650                        warn!(
6651                            "Failed to migrate builtin {} to Core BPF: {}",
6652                            builtin.name, e
6653                        );
6654                    } else {
6655                        builtin_is_bpf = true;
6656                    }
6657                } else {
6658                    // If the builtin has already been migrated to Core BPF, do not
6659                    // add it to the bank's builtins.
6660                    builtin_is_bpf = self
6661                        .get_account(&builtin.program_id)
6662                        .map(|a| a.owner() == &bpf_loader_upgradeable::id())
6663                        .unwrap_or(false);
6664                }
6665            };
6666
6667            if let Some(feature_id) = builtin.enable_feature_id {
6668                let should_enable_builtin_on_feature_transition = !builtin_is_bpf
6669                    && if only_apply_transitions_for_new_features {
6670                        new_feature_activations.contains(&feature_id)
6671                    } else {
6672                        self.feature_set.is_active(&feature_id)
6673                    };
6674
6675                if should_enable_builtin_on_feature_transition {
6676                    self.transaction_processor.add_builtin(
6677                        self,
6678                        builtin.program_id,
6679                        builtin.name,
6680                        ProgramCacheEntry::new_builtin(
6681                            self.feature_set.activated_slot(&feature_id).unwrap_or(0),
6682                            builtin.name.len(),
6683                            builtin.entrypoint,
6684                        ),
6685                    );
6686                }
6687            }
6688        }
6689
6690        // Migrate any necessary stateless builtins to core BPF.
6691        // Stateless builtins do not have an `enable_feature_id` since they
6692        // do not exist on-chain.
6693        for stateless_builtin in STATELESS_BUILTINS.iter() {
6694            if let Some(core_bpf_migration_config) = &stateless_builtin.core_bpf_migration_config {
6695                if new_feature_activations.contains(&core_bpf_migration_config.feature_id) {
6696                    if let Err(e) = self.migrate_builtin_to_core_bpf(
6697                        &stateless_builtin.program_id,
6698                        core_bpf_migration_config,
6699                    ) {
6700                        warn!(
6701                            "Failed to migrate stateless builtin {} to Core BPF: {}",
6702                            stateless_builtin.name, e
6703                        );
6704                    }
6705                }
6706            }
6707        }
6708
6709        for precompile in get_precompiles() {
6710            let should_add_precompile = precompile
6711                .feature
6712                .as_ref()
6713                .map(|feature_id| self.feature_set.is_active(feature_id))
6714                .unwrap_or(false);
6715            if should_add_precompile {
6716                self.add_precompile(&precompile.program_id);
6717            }
6718        }
6719    }
6720
6721    /// Use to replace programs by feature activation
6722    #[allow(dead_code)]
6723    fn replace_program_account(
6724        &mut self,
6725        old_address: &Pubkey,
6726        new_address: &Pubkey,
6727        datapoint_name: &'static str,
6728    ) {
6729        if let Some(old_account) = self.get_account_with_fixed_root(old_address) {
6730            if let Some(new_account) = self.get_account_with_fixed_root(new_address) {
6731                datapoint_info!(datapoint_name, ("slot", self.slot, i64));
6732
6733                // Burn lamports in the old account
6734                self.capitalization
6735                    .fetch_sub(old_account.lamports(), Relaxed);
6736
6737                // Transfer new account to old account
6738                self.store_account(old_address, &new_account);
6739
6740                // Clear new account
6741                self.store_account(new_address, &AccountSharedData::default());
6742
6743                // Unload a program from the bank's cache
6744                self.transaction_processor
6745                    .program_cache
6746                    .write()
6747                    .unwrap()
6748                    .remove_programs([*old_address].into_iter());
6749
6750                self.calculate_and_update_accounts_data_size_delta_off_chain(
6751                    old_account.data().len(),
6752                    new_account.data().len(),
6753                );
6754            }
6755        }
6756    }
6757
6758    /// Get all the accounts for this bank and calculate stats
6759    pub fn get_total_accounts_stats(&self) -> ScanResult<TotalAccountsStats> {
6760        let accounts = self.get_all_accounts(false)?;
6761        Ok(self.calculate_total_accounts_stats(
6762            accounts
6763                .iter()
6764                .map(|(pubkey, account, _slot)| (pubkey, account)),
6765        ))
6766    }
6767
6768    /// Given all the accounts for a bank, calculate stats
6769    pub fn calculate_total_accounts_stats<'a>(
6770        &self,
6771        accounts: impl Iterator<Item = (&'a Pubkey, &'a AccountSharedData)>,
6772    ) -> TotalAccountsStats {
6773        let rent_collector = self.rent_collector();
6774        let mut total_accounts_stats = TotalAccountsStats::default();
6775        accounts.for_each(|(pubkey, account)| {
6776            total_accounts_stats.accumulate_account(pubkey, account, rent_collector);
6777        });
6778
6779        total_accounts_stats
6780    }
6781
6782    /// Get the EAH that will be used by snapshots
6783    ///
6784    /// Since snapshots are taken on roots, if the bank is in the EAH calculation window then an
6785    /// EAH *must* be included.  This means if an EAH calculation is currently in-flight we will
6786    /// wait for it to complete.
6787    pub fn get_epoch_accounts_hash_to_serialize(&self) -> Option<EpochAccountsHash> {
6788        let should_get_epoch_accounts_hash = epoch_accounts_hash_utils::is_enabled_this_epoch(self)
6789            && epoch_accounts_hash_utils::is_in_calculation_window(self);
6790        if !should_get_epoch_accounts_hash {
6791            return None;
6792        }
6793
6794        let (epoch_accounts_hash, waiting_time_us) = measure_us!(self
6795            .rc
6796            .accounts
6797            .accounts_db
6798            .epoch_accounts_hash_manager
6799            .wait_get_epoch_accounts_hash());
6800
6801        datapoint_info!(
6802            "bank-get_epoch_accounts_hash_to_serialize",
6803            ("slot", self.slot(), i64),
6804            ("waiting-time-us", waiting_time_us, i64),
6805        );
6806        Some(epoch_accounts_hash)
6807    }
6808
6809    /// Convenience fn to get the Epoch Accounts Hash
6810    pub fn epoch_accounts_hash(&self) -> Option<EpochAccountsHash> {
6811        self.rc
6812            .accounts
6813            .accounts_db
6814            .epoch_accounts_hash_manager
6815            .try_get_epoch_accounts_hash()
6816    }
6817
6818    pub fn is_in_slot_hashes_history(&self, slot: &Slot) -> bool {
6819        if slot < &self.slot {
6820            if let Ok(slot_hashes) = self.transaction_processor.sysvar_cache().get_slot_hashes() {
6821                return slot_hashes.get(slot).is_some();
6822            }
6823        }
6824        false
6825    }
6826
6827    pub fn check_program_modification_slot(&self) -> bool {
6828        self.check_program_modification_slot
6829    }
6830
6831    pub fn set_check_program_modification_slot(&mut self, check: bool) {
6832        self.check_program_modification_slot = check;
6833    }
6834
6835    pub fn fee_structure(&self) -> &FeeStructure {
6836        &self.fee_structure
6837    }
6838
6839    pub fn block_id(&self) -> Option<Hash> {
6840        *self.block_id.read().unwrap()
6841    }
6842
6843    pub fn set_block_id(&self, block_id: Option<Hash>) {
6844        *self.block_id.write().unwrap() = block_id;
6845    }
6846
6847    pub fn compute_budget(&self) -> Option<ComputeBudget> {
6848        self.compute_budget
6849    }
6850
6851    pub fn add_builtin(&self, program_id: Pubkey, name: &str, builtin: ProgramCacheEntry) {
6852        self.transaction_processor
6853            .add_builtin(self, program_id, name, builtin)
6854    }
6855
6856    pub fn get_bank_hash_stats(&self) -> BankHashStats {
6857        self.bank_hash_stats.load()
6858    }
6859}
6860
6861impl TransactionProcessingCallback for Bank {
6862    fn account_matches_owners(&self, account: &Pubkey, owners: &[Pubkey]) -> Option<usize> {
6863        self.rc
6864            .accounts
6865            .accounts_db
6866            .account_matches_owners(&self.ancestors, account, owners)
6867            .ok()
6868    }
6869
6870    fn get_account_shared_data(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
6871        self.rc
6872            .accounts
6873            .accounts_db
6874            .load_with_fixed_root(&self.ancestors, pubkey)
6875            .map(|(acc, _)| acc)
6876    }
6877
6878    // NOTE: must hold idempotent for the same set of arguments
6879    /// Add a builtin program account
6880    fn add_builtin_account(&self, name: &str, program_id: &Pubkey) {
6881        let existing_genuine_program =
6882            self.get_account_with_fixed_root(program_id)
6883                .and_then(|account| {
6884                    // it's very unlikely to be squatted at program_id as non-system account because of burden to
6885                    // find victim's pubkey/hash. So, when account.owner is indeed native_loader's, it's
6886                    // safe to assume it's a genuine program.
6887                    if native_loader::check_id(account.owner()) {
6888                        Some(account)
6889                    } else {
6890                        // malicious account is pre-occupying at program_id
6891                        self.burn_and_purge_account(program_id, account);
6892                        None
6893                    }
6894                });
6895
6896        // introducing builtin program
6897        if existing_genuine_program.is_some() {
6898            // The existing account is sufficient
6899            return;
6900        }
6901
6902        assert!(
6903            !self.freeze_started(),
6904            "Can't change frozen bank by adding not-existing new builtin program ({name}, {program_id}). \
6905            Maybe, inconsistent program activation is detected on snapshot restore?"
6906        );
6907
6908        // Add a bogus executable builtin account, which will be loaded and ignored.
6909        let account = native_loader::create_loadable_account_with_fields(
6910            name,
6911            self.inherit_specially_retained_account_fields(&existing_genuine_program),
6912        );
6913        self.store_account_and_update_capitalization(program_id, &account);
6914    }
6915
6916    fn inspect_account(&self, address: &Pubkey, account_state: AccountState, is_writable: bool) {
6917        if self.is_accounts_lt_hash_enabled() {
6918            self.inspect_account_for_accounts_lt_hash(address, &account_state, is_writable);
6919        }
6920    }
6921
6922    fn get_current_epoch_vote_account_stake(&self, vote_address: &Pubkey) -> u64 {
6923        self.get_current_epoch_vote_accounts()
6924            .get(vote_address)
6925            .map(|(stake, _)| (*stake))
6926            .unwrap_or(0)
6927    }
6928
6929    fn calculate_fee(
6930        &self,
6931        message: &impl SVMMessage,
6932        lamports_per_signature: u64,
6933        prioritization_fee: u64,
6934        feature_set: &FeatureSet,
6935    ) -> FeeDetails {
6936        solana_fee::calculate_fee_details(
6937            message,
6938            false, /* zero_fees_for_test */
6939            lamports_per_signature,
6940            prioritization_fee,
6941            FeeFeatures::from(feature_set),
6942        )
6943    }
6944}
6945
6946#[cfg(feature = "dev-context-only-utils")]
6947impl Bank {
6948    pub fn wrap_with_bank_forks_for_tests(self) -> (Arc<Self>, Arc<RwLock<BankForks>>) {
6949        let bank_forks = BankForks::new_rw_arc(self);
6950        let bank = bank_forks.read().unwrap().root_bank();
6951        (bank, bank_forks)
6952    }
6953
6954    pub fn default_for_tests() -> Self {
6955        let accounts_db = AccountsDb::default_for_tests();
6956        let accounts = Accounts::new(Arc::new(accounts_db));
6957        Self::default_with_accounts(accounts)
6958    }
6959
6960    pub fn new_with_bank_forks_for_tests(
6961        genesis_config: &GenesisConfig,
6962    ) -> (Arc<Self>, Arc<RwLock<BankForks>>) {
6963        let bank = Self::new_for_tests(genesis_config);
6964        bank.wrap_with_bank_forks_for_tests()
6965    }
6966
6967    pub fn new_for_tests(genesis_config: &GenesisConfig) -> Self {
6968        Self::new_with_config_for_tests(genesis_config, BankTestConfig::default())
6969    }
6970
6971    pub fn new_with_mockup_builtin_for_tests(
6972        genesis_config: &GenesisConfig,
6973        program_id: Pubkey,
6974        builtin_function: BuiltinFunctionWithContext,
6975    ) -> (Arc<Self>, Arc<RwLock<BankForks>>) {
6976        let mut bank = Self::new_for_tests(genesis_config);
6977        bank.add_mockup_builtin(program_id, builtin_function);
6978        bank.wrap_with_bank_forks_for_tests()
6979    }
6980
6981    pub fn new_no_wallclock_throttle_for_tests(
6982        genesis_config: &GenesisConfig,
6983    ) -> (Arc<Self>, Arc<RwLock<BankForks>>) {
6984        let mut bank = Self::new_for_tests(genesis_config);
6985
6986        bank.ns_per_slot = u128::MAX;
6987        bank.wrap_with_bank_forks_for_tests()
6988    }
6989
6990    pub fn new_with_config_for_tests(
6991        genesis_config: &GenesisConfig,
6992        test_config: BankTestConfig,
6993    ) -> Self {
6994        Self::new_with_paths_for_tests(
6995            genesis_config,
6996            Arc::new(RuntimeConfig::default()),
6997            test_config,
6998            Vec::new(),
6999        )
7000    }
7001
7002    pub fn new_with_paths_for_tests(
7003        genesis_config: &GenesisConfig,
7004        runtime_config: Arc<RuntimeConfig>,
7005        test_config: BankTestConfig,
7006        paths: Vec<PathBuf>,
7007    ) -> Self {
7008        Self::new_with_paths(
7009            genesis_config,
7010            runtime_config,
7011            paths,
7012            None,
7013            None,
7014            false,
7015            Some(test_config.accounts_db_config),
7016            None,
7017            Some(Pubkey::new_unique()),
7018            Arc::default(),
7019            None,
7020            None,
7021        )
7022    }
7023
7024    pub fn new_for_benches(genesis_config: &GenesisConfig) -> Self {
7025        Self::new_with_paths_for_benches(genesis_config, Vec::new())
7026    }
7027
7028    /// Intended for use by benches only.
7029    /// create new bank with the given config and paths.
7030    pub fn new_with_paths_for_benches(genesis_config: &GenesisConfig, paths: Vec<PathBuf>) -> Self {
7031        Self::new_with_paths(
7032            genesis_config,
7033            Arc::<RuntimeConfig>::default(),
7034            paths,
7035            None,
7036            None,
7037            false,
7038            Some(ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS),
7039            None,
7040            Some(Pubkey::new_unique()),
7041            Arc::default(),
7042            None,
7043            None,
7044        )
7045    }
7046
7047    /// Prepare a transaction batch from a list of legacy transactions. Used for tests only.
7048    #[cfg(feature = "dev-context-only-utils")]
7049    pub fn prepare_batch_for_tests(
7050        &self,
7051        txs: Vec<Transaction>,
7052    ) -> TransactionBatch<RuntimeTransaction<SanitizedTransaction>> {
7053        let transaction_account_lock_limit = self.get_transaction_account_lock_limit();
7054        let sanitized_txs = txs
7055            .into_iter()
7056            .map(RuntimeTransaction::from_transaction_for_tests)
7057            .collect::<Vec<_>>();
7058        let lock_results = self
7059            .rc
7060            .accounts
7061            .lock_accounts(sanitized_txs.iter(), transaction_account_lock_limit);
7062        TransactionBatch::new(lock_results, self, OwnedOrBorrowed::Owned(sanitized_txs))
7063    }
7064
7065    /// Set the initial accounts data size
7066    /// NOTE: This fn is *ONLY FOR TESTS*
7067    pub fn set_accounts_data_size_initial_for_tests(&mut self, amount: u64) {
7068        self.accounts_data_size_initial = amount;
7069    }
7070
7071    /// Update the accounts data size off-chain delta
7072    /// NOTE: This fn is *ONLY FOR TESTS*
7073    pub fn update_accounts_data_size_delta_off_chain_for_tests(&self, amount: i64) {
7074        self.update_accounts_data_size_delta_off_chain(amount)
7075    }
7076
7077    #[cfg(test)]
7078    fn restore_old_behavior_for_fragile_tests(&self) {
7079        self.lazy_rent_collection.store(true, Relaxed);
7080    }
7081
7082    /// Process multiple transaction in a single batch. This is used for benches and unit tests.
7083    ///
7084    /// # Panics
7085    ///
7086    /// Panics if any of the transactions do not pass sanitization checks.
7087    #[must_use]
7088    pub fn process_transactions<'a>(
7089        &self,
7090        txs: impl Iterator<Item = &'a Transaction>,
7091    ) -> Vec<Result<()>> {
7092        self.try_process_transactions(txs).unwrap()
7093    }
7094
7095    /// Process entry transactions in a single batch. This is used for benches and unit tests.
7096    ///
7097    /// # Panics
7098    ///
7099    /// Panics if any of the transactions do not pass sanitization checks.
7100    #[must_use]
7101    pub fn process_entry_transactions(&self, txs: Vec<VersionedTransaction>) -> Vec<Result<()>> {
7102        self.try_process_entry_transactions(txs).unwrap()
7103    }
7104
7105    #[cfg(test)]
7106    pub fn flush_accounts_cache_slot_for_tests(&self) {
7107        self.rc
7108            .accounts
7109            .accounts_db
7110            .flush_accounts_cache_slot_for_tests(self.slot())
7111    }
7112
7113    /// This is only valid to call from tests.
7114    /// block until initial accounts hash verification has completed
7115    pub fn wait_for_initial_accounts_hash_verification_completed_for_tests(&self) {
7116        self.rc
7117            .accounts
7118            .accounts_db
7119            .verify_accounts_hash_in_bg
7120            .join_background_thread()
7121    }
7122
7123    pub fn get_sysvar_cache_for_tests(&self) -> SysvarCache {
7124        self.transaction_processor.get_sysvar_cache_for_tests()
7125    }
7126
7127    pub fn update_accounts_hash_for_tests(&self) -> AccountsHash {
7128        self.update_accounts_hash(CalcAccountsHashDataSource::IndexForTests, false, false)
7129    }
7130
7131    pub fn new_program_cache_for_tx_batch_for_slot(&self, slot: Slot) -> ProgramCacheForTxBatch {
7132        ProgramCacheForTxBatch::new_from_cache(
7133            slot,
7134            self.epoch_schedule.get_epoch(slot),
7135            &self.transaction_processor.program_cache.read().unwrap(),
7136        )
7137    }
7138
7139    pub fn get_transaction_processor(&self) -> &TransactionBatchProcessor<BankForks> {
7140        &self.transaction_processor
7141    }
7142
7143    pub fn set_fee_structure(&mut self, fee_structure: &FeeStructure) {
7144        self.fee_structure = fee_structure.clone();
7145    }
7146
7147    pub fn load_program(
7148        &self,
7149        pubkey: &Pubkey,
7150        reload: bool,
7151        effective_epoch: Epoch,
7152    ) -> Option<Arc<ProgramCacheEntry>> {
7153        let environments = self
7154            .transaction_processor
7155            .get_environments_for_epoch(effective_epoch)?;
7156        load_program_with_pubkey(
7157            self,
7158            &environments,
7159            pubkey,
7160            self.slot(),
7161            &mut ExecuteTimings::default(), // Called by ledger-tool, metrics not accumulated.
7162            reload,
7163        )
7164    }
7165
7166    pub fn withdraw(&self, pubkey: &Pubkey, lamports: u64) -> Result<()> {
7167        match self.get_account_with_fixed_root(pubkey) {
7168            Some(mut account) => {
7169                let min_balance = match get_system_account_kind(&account) {
7170                    Some(SystemAccountKind::Nonce) => self
7171                        .rent_collector
7172                        .rent
7173                        .minimum_balance(nonce::State::size()),
7174                    _ => 0,
7175                };
7176
7177                lamports
7178                    .checked_add(min_balance)
7179                    .filter(|required_balance| *required_balance <= account.lamports())
7180                    .ok_or(TransactionError::InsufficientFundsForFee)?;
7181                account
7182                    .checked_sub_lamports(lamports)
7183                    .map_err(|_| TransactionError::InsufficientFundsForFee)?;
7184                self.store_account(pubkey, &account);
7185
7186                Ok(())
7187            }
7188            None => Err(TransactionError::AccountNotFound),
7189        }
7190    }
7191
7192    pub fn set_hash_overrides(&self, hash_overrides: HashOverrides) {
7193        *self.hash_overrides.lock().unwrap() = hash_overrides;
7194    }
7195}
7196
7197/// Compute how much an account has changed size.  This function is useful when the data size delta
7198/// needs to be computed and passed to an `update_accounts_data_size_delta` function.
7199fn calculate_data_size_delta(old_data_size: usize, new_data_size: usize) -> i64 {
7200    assert!(old_data_size <= i64::MAX as usize);
7201    assert!(new_data_size <= i64::MAX as usize);
7202    let old_data_size = old_data_size as i64;
7203    let new_data_size = new_data_size as i64;
7204
7205    new_data_size.saturating_sub(old_data_size)
7206}
7207
7208/// Since `apply_feature_activations()` has different behavior depending on its caller, enumerate
7209/// those callers explicitly.
7210#[derive(Debug, Copy, Clone, Eq, PartialEq)]
7211enum ApplyFeatureActivationsCaller {
7212    FinishInit,
7213    NewFromParent,
7214    WarpFromParent,
7215}
7216
7217/// Return the computed values from `collect_rent_from_accounts()`
7218///
7219/// Since `collect_rent_from_accounts()` is running in parallel, instead of updating the
7220/// atomics/shared data inside this function, return those values in this struct for the caller to
7221/// process later.
7222#[derive(Debug, Default)]
7223struct CollectRentFromAccountsInfo {
7224    skipped_rewrites: Vec<(Pubkey, AccountHash)>,
7225    rent_collected_info: CollectedInfo,
7226    rent_rewards: Vec<(Pubkey, RewardInfo)>,
7227    time_collecting_rent_us: u64,
7228    time_storing_accounts_us: u64,
7229    num_accounts: usize,
7230}
7231
7232/// Return the computed values—of each iteration in the parallel loop inside
7233/// `collect_rent_in_partition()`—and then perform a reduce on all of them.
7234#[derive(Debug, Default)]
7235struct CollectRentInPartitionInfo {
7236    skipped_rewrites: Vec<(Pubkey, AccountHash)>,
7237    rent_collected: u64,
7238    accounts_data_size_reclaimed: u64,
7239    rent_rewards: Vec<(Pubkey, RewardInfo)>,
7240    time_loading_accounts_us: u64,
7241    time_collecting_rent_us: u64,
7242    time_storing_accounts_us: u64,
7243    num_accounts: usize,
7244}
7245
7246impl CollectRentInPartitionInfo {
7247    /// Create a new `CollectRentInPartitionInfo` from the results of loading accounts and
7248    /// collecting rent on them.
7249    #[must_use]
7250    fn new(info: CollectRentFromAccountsInfo, time_loading_accounts: Duration) -> Self {
7251        Self {
7252            skipped_rewrites: info.skipped_rewrites,
7253            rent_collected: info.rent_collected_info.rent_amount,
7254            accounts_data_size_reclaimed: info.rent_collected_info.account_data_len_reclaimed,
7255            rent_rewards: info.rent_rewards,
7256            time_loading_accounts_us: time_loading_accounts.as_micros() as u64,
7257            time_collecting_rent_us: info.time_collecting_rent_us,
7258            time_storing_accounts_us: info.time_storing_accounts_us,
7259            num_accounts: info.num_accounts,
7260        }
7261    }
7262
7263    /// Reduce (i.e. 'combine') two `CollectRentInPartitionInfo`s into one.
7264    ///
7265    /// This fn is used by `collect_rent_in_partition()` as the reduce step (of map-reduce) in its
7266    /// parallel loop of rent collection.
7267    #[must_use]
7268    fn reduce(lhs: Self, rhs: Self) -> Self {
7269        Self {
7270            skipped_rewrites: [lhs.skipped_rewrites, rhs.skipped_rewrites].concat(),
7271            rent_collected: lhs.rent_collected.saturating_add(rhs.rent_collected),
7272            accounts_data_size_reclaimed: lhs
7273                .accounts_data_size_reclaimed
7274                .saturating_add(rhs.accounts_data_size_reclaimed),
7275            rent_rewards: [lhs.rent_rewards, rhs.rent_rewards].concat(),
7276            time_loading_accounts_us: lhs
7277                .time_loading_accounts_us
7278                .saturating_add(rhs.time_loading_accounts_us),
7279            time_collecting_rent_us: lhs
7280                .time_collecting_rent_us
7281                .saturating_add(rhs.time_collecting_rent_us),
7282            time_storing_accounts_us: lhs
7283                .time_storing_accounts_us
7284                .saturating_add(rhs.time_storing_accounts_us),
7285            num_accounts: lhs.num_accounts.saturating_add(rhs.num_accounts),
7286        }
7287    }
7288}
7289
7290/// Struct to collect stats when scanning all accounts in `get_total_accounts_stats()`
7291#[derive(Debug, Default, Copy, Clone, Serialize)]
7292pub struct TotalAccountsStats {
7293    /// Total number of accounts
7294    pub num_accounts: usize,
7295    /// Total data size of all accounts
7296    pub data_len: usize,
7297
7298    /// Total number of executable accounts
7299    pub num_executable_accounts: usize,
7300    /// Total data size of executable accounts
7301    pub executable_data_len: usize,
7302
7303    /// Total number of rent exempt accounts
7304    pub num_rent_exempt_accounts: usize,
7305    /// Total number of rent paying accounts
7306    pub num_rent_paying_accounts: usize,
7307    /// Total number of rent paying accounts without data
7308    pub num_rent_paying_accounts_without_data: usize,
7309    /// Total amount of lamports in rent paying accounts
7310    pub lamports_in_rent_paying_accounts: u64,
7311}
7312
7313impl TotalAccountsStats {
7314    pub fn accumulate_account(
7315        &mut self,
7316        address: &Pubkey,
7317        account: &AccountSharedData,
7318        rent_collector: &RentCollector,
7319    ) {
7320        let data_len = account.data().len();
7321        self.num_accounts += 1;
7322        self.data_len += data_len;
7323
7324        if account.executable() {
7325            self.num_executable_accounts += 1;
7326            self.executable_data_len += data_len;
7327        }
7328
7329        if !rent_collector.should_collect_rent(address, account.executable())
7330            || rent_collector
7331                .get_rent_due(
7332                    account.lamports(),
7333                    account.data().len(),
7334                    account.rent_epoch(),
7335                )
7336                .is_exempt()
7337        {
7338            self.num_rent_exempt_accounts += 1;
7339        } else {
7340            self.num_rent_paying_accounts += 1;
7341            self.lamports_in_rent_paying_accounts += account.lamports();
7342            if data_len == 0 {
7343                self.num_rent_paying_accounts_without_data += 1;
7344            }
7345        }
7346    }
7347}
7348
7349impl Drop for Bank {
7350    fn drop(&mut self) {
7351        if let Some(drop_callback) = self.drop_callback.read().unwrap().0.as_ref() {
7352            drop_callback.callback(self);
7353        } else {
7354            // Default case for tests
7355            self.rc
7356                .accounts
7357                .accounts_db
7358                .purge_slot(self.slot(), self.bank_id(), false);
7359        }
7360    }
7361}
7362
7363/// utility function used for testing and benchmarking.
7364pub mod test_utils {
7365    use {
7366        super::Bank,
7367        crate::installed_scheduler_pool::BankWithScheduler,
7368        solana_sdk::{
7369            account::{ReadableAccount, WritableAccount},
7370            hash::hashv,
7371            lamports::LamportsError,
7372            pubkey::Pubkey,
7373        },
7374        solana_vote_program::vote_state::{self, BlockTimestamp, VoteStateVersions},
7375        std::sync::Arc,
7376    };
7377    pub fn goto_end_of_slot(bank: Arc<Bank>) {
7378        goto_end_of_slot_with_scheduler(&BankWithScheduler::new_without_scheduler(bank))
7379    }
7380
7381    pub fn goto_end_of_slot_with_scheduler(bank: &BankWithScheduler) {
7382        let mut tick_hash = bank.last_blockhash();
7383        loop {
7384            tick_hash = hashv(&[tick_hash.as_ref(), &[42]]);
7385            bank.register_tick(&tick_hash);
7386            if tick_hash == bank.last_blockhash() {
7387                bank.freeze();
7388                return;
7389            }
7390        }
7391    }
7392
7393    pub fn update_vote_account_timestamp(
7394        timestamp: BlockTimestamp,
7395        bank: &Bank,
7396        vote_pubkey: &Pubkey,
7397    ) {
7398        let mut vote_account = bank.get_account(vote_pubkey).unwrap_or_default();
7399        let mut vote_state = vote_state::from(&vote_account).unwrap_or_default();
7400        vote_state.last_timestamp = timestamp;
7401        let versioned = VoteStateVersions::new_current(vote_state);
7402        vote_state::to(&versioned, &mut vote_account).unwrap();
7403        bank.store_account(vote_pubkey, &vote_account);
7404    }
7405
7406    pub fn deposit(
7407        bank: &Bank,
7408        pubkey: &Pubkey,
7409        lamports: u64,
7410    ) -> std::result::Result<u64, LamportsError> {
7411        // This doesn't collect rents intentionally.
7412        // Rents should only be applied to actual TXes
7413        let mut account = bank
7414            .get_account_with_fixed_root_no_cache(pubkey)
7415            .unwrap_or_default();
7416        account.checked_add_lamports(lamports)?;
7417        bank.store_account(pubkey, &account);
7418        Ok(account.lamports())
7419    }
7420}