1pub use {
37 crate::slot_params::DEFAULT_MAX_ENTRY_BYTES_PER_SLOT,
38 partitioned_epoch_rewards::KeyedRewardsAndNumPartitions, solana_leader_schedule::SlotLeader,
39 solana_reward_info::RewardType,
40};
41use {
42 crate::{
43 account_saver::collect_accounts_to_store,
44 alpenglow_epoch_type::AlpenglowEpochType,
45 bank::{
46 entry_bytes_budget::EntryBytesBudget,
47 metrics::*,
48 partitioned_epoch_rewards::{CachedVoteAccounts, EpochRewardStatus},
49 },
50 bank_forks::BankForks,
51 block_component_processor::{
52 BlockComponentProcessor,
53 vote_reward::epoch_inflation_account_state::EpochInflationAccountState,
54 },
55 epoch_stakes::{
56 BLSPubkeyToRankMap, DeserializableVersionedEpochStakes, NodeVoteAccounts,
57 VersionedEpochStakes,
58 },
59 inflation_rewards::points::InflationPointCalculationEvent,
60 installed_scheduler_pool::{BankWithScheduler, InstalledSchedulerRwLock},
61 leader_schedule_utils::leader_schedule_from_vote_accounts,
62 rent_collector::RentCollector,
63 reward_info::RewardInfo,
64 runtime_config::RuntimeConfig,
65 slot_params::{SlotParams, SlotParamsArchive},
66 stake_account::StakeAccount,
67 stake_history::StakeHistory as CowStakeHistory,
68 stake_weighted_timestamp::{
69 MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW_V2,
70 MaxAllowableDrift, calculate_stake_weighted_timestamp,
71 },
72 stakes::{
73 DelegatedStakes, DeserializableStakes, SerdeStakesToStakeFormat, Stakes, StakesCache,
74 },
75 status_cache::{SlotDelta, StatusCache},
76 transaction_batch::{OwnedOrBorrowed, TransactionBatch},
77 },
78 accounts_lt_hash::AccountsLtHashAsyncProgress,
79 agave_bls_cert_verify::cert_verify::{self, Error as CertVerifyError},
80 agave_feature_set::{self as feature_set, FeatureSet},
81 agave_precompiles::{get_precompile, get_precompiles, is_precompile},
82 agave_reserved_account_keys::ReservedAccountKeys,
83 agave_snapshots::snapshot_hash::SnapshotHash,
84 agave_votor_messages::{
85 certificate::{Certificate, CertificateType},
86 migration::GENESIS_CERTIFICATE_ACCOUNT,
87 unverified_vote_message::UnverifiedCertificate,
88 wire::{WireBlockCertMessage, WireCertSignature},
89 },
90 ahash::AHashSet,
91 log::*,
92 partitioned_epoch_rewards::PartitionedRewardsCalculation,
93 rayon::ThreadPool,
94 serde::{Deserialize, Serialize},
95 solana_account::{
96 Account, AccountSharedData, InheritableAccountFields, ReadableAccount, WritableAccount,
97 create_account_shared_data_with_fields as create_account, from_account,
98 },
99 solana_accounts_db::{
100 account_locks::validate_account_locks,
101 account_storage_entry::AccountStorageEntry,
102 accounts::{AccountAddressFilter, Accounts},
103 accounts_db::{AccountsDb, AccountsDbConfig},
104 accounts_hash::AccountsLtHash,
105 accounts_index::IndexKey,
106 accounts_scan::ScanResult,
107 accounts_update_notifier_interface::AccountsUpdateNotifier,
108 ancestors::Ancestors,
109 blockhash_queue::BlockhashQueue,
110 storable_accounts::StorableAccounts,
111 utils::create_account_shared_data,
112 },
113 solana_builtins::{BUILTINS, STATELESS_BUILTINS},
114 solana_clock::{
115 BankId, Epoch, INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_TRANSACTION_FORWARDING_DELAY,
116 Slot, SlotIndex, UnixTimestamp,
117 },
118 solana_cluster_type::ClusterType,
119 solana_compute_budget::compute_budget::ComputeBudget,
120 solana_cost_model::cost_tracker::CostTracker,
121 solana_epoch_info::EpochInfo,
122 solana_epoch_schedule::EpochSchedule,
123 solana_feature_gate_interface as feature,
124 solana_fee::FeeFeatures,
125 solana_fee_calculator::FeeRateGovernor,
126 solana_fee_structure::{FeeDetails, FeeStructure},
127 solana_genesis_config::GenesisConfig,
128 solana_hard_forks::HardForks,
129 solana_hash::Hash,
130 solana_inflation::Inflation,
131 solana_keypair::Keypair,
132 solana_lattice_hash::lt_hash::LtHash,
133 solana_measure::{measure::Measure, measure_time, measure_us},
134 solana_message::{
135 AccountKeys, SanitizedMessage, VersionedMessage, inner_instruction::InnerInstructions,
136 },
137 solana_packet::PACKET_DATA_SIZE,
138 solana_precompile_error::PrecompileError,
139 solana_program_runtime::{
140 invoke_context::BuiltinFunctionRegisterer,
141 loaded_programs::{ProgramRuntimeEnvironment, ProgramRuntimeEnvironments},
142 program_cache_entry::ProgramCacheEntry,
143 },
144 solana_pubkey::Pubkey,
145 solana_rent::Rent,
146 solana_runtime_transaction::{
147 runtime_transaction::RuntimeTransaction, transaction_meta::TransactionConfiguration,
148 transaction_with_meta::TransactionWithMeta,
149 },
150 solana_sdk_ids::{
151 bpf_loader_upgradeable, incinerator, native_loader, system_program, sysvar as sysvar_id,
152 },
153 solana_sha256_hasher::hashv,
154 solana_signature::Signature,
155 solana_slot_hashes::SlotHashes,
156 solana_slot_history::{Check, SlotHistory},
157 solana_stake_interface::{
158 stake_history::{SIZE as STAKE_HISTORY_ACCOUNT_SIZE, StakeHistory},
159 state::Delegation,
160 sysvar::stake_history,
161 },
162 solana_svm::{
163 account_loader::LoadedTransaction,
164 account_overrides::AccountOverrides,
165 transaction_balances::{BalanceCollector, SvmTokenInfo},
166 transaction_commit_result::{CommittedTransaction, TransactionCommitResult},
167 transaction_error_metrics::TransactionErrorMetrics,
168 transaction_execution_result::{
169 TransactionExecutionDetails, TransactionLoadedAccountsStats,
170 },
171 transaction_processing_result::{
172 ProcessedTransaction, TransactionProcessingResult,
173 TransactionProcessingResultExtensions,
174 },
175 transaction_processor::{
176 ExecutionRecordingConfig, TransactionBatchProcessor, TransactionLogMessages,
177 TransactionProcessingConfig, TransactionProcessingEnvironment,
178 },
179 },
180 solana_svm_callback::{AccountState, InvokeContextCallback, TransactionProcessingCallback},
181 solana_svm_timings::{ExecuteTimingType, ExecuteTimings},
182 solana_svm_transaction::svm_message::SVMMessage,
183 solana_syscalls::create_program_runtime_environment,
184 solana_system_transaction as system_transaction,
185 solana_sysvar::{self as sysvar, SysvarSerialize, last_restart_slot::LastRestartSlot},
186 solana_sysvar_id::SysvarId,
187 solana_transaction::{
188 Transaction, TransactionVerificationMode,
189 sanitized::{MAX_TX_ACCOUNT_LOCKS, MessageHash, SanitizedTransaction},
190 versioned::{TransactionVersion, VersionedTransaction},
191 },
192 solana_transaction_context::{
193 transaction::TransactionReturnData, transaction_accounts::KeyedAccountSharedData,
194 },
195 solana_transaction_error::{TransactionError, TransactionResult as Result},
196 solana_vote::{
197 vote_account::{VoteAccount, VoteAccounts, VoteAccountsHashMap},
198 vote_parser,
199 },
200 solana_vote_interface::state::VoteStateV4,
201 std::{
202 collections::{HashMap, HashSet},
203 fmt,
204 ops::AddAssign,
205 path::PathBuf,
206 slice,
207 sync::{
208 Arc, LazyLock, LockResult, Mutex, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard,
209 Weak,
210 atomic::{
211 AtomicBool, AtomicI64, AtomicU64,
212 Ordering::{AcqRel, Acquire, Relaxed},
213 },
214 },
215 time::{Duration, Instant},
216 },
217 thiserror::Error,
218};
219#[cfg(feature = "dev-context-only-utils")]
220use {
221 dashmap::DashSet,
222 qualifier_attr::{field_qualifiers, qualifiers},
223 rayon::iter::{IntoParallelRefIterator, ParallelIterator},
224 solana_accounts_db::accounts_db::{
225 ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS, ACCOUNTS_DB_CONFIG_FOR_TESTING,
226 },
227 solana_nonce as nonce,
228 solana_nonce_account::{SystemAccountKind, get_system_account_kind},
229 solana_program_runtime::sysvar_cache::SysvarCache,
230 solana_svm::program_loader::load_program_with_pubkey,
231};
232
233mod accounts_lt_hash;
234mod address_lookup_table;
235pub mod bank_hash_details;
236pub mod builtins;
237mod check_transactions;
238pub mod entry_bytes_budget;
239mod fee_distribution;
240mod metrics;
241pub(crate) mod partitioned_epoch_rewards;
242mod recent_blockhashes_account;
243mod serde_snapshot;
244mod sysvar_cache;
245pub(crate) mod tests;
246
247pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
248
249pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
250
251pub const MAX_ALPENGLOW_VOTE_ACCOUNTS: usize = 2000;
254
255pub const DEFAULT_VAT_TO_BURN_PER_EPOCH: u64 =
260 crate::slot_params::LEGACY_SLOT_PARAMS.vat_to_burn_per_epoch();
261
262static NANOSECOND_CLOCK_ACCOUNT: LazyLock<Pubkey> = LazyLock::new(|| {
265 let (pubkey, _) =
266 Pubkey::find_program_address(&[b"alpenclock"], &agave_feature_set::alpenglow::id());
267 pubkey
268});
269
270pub type BankStatusCache = StatusCache<Result<()>>;
271#[cfg_attr(
272 feature = "frozen-abi",
273 frozen_abi(digest = "23uAyYmzMrmPvPDKf6SvF1YoojYstmEPmdkfAQDnpwsq")
274)]
275pub type BankSlotDelta = SlotDelta<Result<()>>;
276
277#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
278pub struct SquashTiming {
279 pub squash_accounts_ms: u64,
280 pub squash_accounts_cache_ms: u64,
281 pub squash_accounts_index_ms: u64,
282 pub squash_cache_ms: u64,
283}
284
285impl AddAssign for SquashTiming {
286 fn add_assign(&mut self, rhs: Self) {
287 self.squash_accounts_ms += rhs.squash_accounts_ms;
288 self.squash_accounts_cache_ms += rhs.squash_accounts_cache_ms;
289 self.squash_accounts_index_ms += rhs.squash_accounts_index_ms;
290 self.squash_cache_ms += rhs.squash_cache_ms;
291 }
292}
293
294#[derive(Clone, Debug, Default, PartialEq)]
295pub struct CollectorFeeDetails {
296 transaction_fee: u64,
297 priority_fee: u64,
298}
299
300impl CollectorFeeDetails {
301 pub(crate) fn accumulate(&mut self, fee_details: &FeeDetails) {
302 self.transaction_fee = self
303 .transaction_fee
304 .saturating_add(fee_details.transaction_fee());
305 self.priority_fee = self
306 .priority_fee
307 .saturating_add(fee_details.prioritization_fee());
308 }
309
310 pub fn total_transaction_fee(&self) -> u64 {
311 self.transaction_fee.saturating_add(self.priority_fee)
312 }
313
314 pub fn total_priority_fee(&self) -> u64 {
315 self.priority_fee
316 }
317}
318
319impl From<FeeDetails> for CollectorFeeDetails {
320 fn from(fee_details: FeeDetails) -> Self {
321 CollectorFeeDetails {
322 transaction_fee: fee_details.transaction_fee(),
323 priority_fee: fee_details.prioritization_fee(),
324 }
325 }
326}
327
328#[derive(Debug)]
329pub struct BankRc {
330 pub accounts: Arc<Accounts>,
332
333 pub(crate) parent: RwLock<Option<Arc<Bank>>>,
335
336 pub(crate) bank_id_generator: Arc<AtomicU64>,
337}
338
339impl BankRc {
340 #[cfg_attr(feature = "dev-context-only-utils", qualifiers(pub))]
341 pub(crate) fn new(accounts: Accounts) -> Self {
342 Self {
343 accounts: Arc::new(accounts),
344 parent: RwLock::new(None),
345 bank_id_generator: Arc::new(AtomicU64::new(0)),
346 }
347 }
348}
349
350pub struct LoadAndExecuteTransactionsOutput {
351 pub processing_results: Vec<TransactionProcessingResult>,
354 pub processed_counts: ProcessedTransactionCounts,
357 pub balance_collector: Option<BalanceCollector>,
360}
361
362#[derive(Debug, PartialEq)]
363pub struct TransactionSimulationResult {
364 pub result: Result<()>,
365 pub logs: TransactionLogMessages,
366 pub post_simulation_accounts: Vec<KeyedAccountSharedData>,
367 pub units_consumed: u64,
368 pub loaded_accounts_data_size: u32,
369 pub return_data: Option<TransactionReturnData>,
370 pub inner_instructions: Option<Vec<InnerInstructions>>,
371 pub fee: Option<u64>,
372 pub pre_balances: Option<Vec<u64>>,
373 pub post_balances: Option<Vec<u64>>,
374 pub pre_token_balances: Option<Vec<SvmTokenInfo>>,
375 pub post_token_balances: Option<Vec<SvmTokenInfo>>,
376}
377
378impl TransactionSimulationResult {
379 pub fn new_error(err: TransactionError) -> Self {
380 Self {
381 fee: None,
382 inner_instructions: None,
383 loaded_accounts_data_size: 0,
384 logs: vec![],
385 post_balances: None,
386 post_simulation_accounts: vec![],
387 post_token_balances: None,
388 pre_balances: None,
389 pre_token_balances: None,
390 result: Err(err),
391 return_data: None,
392 units_consumed: 0,
393 }
394 }
395}
396
397#[derive(Clone, Debug)]
398pub struct TransactionBalancesSet {
399 pub pre_balances: TransactionBalances,
400 pub post_balances: TransactionBalances,
401}
402
403impl TransactionBalancesSet {
404 pub fn new(pre_balances: TransactionBalances, post_balances: TransactionBalances) -> Self {
405 assert_eq!(pre_balances.len(), post_balances.len());
406 Self {
407 pre_balances,
408 post_balances,
409 }
410 }
411}
412pub type TransactionBalances = Vec<Vec<u64>>;
413
414pub type PreCommitResult<'a> = Result<Option<RwLockReadGuard<'a, Hash>>>;
415
416#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Default)]
417pub enum TransactionLogCollectorFilter {
418 All,
419 AllWithVotes,
420 #[default]
421 None,
422 OnlyMentionedAddresses,
423}
424
425#[derive(Debug, Default)]
426pub struct TransactionLogCollectorConfig {
427 pub mentioned_addresses: HashSet<Pubkey>,
428 pub filter: TransactionLogCollectorFilter,
429}
430
431#[derive(Clone, Debug, PartialEq, Eq)]
432pub struct TransactionLogInfo {
433 pub signature: Signature,
434 pub result: Result<()>,
435 pub is_vote: bool,
436 pub log_messages: TransactionLogMessages,
437}
438
439#[derive(Default, Debug)]
440pub struct TransactionLogCollector {
441 pub logs: Vec<TransactionLogInfo>,
444
445 pub mentioned_address_map: HashMap<Pubkey, Vec<usize>>,
448}
449
450impl TransactionLogCollector {
451 pub fn get_logs_for_address(
452 &self,
453 address: Option<&Pubkey>,
454 ) -> Option<Vec<TransactionLogInfo>> {
455 match address {
456 None => Some(self.logs.clone()),
457 Some(address) => self.mentioned_address_map.get(address).map(|log_indices| {
458 log_indices
459 .iter()
460 .filter_map(|i| self.logs.get(*i).cloned())
461 .collect()
462 }),
463 }
464 }
465}
466
467#[derive(Error, Debug, Serialize, Deserialize)]
468pub enum VATHealthError {
469 #[error("vote account not found")]
470 VoteAccountNotFound,
471 #[error("missing BLS pubkey")]
472 NoBLSPubkey,
473 #[error("insufficient lamports in vote account: {0} < {1}")]
474 InsufficientFundsInVoteAccount(u64, u64),
475}
476
477#[derive(Clone, Debug)]
485#[cfg_attr(
486 feature = "dev-context-only-utils",
487 field_qualifiers(
488 blockhash_queue(pub),
489 hash(pub),
490 parent_hash(pub),
491 parent_slot(pub),
492 hard_forks(pub),
493 transaction_count(pub),
494 tick_height(pub),
495 signature_count(pub),
496 capitalization(pub),
497 max_tick_height(pub),
498 hashes_per_tick(pub),
499 ticks_per_slot(pub),
500 ns_per_slot(pub),
501 genesis_creation_time(pub),
502 slots_per_year(pub),
503 slot(pub),
504 block_height(pub),
505 leader_id(pub),
506 fee_rate_governor(pub),
507 epoch_schedule(pub),
508 inflation(pub),
509 stakes(pub),
510 is_delta(pub),
511 accounts_data_len(pub),
512 versioned_epoch_stakes(pub),
513 accounts_lt_hash(pub),
514 bank_hash_stats(pub),
515 block_id(pub),
516 )
517)]
518pub struct BankFieldsToDeserialize {
519 pub(crate) blockhash_queue: BlockhashQueue,
520 pub(crate) hash: Hash,
521 pub(crate) parent_hash: Hash,
522 pub(crate) parent_slot: Slot,
523 pub(crate) hard_forks: HardForks,
524 pub(crate) transaction_count: u64,
525 pub(crate) tick_height: u64,
526 pub(crate) signature_count: u64,
527 pub(crate) capitalization: u64,
528 pub(crate) max_tick_height: u64,
529 pub(crate) hashes_per_tick: Option<u64>,
530 pub(crate) ticks_per_slot: u64,
531 pub(crate) ns_per_slot: u128,
532 pub(crate) genesis_creation_time: UnixTimestamp,
533 pub(crate) slots_per_year: f64,
534 pub(crate) slot: Slot,
535 pub(crate) block_height: u64,
536 pub(crate) leader_id: Pubkey,
537 pub(crate) fee_rate_governor: FeeRateGovernor,
538 pub(crate) epoch_schedule: EpochSchedule,
539 pub(crate) inflation: Inflation,
540 pub(crate) stakes: DeserializableStakes<Delegation>,
541 pub(crate) versioned_epoch_stakes: Vec<(Epoch, DeserializableVersionedEpochStakes)>,
544 pub(crate) is_delta: bool,
545 pub(crate) accounts_data_len: u64,
546 pub(crate) accounts_lt_hash: AccountsLtHash,
547 pub(crate) bank_hash_stats: BankHashStats,
548 pub(crate) block_id: Option<Hash>, }
550
551#[derive(Debug)]
560pub struct BankFieldsToSerialize {
561 pub blockhash_queue: BlockhashQueue,
562 pub hash: Hash,
563 pub parent_hash: Hash,
564 pub parent_slot: Slot,
565 pub hard_forks: HardForks,
566 pub transaction_count: u64,
567 pub tick_height: u64,
568 pub signature_count: u64,
569 pub capitalization: u64,
570 pub max_tick_height: u64,
571 pub hashes_per_tick: Option<u64>,
572 pub ticks_per_slot: u64,
573 pub ns_per_slot: u128,
574 pub genesis_creation_time: UnixTimestamp,
575 pub slots_per_year: f64,
576 pub slot: Slot,
577 pub block_height: u64,
578 pub leader_id: Pubkey,
579 pub fee_rate_governor: FeeRateGovernor,
580 pub epoch_schedule: EpochSchedule,
581 pub inflation: Inflation,
582 pub stakes: Stakes<StakeAccount<Delegation>>,
583 pub is_delta: bool,
584 pub accounts_data_len: u64,
585 pub versioned_epoch_stakes: HashMap<u64, VersionedEpochStakes>,
586 pub accounts_lt_hash: AccountsLtHash,
587 pub block_id: Hash,
588}
589
590#[cfg(feature = "dev-context-only-utils")]
592impl PartialEq for Bank {
593 fn eq(&self, other: &Self) -> bool {
594 if std::ptr::eq(self, other) {
595 return true;
596 }
597 #[rustfmt::skip]
599 let Self {
600 rc: _,
601 status_cache: _,
602 blockhash_queue,
603 max_processing_age,
604 partitioned_rewards_stake_account_stores_per_block,
605 ancestors: _,
606 hash,
607 parent_hash,
608 parent_slot,
609 hard_forks,
610 transaction_count,
611 non_vote_transaction_count_since_restart: _,
612 transaction_error_count: _,
613 transaction_entries_count: _,
614 transactions_per_entry_max: _,
615 entry_bytes_consumed: _,
616 tick_height,
617 signature_count,
618 capitalization,
619 max_tick_height,
620 hashes_per_tick,
621 ticks_per_slot,
622 ns_per_slot,
623 genesis_creation_time,
624 slots_per_year,
625 slot_params: _,
626 slot,
627 bank_id: _,
628 epoch,
629 block_height,
630 leader,
631 fee_rate_governor,
632 rent_collector,
633 epoch_schedule,
634 inflation,
635 stakes_cache,
636 epoch_stakes,
637 is_delta,
638 #[cfg(feature = "dev-context-only-utils")]
639 hash_overrides,
640 accounts_lt_hash,
641 is_alpenglow,
642 rewards: _,
644 cluster_type: _,
645 transaction_debug_keys: _,
646 transaction_log_collector_config: _,
647 transaction_log_collector: _,
648 feature_set: _,
649 reserved_account_keys: _,
650 drop_callback: _,
651 freeze_started: _,
652 vote_only_bank: _,
653 cost_tracker: _,
654 accounts_data_size_initial: _,
655 accounts_data_size_delta_on_chain: _,
656 accounts_data_size_delta_off_chain: _,
657 epoch_reward_status: _,
658 transaction_processor: _,
659 check_program_deployment_slot: _,
660 collector_fee_details: _,
661 compute_budget: _,
662 transaction_account_lock_limit: _,
663 fee_structure: _,
664 accounts_lt_hash_async_progress: _,
665 block_id,
666 expected_bank_hash: _,
667 bank_hash_stats: _,
668 epoch_rewards_calculation_cache: _,
669 block_component_processor: _,
670 } = self;
674 *blockhash_queue.read().unwrap() == *other.blockhash_queue.read().unwrap()
675 && *max_processing_age == other.max_processing_age
676 && *partitioned_rewards_stake_account_stores_per_block
677 == other.partitioned_rewards_stake_account_stores_per_block
678 && *hash.read().unwrap() == *other.hash.read().unwrap()
679 && parent_hash == &other.parent_hash
680 && parent_slot == &other.parent_slot
681 && *hard_forks.read().unwrap() == *other.hard_forks.read().unwrap()
682 && transaction_count.load(Relaxed) == other.transaction_count.load(Relaxed)
683 && tick_height.load(Relaxed) == other.tick_height.load(Relaxed)
684 && signature_count.load(Relaxed) == other.signature_count.load(Relaxed)
685 && capitalization.load(Relaxed) == other.capitalization.load(Relaxed)
686 && max_tick_height == &other.max_tick_height
687 && *hashes_per_tick.read().unwrap() == *other.hashes_per_tick.read().unwrap()
688 && ticks_per_slot == &other.ticks_per_slot
689 && ns_per_slot == &other.ns_per_slot
690 && genesis_creation_time == &other.genesis_creation_time
691 && slots_per_year == &other.slots_per_year
692 && slot == &other.slot
693 && epoch == &other.epoch
694 && block_height == &other.block_height
695 && leader == &other.leader
696 && fee_rate_governor == &other.fee_rate_governor
697 && rent_collector == &other.rent_collector
698 && epoch_schedule == &other.epoch_schedule
699 && *inflation.read().unwrap() == *other.inflation.read().unwrap()
700 && *stakes_cache.stakes() == *other.stakes_cache.stakes()
701 && epoch_stakes == &other.epoch_stakes
702 && is_delta.load(Relaxed) == other.is_delta.load(Relaxed)
703 && (Arc::ptr_eq(hash_overrides, &other.hash_overrides) ||
706 *hash_overrides.lock().unwrap() == *other.hash_overrides.lock().unwrap())
707 && *accounts_lt_hash.lock().unwrap() == *other.accounts_lt_hash.lock().unwrap()
708 && *block_id.read().unwrap() == *other.block_id.read().unwrap()
709 && is_alpenglow.load(Relaxed) == other.is_alpenglow()
710 }
711}
712
713#[cfg(feature = "dev-context-only-utils")]
714impl BankFieldsToSerialize {
715 pub fn default_for_tests() -> Self {
718 Self {
719 blockhash_queue: BlockhashQueue::default(),
720 hash: Hash::default(),
721 parent_hash: Hash::default(),
722 parent_slot: Slot::default(),
723 hard_forks: HardForks::default(),
724 transaction_count: u64::default(),
725 tick_height: u64::default(),
726 signature_count: u64::default(),
727 capitalization: u64::default(),
728 max_tick_height: u64::default(),
729 hashes_per_tick: Option::default(),
730 ticks_per_slot: u64::default(),
731 ns_per_slot: u128::default(),
732 genesis_creation_time: UnixTimestamp::default(),
733 slots_per_year: f64::default(),
734 slot: Slot::default(),
735 block_height: u64::default(),
736 leader_id: Pubkey::default(),
737 fee_rate_governor: FeeRateGovernor::default(),
738 epoch_schedule: EpochSchedule::default(),
739 inflation: Inflation::default(),
740 stakes: Stakes::<StakeAccount<Delegation>>::default(),
741 is_delta: bool::default(),
742 accounts_data_len: u64::default(),
743 versioned_epoch_stakes: HashMap::default(),
744 accounts_lt_hash: AccountsLtHash(LtHash([0x7E57; LtHash::NUM_ELEMENTS])),
745 block_id: Hash::default(),
746 }
747 }
748}
749
750#[derive(Debug)]
751pub enum RewardCalculationEvent<'a, 'b> {
752 Staking(&'a Pubkey, &'b InflationPointCalculationEvent),
753}
754pub trait RewardCalcTracer: Fn(&RewardCalculationEvent) + Send + Sync {}
758
759impl<T: Fn(&RewardCalculationEvent) + Send + Sync> RewardCalcTracer for T {}
760
761fn null_tracer() -> Option<impl RewardCalcTracer> {
762 None::<fn(&RewardCalculationEvent)>
763}
764
765pub trait DropCallback: fmt::Debug {
766 fn callback(&self, b: &Bank);
767 fn clone_box(&self) -> Box<dyn DropCallback + Send + Sync>;
768}
769
770#[derive(Debug, Default)]
771pub struct OptionalDropCallback(Option<Box<dyn DropCallback + Send + Sync>>);
772
773#[derive(Default, Debug, Clone, PartialEq)]
774#[cfg(feature = "dev-context-only-utils")]
775pub struct HashOverrides {
776 hashes: HashMap<Slot, HashOverride>,
777}
778
779#[cfg(feature = "dev-context-only-utils")]
780impl HashOverrides {
781 fn get_hash_override(&self, slot: Slot) -> Option<&HashOverride> {
782 self.hashes.get(&slot)
783 }
784
785 fn get_blockhash_override(&self, slot: Slot) -> Option<&Hash> {
786 self.get_hash_override(slot)
787 .map(|hash_override| &hash_override.blockhash)
788 }
789
790 fn get_bank_hash_override(&self, slot: Slot) -> Option<&Hash> {
791 self.get_hash_override(slot)
792 .map(|hash_override| &hash_override.bank_hash)
793 }
794
795 pub fn add_override(&mut self, slot: Slot, blockhash: Hash, bank_hash: Hash) {
796 let is_new = self
797 .hashes
798 .insert(
799 slot,
800 HashOverride {
801 blockhash,
802 bank_hash,
803 },
804 )
805 .is_none();
806 assert!(is_new);
807 }
808}
809
810#[derive(Debug, Clone, PartialEq)]
811#[cfg(feature = "dev-context-only-utils")]
812struct HashOverride {
813 blockhash: Hash,
814 bank_hash: Hash,
815}
816
817pub struct Bank {
819 pub rc: BankRc,
821
822 pub status_cache: Arc<RwLock<BankStatusCache>>,
824
825 blockhash_queue: RwLock<BlockhashQueue>,
827
828 max_processing_age: usize,
830
831 partitioned_rewards_stake_account_stores_per_block: u64,
833
834 pub ancestors: Ancestors,
836
837 hash: RwLock<Hash>,
839
840 parent_hash: Hash,
842
843 parent_slot: Slot,
845
846 hard_forks: Arc<RwLock<HardForks>>,
848
849 transaction_count: AtomicU64,
851
852 non_vote_transaction_count_since_restart: AtomicU64,
857
858 transaction_error_count: AtomicU64,
860
861 transaction_entries_count: AtomicU64,
863
864 transactions_per_entry_max: AtomicU64,
866
867 entry_bytes_consumed: EntryBytesBudget,
869
870 tick_height: AtomicU64,
872
873 signature_count: AtomicU64,
875
876 capitalization: AtomicU64,
878
879 max_tick_height: u64,
881
882 hashes_per_tick: RwLock<Option<u64>>,
884
885 ticks_per_slot: u64,
887
888 pub ns_per_slot: u128,
890
891 genesis_creation_time: UnixTimestamp,
893
894 slots_per_year: f64,
896
897 slot_params: SlotParamsArchive,
899
900 slot: Slot,
902
903 bank_id: BankId,
904
905 epoch: Epoch,
907
908 block_height: u64,
910
911 leader: SlotLeader,
913
914 pub(crate) fee_rate_governor: FeeRateGovernor,
916
917 rent_collector: RentCollector,
919
920 pub(crate) epoch_schedule: EpochSchedule,
922
923 inflation: Arc<RwLock<Inflation>>,
925
926 stakes_cache: StakesCache,
928
929 epoch_stakes: HashMap<Epoch, VersionedEpochStakes>,
932
933 is_delta: AtomicBool,
936
937 pub rewards: RwLock<Vec<(Pubkey, RewardInfo)>>,
939
940 pub cluster_type: Option<ClusterType>,
941
942 transaction_debug_keys: Option<Arc<HashSet<Pubkey>>>,
943
944 pub transaction_log_collector_config: Arc<RwLock<TransactionLogCollectorConfig>>,
946
947 pub transaction_log_collector: Arc<RwLock<TransactionLogCollector>>,
950
951 pub feature_set: Arc<FeatureSet>,
952
953 reserved_account_keys: Arc<ReservedAccountKeys>,
955
956 pub drop_callback: RwLock<OptionalDropCallback>,
958
959 pub freeze_started: AtomicBool,
960
961 vote_only_bank: bool,
962
963 cost_tracker: RwLock<CostTracker>,
964
965 accounts_data_size_initial: u64,
967 accounts_data_size_delta_on_chain: AtomicI64,
969 accounts_data_size_delta_off_chain: AtomicI64,
971
972 epoch_reward_status: EpochRewardStatus,
973
974 transaction_processor: TransactionBatchProcessor<BankForks>,
975
976 check_program_deployment_slot: bool,
977
978 collector_fee_details: RwLock<CollectorFeeDetails>,
980
981 compute_budget: Option<ComputeBudget>,
983
984 transaction_account_lock_limit: Option<usize>,
986
987 fee_structure: FeeStructure,
989
990 #[cfg(feature = "dev-context-only-utils")]
993 hash_overrides: Arc<Mutex<HashOverrides>>,
994
995 accounts_lt_hash: Mutex<AccountsLtHash>,
999
1000 accounts_lt_hash_async_progress: AccountsLtHashAsyncProgress,
1002
1003 block_id: RwLock<Option<Hash>>,
1007
1008 expected_bank_hash: RwLock<Option<Hash>>,
1011
1012 bank_hash_stats: AtomicBankHashStats,
1014
1015 epoch_rewards_calculation_cache: Arc<Mutex<HashMap<Hash, Arc<PartitionedRewardsCalculation>>>>,
1019
1020 pub block_component_processor: RwLock<BlockComponentProcessor>,
1024
1025 is_alpenglow: AtomicBool,
1027}
1028
1029#[derive(Debug, Default)]
1030pub struct NewBankOptions {
1031 pub vote_only_bank: bool,
1032}
1033
1034#[cfg(feature = "dev-context-only-utils")]
1035#[derive(Debug)]
1036pub struct BankTestConfig {
1037 pub accounts_db_config: AccountsDbConfig,
1038}
1039
1040#[cfg(feature = "dev-context-only-utils")]
1041impl Default for BankTestConfig {
1042 fn default() -> Self {
1043 Self {
1044 accounts_db_config: ACCOUNTS_DB_CONFIG_FOR_TESTING,
1045 }
1046 }
1047}
1048
1049#[derive(Debug, Default, PartialEq)]
1050pub struct ProcessedTransactionCounts {
1051 pub processed_transactions_count: u64,
1052 pub processed_non_vote_transactions_count: u64,
1053 pub processed_with_successful_result_count: u64,
1054 pub signature_count: u64,
1055}
1056
1057#[cfg_attr(feature = "frozen-abi", derive(AbiExample, StableAbi, StableAbiSample))]
1060#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)]
1061pub struct BankHashStats {
1062 pub num_updated_accounts: u64,
1063 pub num_removed_accounts: u64,
1064 pub num_lamports_stored: u64,
1065 pub total_data_len: u64,
1066 pub num_executable_accounts: u64,
1067}
1068
1069impl BankHashStats {
1070 pub fn update<T: ReadableAccount>(&mut self, account: &T) {
1071 if account.lamports() == 0 {
1072 self.num_removed_accounts += 1;
1073 } else {
1074 self.num_updated_accounts += 1;
1075 }
1076 self.total_data_len = self
1077 .total_data_len
1078 .wrapping_add(account.data().len() as u64);
1079 if account.executable() {
1080 self.num_executable_accounts += 1;
1081 }
1082 self.num_lamports_stored = self.num_lamports_stored.wrapping_add(account.lamports());
1083 }
1084 pub fn accumulate(&mut self, other: &BankHashStats) {
1085 self.num_updated_accounts += other.num_updated_accounts;
1086 self.num_removed_accounts += other.num_removed_accounts;
1087 self.total_data_len = self.total_data_len.wrapping_add(other.total_data_len);
1088 self.num_lamports_stored = self
1089 .num_lamports_stored
1090 .wrapping_add(other.num_lamports_stored);
1091 self.num_executable_accounts += other.num_executable_accounts;
1092 }
1093}
1094
1095#[derive(Debug, Default)]
1096pub struct AtomicBankHashStats {
1097 pub num_updated_accounts: AtomicU64,
1098 pub num_removed_accounts: AtomicU64,
1099 pub num_lamports_stored: AtomicU64,
1100 pub total_data_len: AtomicU64,
1101 pub num_executable_accounts: AtomicU64,
1102}
1103
1104impl AtomicBankHashStats {
1105 pub fn new(stat: &BankHashStats) -> Self {
1106 AtomicBankHashStats {
1107 num_updated_accounts: AtomicU64::new(stat.num_updated_accounts),
1108 num_removed_accounts: AtomicU64::new(stat.num_removed_accounts),
1109 num_lamports_stored: AtomicU64::new(stat.num_lamports_stored),
1110 total_data_len: AtomicU64::new(stat.total_data_len),
1111 num_executable_accounts: AtomicU64::new(stat.num_executable_accounts),
1112 }
1113 }
1114
1115 pub fn accumulate(&self, other: &BankHashStats) {
1116 self.num_updated_accounts
1117 .fetch_add(other.num_updated_accounts, Relaxed);
1118 self.num_removed_accounts
1119 .fetch_add(other.num_removed_accounts, Relaxed);
1120 self.total_data_len.fetch_add(other.total_data_len, Relaxed);
1121 self.num_lamports_stored
1122 .fetch_add(other.num_lamports_stored, Relaxed);
1123 self.num_executable_accounts
1124 .fetch_add(other.num_executable_accounts, Relaxed);
1125 }
1126
1127 pub fn load(&self) -> BankHashStats {
1128 BankHashStats {
1129 num_updated_accounts: self.num_updated_accounts.load(Relaxed),
1130 num_removed_accounts: self.num_removed_accounts.load(Relaxed),
1131 num_lamports_stored: self.num_lamports_stored.load(Relaxed),
1132 total_data_len: self.total_data_len.load(Relaxed),
1133 num_executable_accounts: self.num_executable_accounts.load(Relaxed),
1134 }
1135 }
1136}
1137
1138struct NewEpochBundle {
1139 stake_history: CowStakeHistory,
1140 unfiltered_distribution_vote_accounts: VoteAccounts,
1143 delegated_stakes: DelegatedStakes,
1145 filtered_distribution_vote_accounts: VoteAccounts,
1149 rewards_calculation: Arc<PartitionedRewardsCalculation>,
1150 calculate_activated_stake_time_us: u64,
1151 update_rewards_with_thread_pool_time_us: u64,
1152}
1153
1154fn create_stake_history_account(
1155 stake_history: &StakeHistory,
1156 (lamports, rent_epoch): InheritableAccountFields,
1157) -> AccountSharedData {
1158 let data_len =
1159 STAKE_HISTORY_ACCOUNT_SIZE.max(bincode::serialized_size(stake_history).unwrap() as usize);
1160 let mut account = AccountSharedData::new(lamports, data_len, &sysvar_id::id());
1161 account.serialize_data(stake_history).unwrap();
1162 account.set_rent_epoch(rent_epoch);
1163 account
1164}
1165
1166impl Bank {
1167 fn default_with_accounts(accounts: Accounts) -> Self {
1168 let partitioned_rewards_stake_account_stores_per_block = accounts
1169 .accounts_db
1170 .partitioned_epoch_rewards_config
1171 .stake_account_stores_per_block;
1172 let mut bank = Self {
1173 rc: BankRc::new(accounts),
1174 status_cache: Arc::<RwLock<BankStatusCache>>::default(),
1175 blockhash_queue: RwLock::<BlockhashQueue>::default(),
1176 max_processing_age: MAX_PROCESSING_AGE,
1177 partitioned_rewards_stake_account_stores_per_block,
1178 ancestors: Ancestors::default(),
1179 hash: RwLock::<Hash>::default(),
1180 parent_hash: Hash::default(),
1181 parent_slot: Slot::default(),
1182 hard_forks: Arc::<RwLock<HardForks>>::default(),
1183 transaction_count: AtomicU64::default(),
1184 non_vote_transaction_count_since_restart: AtomicU64::default(),
1185 transaction_error_count: AtomicU64::default(),
1186 transaction_entries_count: AtomicU64::default(),
1187 transactions_per_entry_max: AtomicU64::default(),
1188 entry_bytes_consumed: EntryBytesBudget::new(DEFAULT_MAX_ENTRY_BYTES_PER_SLOT),
1189 tick_height: AtomicU64::default(),
1190 signature_count: AtomicU64::default(),
1191 capitalization: AtomicU64::default(),
1192 max_tick_height: u64::default(),
1193 hashes_per_tick: RwLock::default(),
1194 ticks_per_slot: u64::default(),
1195 ns_per_slot: u128::default(),
1196 genesis_creation_time: UnixTimestamp::default(),
1197 slots_per_year: f64::default(),
1198 slot_params: SlotParamsArchive::default(),
1199 slot: Slot::default(),
1200 bank_id: BankId::default(),
1201 epoch: Epoch::default(),
1202 block_height: u64::default(),
1203 leader: SlotLeader::default(),
1204 fee_rate_governor: FeeRateGovernor::default(),
1205 rent_collector: RentCollector::default(),
1206 epoch_schedule: EpochSchedule::default(),
1207 inflation: Arc::<RwLock<Inflation>>::default(),
1208 stakes_cache: StakesCache::default(),
1209 epoch_stakes: HashMap::<Epoch, VersionedEpochStakes>::default(),
1210 is_delta: AtomicBool::default(),
1211 rewards: RwLock::<Vec<(Pubkey, RewardInfo)>>::default(),
1212 cluster_type: Option::<ClusterType>::default(),
1213 transaction_debug_keys: Option::<Arc<HashSet<Pubkey>>>::default(),
1214 transaction_log_collector_config: Arc::<RwLock<TransactionLogCollectorConfig>>::default(
1215 ),
1216 transaction_log_collector: Arc::<RwLock<TransactionLogCollector>>::default(),
1217 feature_set: Arc::<FeatureSet>::default(),
1218 reserved_account_keys: Arc::<ReservedAccountKeys>::default(),
1219 drop_callback: RwLock::new(OptionalDropCallback(None)),
1220 freeze_started: AtomicBool::default(),
1221 vote_only_bank: false,
1222 cost_tracker: RwLock::<CostTracker>::default(),
1223 accounts_data_size_initial: 0,
1224 accounts_data_size_delta_on_chain: AtomicI64::new(0),
1225 accounts_data_size_delta_off_chain: AtomicI64::new(0),
1226 epoch_reward_status: EpochRewardStatus::default(),
1227 transaction_processor: TransactionBatchProcessor::default(),
1228 check_program_deployment_slot: false,
1229 collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
1230 compute_budget: None,
1231 transaction_account_lock_limit: None,
1232 fee_structure: FeeStructure::default(),
1233 #[cfg(feature = "dev-context-only-utils")]
1234 hash_overrides: Arc::new(Mutex::new(HashOverrides::default())),
1235 accounts_lt_hash: Mutex::new(AccountsLtHash(LtHash::identity())),
1236 accounts_lt_hash_async_progress: AccountsLtHashAsyncProgress::new(),
1237 block_id: RwLock::new(None),
1238 expected_bank_hash: RwLock::new(None),
1239 bank_hash_stats: AtomicBankHashStats::default(),
1240 epoch_rewards_calculation_cache: Arc::new(Mutex::new(HashMap::default())),
1241 block_component_processor: RwLock::new(BlockComponentProcessor::default()),
1242 is_alpenglow: AtomicBool::new(false),
1243 };
1244
1245 bank.transaction_processor =
1246 TransactionBatchProcessor::new_uninitialized(bank.slot, bank.epoch);
1247
1248 bank.accounts_data_size_initial = bank.calculate_accounts_data_size().unwrap();
1249
1250 bank
1251 }
1252
1253 #[expect(clippy::too_many_arguments)]
1254 pub fn new_from_genesis(
1255 genesis_config: &GenesisConfig,
1256 runtime_config: Arc<RuntimeConfig>,
1257 paths: Vec<PathBuf>,
1258 debug_keys: Option<Arc<HashSet<Pubkey>>>,
1259 accounts_db_config: AccountsDbConfig,
1260 accounts_update_notifier: Option<AccountsUpdateNotifier>,
1261 #[cfg_attr(not(feature = "dev-context-only-utils"), expect(unused))]
1262 leader_for_tests: Option<SlotLeader>,
1263 exit: Arc<AtomicBool>,
1264 #[cfg_attr(not(feature = "dev-context-only-utils"), expect(unused))] genesis_hash: Option<
1265 Hash,
1266 >,
1267 #[cfg_attr(not(feature = "dev-context-only-utils"), expect(unused))] feature_set: Option<
1268 FeatureSet,
1269 >,
1270 ) -> Self {
1271 let _rewards_calculation_thread_pool = rewards_calculation_thread_pool();
1274 let accounts_db =
1275 AccountsDb::new_with_config(paths, accounts_db_config, accounts_update_notifier, exit);
1276 let accounts = Accounts::new(Arc::new(accounts_db));
1277 let mut bank = Self::default_with_accounts(accounts);
1278 bank.ancestors = Ancestors::from(vec![bank.slot()]);
1279 bank.compute_budget = runtime_config.compute_budget;
1280 if let Some(compute_budget) = &bank.compute_budget {
1281 bank.transaction_processor
1282 .set_execution_cost(compute_budget.to_cost());
1283 }
1284 bank.transaction_account_lock_limit = runtime_config.transaction_account_lock_limit;
1285 bank.transaction_debug_keys = debug_keys;
1286 bank.cluster_type = Some(genesis_config.cluster_type);
1287
1288 #[cfg(feature = "dev-context-only-utils")]
1289 {
1290 bank.feature_set = Arc::new(feature_set.unwrap_or_default());
1291 }
1292
1293 #[cfg(not(feature = "dev-context-only-utils"))]
1294 bank.process_genesis_config(genesis_config);
1295 #[cfg(feature = "dev-context-only-utils")]
1296 bank.process_genesis_config(genesis_config, leader_for_tests, genesis_hash);
1297
1298 bank.compute_and_apply_genesis_features();
1299
1300 {
1303 let stakes = bank.get_top_epoch_stakes();
1304 let stakes = SerdeStakesToStakeFormat::from(stakes);
1305 for epoch in 0..=bank.get_leader_schedule_epoch(bank.slot) {
1306 bank.epoch_stakes
1307 .insert(epoch, VersionedEpochStakes::new(stakes.clone(), epoch));
1308 }
1309 bank.update_stake_history(None);
1310 }
1311 bank.update_clock(None);
1312 bank.update_rent();
1313 bank.update_epoch_schedule();
1314 bank.update_recent_blockhashes();
1315 bank.update_last_restart_slot();
1316 bank.transaction_processor
1317 .fill_missing_sysvar_cache_entries(&bank);
1318 if bank.get_alpenglow_genesis_certificate().is_some() {
1319 bank.set_is_alpenglow();
1320 }
1321 bank
1322 }
1323
1324 pub fn new_from_parent(parent: Arc<Bank>, leader: SlotLeader, slot: Slot) -> Self {
1326 Self::_new_from_parent(
1327 parent,
1328 leader,
1329 slot,
1330 null_tracer(),
1331 NewBankOptions::default(),
1332 )
1333 }
1334
1335 pub fn new_from_parent_with_options(
1336 parent: Arc<Bank>,
1337 leader: SlotLeader,
1338 slot: Slot,
1339 new_bank_options: NewBankOptions,
1340 ) -> Self {
1341 Self::_new_from_parent(parent, leader, slot, null_tracer(), new_bank_options)
1342 }
1343
1344 pub fn new_from_parent_with_tracer(
1345 parent: Arc<Bank>,
1346 leader: SlotLeader,
1347 slot: Slot,
1348 reward_calc_tracer: impl RewardCalcTracer,
1349 ) -> Self {
1350 Self::_new_from_parent(
1351 parent,
1352 leader,
1353 slot,
1354 Some(reward_calc_tracer),
1355 NewBankOptions::default(),
1356 )
1357 }
1358
1359 fn get_rent_collector_from(rent_collector: &RentCollector, epoch: Epoch) -> RentCollector {
1360 rent_collector.clone_with_epoch(epoch)
1361 }
1362
1363 fn _new_from_parent(
1364 parent: Arc<Bank>,
1365 leader: SlotLeader,
1366 slot: Slot,
1367 reward_calc_tracer: Option<impl RewardCalcTracer>,
1368 new_bank_options: NewBankOptions,
1369 ) -> Self {
1370 let mut time = Measure::start("bank::new_from_parent");
1371 let NewBankOptions { vote_only_bank } = new_bank_options;
1372
1373 parent.freeze();
1374 assert_ne!(slot, parent.slot());
1375
1376 let epoch_schedule = parent.epoch_schedule().clone();
1377 let epoch = epoch_schedule.get_epoch(slot);
1378
1379 let (rc, bank_rc_creation_time_us) = measure_us!({
1380 let accounts_db = Arc::clone(&parent.rc.accounts.accounts_db);
1381 BankRc {
1382 accounts: Arc::new(Accounts::new(accounts_db)),
1383 parent: RwLock::new(Some(Arc::clone(&parent))),
1384 bank_id_generator: Arc::clone(&parent.rc.bank_id_generator),
1385 }
1386 });
1387
1388 let (status_cache, status_cache_time_us) = measure_us!(Arc::clone(&parent.status_cache));
1389
1390 let (fee_rate_governor, fee_components_time_us) = measure_us!(
1391 FeeRateGovernor::new_derived(&parent.fee_rate_governor, parent.signature_count())
1392 );
1393
1394 let bank_id = rc.bank_id_generator.fetch_add(1, Relaxed) + 1;
1395 let (blockhash_queue, blockhash_queue_time_us) =
1396 measure_us!(RwLock::new(parent.blockhash_queue.read().unwrap().clone()));
1397
1398 let (stakes_cache, stakes_cache_time_us) =
1399 measure_us!(StakesCache::new(parent.stakes_cache.stakes().clone()));
1400
1401 let (epoch_stakes, epoch_stakes_time_us) = measure_us!(parent.epoch_stakes.clone());
1402
1403 let (transaction_processor, builtin_program_ids_time_us) = measure_us!(
1404 TransactionBatchProcessor::new_from(&parent.transaction_processor, slot, epoch)
1405 );
1406
1407 let (transaction_debug_keys, transaction_debug_keys_time_us) =
1408 measure_us!(parent.transaction_debug_keys.clone());
1409
1410 let (transaction_log_collector_config, transaction_log_collector_config_time_us) =
1411 measure_us!(parent.transaction_log_collector_config.clone());
1412
1413 let (feature_set, feature_set_time_us) = measure_us!(parent.feature_set.clone());
1414
1415 let accounts_data_size_initial = parent.load_accounts_data_size();
1416 let mut new = Self {
1417 rc,
1418 status_cache,
1419 slot,
1420 bank_id,
1421 epoch,
1422 blockhash_queue,
1423 max_processing_age: parent.max_processing_age,
1424 partitioned_rewards_stake_account_stores_per_block: parent
1425 .partitioned_rewards_stake_account_stores_per_block,
1426 hashes_per_tick: RwLock::new(parent.hashes_per_tick()),
1428 ticks_per_slot: parent.ticks_per_slot,
1429 ns_per_slot: parent.ns_per_slot,
1430 genesis_creation_time: parent.genesis_creation_time,
1431 slots_per_year: parent.slots_per_year,
1432 slot_params: parent.slot_params.clone(),
1433 epoch_schedule,
1434 rent_collector: Self::get_rent_collector_from(&parent.rent_collector, epoch),
1435 max_tick_height: slot
1436 .checked_add(1)
1437 .expect("max tick height addition overflowed")
1438 .checked_mul(parent.ticks_per_slot)
1439 .expect("max tick height multiplication overflowed"),
1440 block_height: parent
1441 .block_height
1442 .checked_add(1)
1443 .expect("block height addition overflowed"),
1444 fee_rate_governor,
1445 capitalization: AtomicU64::new(parent.capitalization()),
1446 vote_only_bank,
1447 inflation: parent.inflation.clone(),
1448 transaction_count: AtomicU64::new(parent.transaction_count()),
1449 non_vote_transaction_count_since_restart: AtomicU64::new(
1450 parent.non_vote_transaction_count_since_restart(),
1451 ),
1452 transaction_error_count: AtomicU64::new(0),
1453 transaction_entries_count: AtomicU64::new(0),
1454 transactions_per_entry_max: AtomicU64::new(0),
1455 entry_bytes_consumed: EntryBytesBudget::new(parent.entry_bytes_budget().slot_limit()),
1456 stakes_cache,
1458 epoch_stakes,
1459 parent_hash: parent.hash(),
1460 parent_slot: parent.slot(),
1461 leader,
1462 ancestors: Ancestors::default(),
1463 hash: RwLock::new(Hash::default()),
1464 is_delta: AtomicBool::new(false),
1465 tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
1466 signature_count: AtomicU64::new(0),
1467 hard_forks: parent.hard_forks.clone(),
1468 rewards: RwLock::new(vec![]),
1469 cluster_type: parent.cluster_type,
1470 transaction_debug_keys,
1471 transaction_log_collector_config,
1472 transaction_log_collector: Arc::new(RwLock::new(TransactionLogCollector::default())),
1473 feature_set: Arc::clone(&feature_set),
1474 reserved_account_keys: parent.reserved_account_keys.clone(),
1475 drop_callback: RwLock::new(OptionalDropCallback(
1476 parent
1477 .drop_callback
1478 .read()
1479 .unwrap()
1480 .0
1481 .as_ref()
1482 .map(|drop_callback| drop_callback.clone_box()),
1483 )),
1484 freeze_started: AtomicBool::new(false),
1485 cost_tracker: RwLock::new(parent.read_cost_tracker().unwrap().new_from_parent_limits()),
1486 accounts_data_size_initial,
1487 accounts_data_size_delta_on_chain: AtomicI64::new(0),
1488 accounts_data_size_delta_off_chain: AtomicI64::new(0),
1489 epoch_reward_status: parent.epoch_reward_status.clone(),
1490 transaction_processor,
1491 check_program_deployment_slot: false,
1492 collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
1493 compute_budget: parent.compute_budget,
1494 transaction_account_lock_limit: parent.transaction_account_lock_limit,
1495 fee_structure: parent.fee_structure.clone(),
1496 #[cfg(feature = "dev-context-only-utils")]
1497 hash_overrides: parent.hash_overrides.clone(),
1498 accounts_lt_hash: Mutex::new(parent.accounts_lt_hash.lock().unwrap().clone()),
1499 accounts_lt_hash_async_progress: AccountsLtHashAsyncProgress::new(),
1500 block_id: RwLock::new(None),
1501 expected_bank_hash: RwLock::new(None),
1502 bank_hash_stats: AtomicBankHashStats::default(),
1503 epoch_rewards_calculation_cache: parent.epoch_rewards_calculation_cache.clone(),
1504 block_component_processor: RwLock::new(BlockComponentProcessor::default()),
1505 is_alpenglow: AtomicBool::new(parent.is_alpenglow()),
1506 };
1507
1508 let (_, ancestors_time_us) = measure_us!({
1509 let mut ancestors = Vec::with_capacity(parent.ancestors.len() + 1);
1510 ancestors.push(new.slot());
1511 ancestors.extend(new.parents_iter().map(|parent| parent.slot()));
1512 new.ancestors = Ancestors::from(ancestors);
1513 });
1514
1515 let prepare_timings = new.prepare_for_block_execution(
1516 parent.epoch(),
1517 parent.slot(),
1518 parent.capitalization(),
1519 parent.block_height(),
1520 reward_calc_tracer,
1521 );
1522
1523 time.stop();
1524 report_new_bank_metrics(
1525 slot,
1526 parent.slot(),
1527 new.block_height,
1528 NewBankTimings {
1529 bank_rc_creation_time_us,
1530 total_elapsed_time_us: time.as_us(),
1531 status_cache_time_us,
1532 fee_components_time_us,
1533 blockhash_queue_time_us,
1534 stakes_cache_time_us,
1535 epoch_stakes_time_us,
1536 builtin_program_ids_time_us,
1537 executor_cache_time_us: 0,
1538 transaction_debug_keys_time_us,
1539 transaction_log_collector_config_time_us,
1540 feature_set_time_us,
1541 ancestors_time_us,
1542 update_epoch_time_us: prepare_timings.update_epoch_time_us,
1543 distribute_rewards_time_us: prepare_timings.distribute_rewards_time_us,
1544 cache_preparation_time_us: prepare_timings.cache_preparation_time_us,
1545 update_sysvars_time_us: prepare_timings.update_sysvars_time_us,
1546 fill_sysvar_cache_time_us: prepare_timings.fill_sysvar_cache_time_us,
1547 },
1548 );
1549
1550 report_loaded_programs_stats(
1551 &parent
1552 .transaction_processor
1553 .global_program_cache
1554 .read()
1555 .unwrap(),
1556 parent.slot(),
1557 );
1558
1559 new.transaction_processor
1560 .global_program_cache
1561 .write()
1562 .unwrap()
1563 .stats
1564 .reset();
1565
1566 new
1567 }
1568
1569 pub fn set_fork_graph_in_program_cache(&self, fork_graph: Weak<RwLock<BankForks>>) {
1570 self.transaction_processor
1571 .global_program_cache
1572 .write()
1573 .unwrap()
1574 .set_fork_graph(fork_graph);
1575 }
1576
1577 fn prepare_program_cache_for_upcoming_feature_set(&self) {
1578 let (_epoch, slot_index) = self.epoch_schedule.get_epoch_and_slot_index(self.slot);
1579 let slots_in_epoch = self.epoch_schedule.get_slots_in_epoch(self.epoch);
1580 let (upcoming_feature_set, _newly_activated) = self.compute_active_feature_set(true);
1581
1582 let slots_in_recompilation_phase =
1584 (solana_program_runtime::loaded_programs::MAX_LOADED_ENTRY_COUNT as u64)
1585 .min(slots_in_epoch)
1586 .checked_div(2)
1587 .unwrap();
1588
1589 let mut epoch_boundary_preparation = self
1590 .transaction_processor
1591 .epoch_boundary_preparation
1592 .write()
1593 .unwrap();
1594
1595 if let Some(upcoming_environment) = epoch_boundary_preparation.upcoming_environment.as_ref()
1596 {
1597 let upcoming_environment = upcoming_environment.clone();
1598 if let Some((key, program_to_recompile)) =
1599 epoch_boundary_preparation.programs_to_recompile.pop()
1600 {
1601 drop(epoch_boundary_preparation);
1602 self.transaction_processor
1603 .prepare_one_program_for_upcoming_feature_set(
1604 self,
1605 self.check_program_deployment_slot(),
1606 &upcoming_environment,
1607 &key,
1608 &program_to_recompile.stats,
1609 );
1610 }
1611 } else if slot_index.saturating_add(slots_in_recompilation_phase) >= slots_in_epoch {
1612 let new_environment = self.create_program_runtime_environment(&upcoming_feature_set);
1615 let mut upcoming_environment = self
1616 .transaction_processor
1617 .program_runtime_environment
1618 .clone();
1619 let changed_program_runtime_environment = *upcoming_environment != *new_environment;
1621 if changed_program_runtime_environment {
1622 upcoming_environment = new_environment;
1623 let program_cache_guard = self
1624 .transaction_processor
1625 .global_program_cache
1626 .read()
1627 .unwrap();
1628 epoch_boundary_preparation.programs_to_recompile = program_cache_guard
1629 .get_flattened_entries()
1630 .into_iter()
1631 .map(|(id, _last_modification_slot, entry)| (id, entry))
1632 .collect();
1633 epoch_boundary_preparation
1634 .programs_to_recompile
1635 .sort_by_cached_key(|(_id, program)| program.retention_score());
1636 } else {
1637 epoch_boundary_preparation.programs_to_recompile.clear();
1638 }
1639 epoch_boundary_preparation.upcoming_epoch = self.epoch.saturating_add(1);
1640 epoch_boundary_preparation.upcoming_environment = Some(upcoming_environment);
1641 }
1642 }
1643
1644 pub fn prune_program_cache(&self, bank_forks: &BankForks) {
1645 let upcoming_environment = self
1646 .transaction_processor
1647 .epoch_boundary_preparation
1648 .write()
1649 .unwrap()
1650 .reroot(self.epoch());
1651 self.transaction_processor
1652 .global_program_cache
1653 .write()
1654 .unwrap()
1655 .prune(
1656 self.slot(),
1657 upcoming_environment.map(|_| {
1658 ProgramRuntimeEnvironment::clone(
1659 &self.transaction_processor.program_runtime_environment,
1660 )
1661 }),
1662 bank_forks,
1663 );
1664 }
1665
1666 pub fn prune_program_cache_by_deployment_slot(&self, deployment_slot: Slot) {
1667 self.transaction_processor
1668 .global_program_cache
1669 .write()
1670 .unwrap()
1671 .prune_by_deployment_slot(deployment_slot);
1672 }
1673
1674 pub fn new_warmup_cooldown_rate_epoch(&self) -> Option<Epoch> {
1676 self.feature_set
1677 .new_warmup_cooldown_rate_epoch(&self.epoch_schedule)
1678 }
1679
1680 fn use_fixed_point_stake_math(&self) -> bool {
1681 self.feature_set
1682 .snapshot()
1683 .upgrade_bpf_stake_program_to_v5_1
1684 }
1685
1686 fn get_cached_vote_accounts<'a>(
1690 &'a self,
1691 rewarded_epoch: Epoch,
1692 distribution_epoch_vote_accounts: &'a VoteAccounts,
1693 ) -> CachedVoteAccounts<'a> {
1694 let snapshot_epoch_vote_accounts = self
1698 .epoch_stakes(rewarded_epoch)
1699 .map(|epoch_stakes| epoch_stakes.stakes().vote_accounts());
1700
1701 let rewarded_epoch_vote_accounts = self
1703 .epoch_stakes(self.epoch())
1704 .map(|epoch_stakes| epoch_stakes.stakes().vote_accounts());
1705
1706 CachedVoteAccounts {
1707 snapshot_epoch_vote_accounts,
1708 rewarded_epoch_vote_accounts,
1709 distribution_epoch_vote_accounts,
1710 }
1711 }
1712
1713 fn compute_new_epoch_caches_and_rewards(
1716 &self,
1717 thread_pool: &ThreadPool,
1718 rewarded_epoch: Epoch,
1719 reward_calc_tracer: Option<impl RewardCalcTracer>,
1720 rewards_metrics: &mut RewardsMetrics,
1721 ) -> NewEpochBundle {
1722 let stakes = self.stakes_cache.stakes();
1726 let stake_delegations = stakes.stake_delegations_vec();
1727 let (
1728 (
1729 stake_history,
1730 unfiltered_distribution_vote_accounts,
1731 delegated_stakes,
1732 reward_epoch_delegated_stakes,
1733 ),
1734 calculate_activated_stake_time_us,
1735 ) = measure_us!(stakes.calculate_activated_stake(
1736 self.epoch(),
1737 thread_pool,
1738 self.new_warmup_cooldown_rate_epoch(),
1739 &stake_delegations,
1740 self.use_fixed_point_stake_math(),
1741 ));
1742 debug_assert_eq!(reward_epoch_delegated_stakes.epoch, rewarded_epoch);
1743
1744 let filtered_distribution_vote_accounts =
1747 if self.feature_set.snapshot().validator_admission_ticket {
1748 unfiltered_distribution_vote_accounts.clone_and_filter_for_vat(
1749 MAX_ALPENGLOW_VOTE_ACCOUNTS,
1750 self.minimum_vote_account_balance_for_vat(),
1751 )
1752 } else {
1753 unfiltered_distribution_vote_accounts.clone()
1754 };
1755 if AlpenglowEpochType::is_alpenglow_or_migration_epoch(self, rewarded_epoch) {
1756 assert!(
1757 self.feature_set.snapshot().validator_admission_ticket,
1758 "Alpenglow should not be activated before the VAT"
1759 );
1760 reward_epoch_delegated_stakes.set(self, &filtered_distribution_vote_accounts);
1761 }
1762 let cached_vote_accounts =
1763 self.get_cached_vote_accounts(rewarded_epoch, &filtered_distribution_vote_accounts);
1764 let (rewards_calculation, update_rewards_with_thread_pool_time_us) =
1765 measure_us!(self.calculate_rewards(
1766 &stake_history,
1767 stake_delegations,
1768 cached_vote_accounts,
1769 rewarded_epoch,
1770 reward_epoch_delegated_stakes,
1771 reward_calc_tracer,
1772 thread_pool,
1773 rewards_metrics,
1774 ));
1775 NewEpochBundle {
1776 stake_history,
1777 unfiltered_distribution_vote_accounts,
1778 delegated_stakes,
1779 filtered_distribution_vote_accounts,
1780 rewards_calculation,
1781 calculate_activated_stake_time_us,
1782 update_rewards_with_thread_pool_time_us,
1783 }
1784 }
1785
1786 fn process_new_epoch(
1788 &mut self,
1789 parent_epoch: Epoch,
1790 parent_slot: Slot,
1791 parent_capitalization: u64,
1792 parent_height: u64,
1793 reward_calc_tracer: Option<impl RewardCalcTracer>,
1794 ) {
1795 let epoch = self.epoch();
1796 let slot = self.slot();
1797 let thread_pool = rewards_calculation_thread_pool();
1798
1799 let (_, apply_feature_activations_time_us) = measure_us!(
1800 thread_pool.install(|| { self.compute_and_apply_new_feature_activations() })
1801 );
1802
1803 let mut rewards_metrics = RewardsMetrics::default();
1804 let NewEpochBundle {
1805 stake_history,
1806 unfiltered_distribution_vote_accounts,
1807 delegated_stakes,
1808 filtered_distribution_vote_accounts,
1809 rewards_calculation,
1810 calculate_activated_stake_time_us,
1811 update_rewards_with_thread_pool_time_us,
1812 } = self.compute_new_epoch_caches_and_rewards(
1813 thread_pool,
1814 parent_epoch,
1815 reward_calc_tracer,
1816 &mut rewards_metrics,
1817 );
1818
1819 self.stakes_cache.activate_epoch(
1820 epoch,
1821 stake_history,
1822 unfiltered_distribution_vote_accounts,
1823 delegated_stakes,
1824 );
1825
1826 let leader_schedule_epoch = self.epoch_schedule.get_leader_schedule_epoch(slot);
1828 let (_, update_epoch_stakes_time_us) = measure_us!(self.update_epoch_stakes(
1829 leader_schedule_epoch,
1830 Some(filtered_distribution_vote_accounts),
1831 ));
1832
1833 let (epoch_rewards, begin_partitioned_rewards_time_us) =
1836 measure_us!(self.begin_partitioned_rewards(
1837 parent_epoch,
1838 parent_slot,
1839 parent_height,
1840 &rewards_calculation,
1841 &mut rewards_metrics,
1842 thread_pool,
1843 ));
1844
1845 if self.feature_set.snapshot().alpenglow {
1848 let epoch_start_capitalization = parent_capitalization;
1849 EpochInflationAccountState::new_epoch_update_account(
1850 self,
1851 epoch_start_capitalization,
1852 epoch_rewards,
1853 );
1854 }
1855
1856 report_new_epoch_metrics(
1857 epoch,
1858 slot,
1859 parent_slot,
1860 NewEpochTimings {
1861 apply_feature_activations_time_us,
1862 calculate_activated_stake_time_us,
1863 update_epoch_stakes_time_us,
1864 update_rewards_with_thread_pool_time_us,
1865 begin_partitioned_rewards_time_us,
1866 },
1867 rewards_metrics,
1868 );
1869
1870 let program_runtime_environment =
1871 self.create_program_runtime_environment(&self.feature_set);
1872 self.transaction_processor
1873 .set_program_runtime_environment(program_runtime_environment);
1874 }
1875
1876 pub fn proper_ancestors_set(&self) -> HashSet<Slot> {
1877 HashSet::from_iter(self.proper_ancestors())
1878 }
1879
1880 pub(crate) fn proper_ancestors(&self) -> impl Iterator<Item = Slot> + '_ {
1882 self.ancestors
1883 .keys()
1884 .into_iter()
1885 .filter(move |slot| *slot != self.slot)
1886 }
1887
1888 pub fn set_callback(&self, callback: Option<Box<dyn DropCallback + Send + Sync>>) {
1889 *self.drop_callback.write().unwrap() = OptionalDropCallback(callback);
1890 }
1891
1892 pub fn vote_only_bank(&self) -> bool {
1893 self.vote_only_bank
1894 }
1895
1896 pub fn warp_from_parent(parent: Arc<Bank>, leader: SlotLeader, slot: Slot) -> Self {
1902 parent.freeze();
1903 let parent_timestamp = parent.clock().unix_timestamp;
1904 let mut new = Bank::new_from_parent(parent, leader, slot);
1905 new.update_epoch_stakes(new.epoch_schedule().get_epoch(slot), None);
1906 new.tick_height.store(new.max_tick_height(), Relaxed);
1907
1908 let mut clock = new.clock();
1909 clock.epoch_start_timestamp = parent_timestamp;
1910 clock.unix_timestamp = parent_timestamp;
1911 new.update_sysvar_account(&sysvar::clock::id(), |account| {
1912 create_account(
1913 &clock,
1914 new.inherit_specially_retained_account_fields(account),
1915 )
1916 });
1917 new.transaction_processor
1918 .fill_missing_sysvar_cache_entries(&new);
1919 new.freeze();
1920 new
1921 }
1922
1923 fn load_rent_from_account_for_snapshot_load(
1924 accounts: &Accounts,
1925 ancestors: &Ancestors,
1926 ) -> Rent {
1927 let rent_sysvar = accounts
1930 .load_with_fixed_root_do_not_populate_read_cache(ancestors, &sysvar::rent::id())
1931 .expect("snapshot must contain rent sysvar account")
1932 .0;
1933 from_account::<sysvar::rent::Rent, _>(&rent_sysvar)
1934 .expect("snapshot must contain well-formed rent sysvar account")
1935 }
1936
1937 fn prepare_for_block_execution(
1942 &mut self,
1943 parent_epoch: Epoch,
1944 parent_slot: Slot,
1945 parent_capitalization: u64,
1946 parent_block_height: u64,
1947 reward_calc_tracer: Option<impl RewardCalcTracer>,
1948 ) -> PrepareBlockExecutionStats {
1949 let slot = self.slot;
1950
1951 let (_, update_epoch_time_us) = measure_us!({
1953 if parent_epoch < self.epoch() {
1954 self.process_new_epoch(
1955 parent_epoch,
1956 parent_slot,
1957 parent_capitalization,
1958 parent_block_height,
1959 reward_calc_tracer,
1960 );
1961 } else {
1962 let leader_schedule_epoch = self.epoch_schedule().get_leader_schedule_epoch(slot);
1964 self.update_epoch_stakes(leader_schedule_epoch, None);
1965 }
1966 });
1967
1968 let (_, distribute_rewards_time_us) =
1969 measure_us!(self.distribute_partitioned_epoch_rewards());
1970
1971 let (_, cache_preparation_time_us) =
1972 measure_us!(self.prepare_program_cache_for_upcoming_feature_set());
1973
1974 let (_, update_sysvars_time_us) = measure_us!({
1976 self.update_slot_hashes();
1977 self.update_stake_history(Some(parent_epoch));
1978
1979 if self.is_alpenglow() {
1980 self.update_clock_slot_for_alpenglow();
1983 } else {
1984 self.update_clock(Some(parent_epoch));
1988 }
1989 self.update_last_restart_slot()
1990 });
1991
1992 let (_, fill_sysvar_cache_time_us) = measure_us!(
1993 self.transaction_processor
1994 .fill_missing_sysvar_cache_entries(self)
1995 );
1996
1997 PrepareBlockExecutionStats {
1998 update_epoch_time_us,
1999 distribute_rewards_time_us,
2000 cache_preparation_time_us,
2001 update_sysvars_time_us,
2002 fill_sysvar_cache_time_us,
2003 }
2004 }
2005
2006 pub(crate) fn new_from_snapshot(
2008 bank_rc: BankRc,
2009 genesis_config: &GenesisConfig,
2010 runtime_config: Arc<RuntimeConfig>,
2011 fields: BankFieldsToDeserialize,
2012 leader_for_tests: Option<SlotLeader>,
2013 debug_keys: Option<Arc<HashSet<Pubkey>>>,
2014 accounts_data_size_initial: u64,
2015 epoch_stakes: HashMap<Epoch, VersionedEpochStakes>,
2016 ) -> Self {
2017 let now = Instant::now();
2018 let slot = fields.slot;
2019 let epoch = fields.epoch_schedule.get_epoch(slot);
2020 let ancestors = Ancestors::from(vec![slot]);
2021 let rewards_calculation_thread_pool = rewards_calculation_thread_pool();
2024 let (stakes, stakes_time) = measure_time!(
2035 Stakes::load_from_deserialized_delegations(fields.stakes, |pubkey| {
2036 let (account, _slot) = bank_rc
2037 .accounts
2038 .load_with_fixed_root_do_not_populate_read_cache(&ancestors, pubkey)?;
2039 Some(account)
2040 })
2041 .expect(
2042 "Stakes cache is inconsistent with accounts-db. This can indicate a corrupted \
2043 snapshot or bugs in cached accounts or accounts-db.",
2044 )
2045 );
2046 info!("Loading Stakes took: {stakes_time}");
2047 assert!(
2048 fields.versioned_epoch_stakes.is_empty(),
2049 "should be already converted and passed in epoch_stakes parameter"
2050 );
2051 assert!(
2052 !epoch_stakes.is_empty(),
2053 "should be populated (from fields.versioned_epoch_stakes)"
2054 );
2055
2056 let compute_leader = || {
2058 if slot == 0 {
2059 stakes
2062 .highest_staked_node()
2063 .expect("genesis snapshot should contain at least one staked vote account")
2064 } else {
2065 Self::slot_leader_from_epoch_stakes(
2066 fields.slot,
2067 &fields.epoch_schedule,
2068 &epoch_stakes,
2069 )
2070 }
2071 };
2072 #[cfg(not(feature = "dev-context-only-utils"))]
2073 let leader = {
2074 _ = leader_for_tests;
2075 compute_leader()
2076 };
2077 #[cfg(feature = "dev-context-only-utils")]
2078 let leader = leader_for_tests.unwrap_or_else(compute_leader);
2079 assert_eq!(
2080 fields.leader_id, leader.id,
2081 "snapshot leader_id does not match computed slot leader"
2082 );
2083
2084 let stakes_accounts_load_duration = now.elapsed();
2085 let rent = Self::load_rent_from_account_for_snapshot_load(&bank_rc.accounts, &ancestors);
2086 let partitioned_rewards_stake_account_stores_per_block = bank_rc
2087 .accounts
2088 .accounts_db
2089 .partitioned_epoch_rewards_config
2090 .stake_account_stores_per_block;
2091 let mut bank = Self {
2092 rc: bank_rc,
2093 status_cache: Arc::<RwLock<BankStatusCache>>::default(),
2094 blockhash_queue: RwLock::new(fields.blockhash_queue),
2095 max_processing_age: MAX_PROCESSING_AGE,
2096 partitioned_rewards_stake_account_stores_per_block,
2097 ancestors,
2098 hash: RwLock::new(fields.hash),
2099 parent_hash: fields.parent_hash,
2100 parent_slot: fields.parent_slot,
2101 hard_forks: Arc::new(RwLock::new(fields.hard_forks)),
2102 transaction_count: AtomicU64::new(fields.transaction_count),
2103 non_vote_transaction_count_since_restart: AtomicU64::default(),
2104 transaction_error_count: AtomicU64::default(),
2105 transaction_entries_count: AtomicU64::default(),
2106 transactions_per_entry_max: AtomicU64::default(),
2107 entry_bytes_consumed: EntryBytesBudget::new(DEFAULT_MAX_ENTRY_BYTES_PER_SLOT),
2108 tick_height: AtomicU64::new(fields.tick_height),
2109 signature_count: AtomicU64::new(fields.signature_count),
2110 capitalization: AtomicU64::new(fields.capitalization),
2111 max_tick_height: fields.max_tick_height,
2112 hashes_per_tick: RwLock::new(fields.hashes_per_tick),
2113 ticks_per_slot: fields.ticks_per_slot,
2114 ns_per_slot: fields.ns_per_slot,
2115 genesis_creation_time: fields.genesis_creation_time,
2116 slots_per_year: fields.slots_per_year,
2117 slot_params: SlotParamsArchive::default(),
2118 slot,
2119 bank_id: 0,
2120 epoch,
2121 block_height: fields.block_height,
2122 leader,
2123 fee_rate_governor: fields.fee_rate_governor,
2124 rent_collector: RentCollector::new(
2125 epoch,
2126 fields.epoch_schedule.clone(),
2127 fields.slots_per_year,
2128 rent,
2129 ),
2130 epoch_schedule: fields.epoch_schedule,
2131 inflation: Arc::new(RwLock::new(fields.inflation)),
2132 stakes_cache: StakesCache::new(stakes),
2133 epoch_stakes,
2134 is_delta: AtomicBool::new(fields.is_delta),
2135 rewards: RwLock::new(vec![]),
2136 cluster_type: Some(genesis_config.cluster_type),
2137 transaction_debug_keys: debug_keys,
2138 transaction_log_collector_config: Arc::<RwLock<TransactionLogCollectorConfig>>::default(
2139 ),
2140 transaction_log_collector: Arc::<RwLock<TransactionLogCollector>>::default(),
2141 feature_set: Arc::<FeatureSet>::default(),
2142 reserved_account_keys: Arc::<ReservedAccountKeys>::default(),
2143 drop_callback: RwLock::new(OptionalDropCallback(None)),
2144 freeze_started: AtomicBool::new(fields.hash != Hash::default()),
2145 vote_only_bank: false,
2146 cost_tracker: RwLock::new(CostTracker::default()),
2147 accounts_data_size_initial,
2148 accounts_data_size_delta_on_chain: AtomicI64::new(0),
2149 accounts_data_size_delta_off_chain: AtomicI64::new(0),
2150 epoch_reward_status: EpochRewardStatus::default(),
2151 transaction_processor: TransactionBatchProcessor::default(),
2152 check_program_deployment_slot: false,
2153 collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
2155 compute_budget: runtime_config.compute_budget,
2156 transaction_account_lock_limit: runtime_config.transaction_account_lock_limit,
2157 fee_structure: FeeStructure::default(),
2158 #[cfg(feature = "dev-context-only-utils")]
2159 hash_overrides: Arc::new(Mutex::new(HashOverrides::default())),
2160 accounts_lt_hash: Mutex::new(fields.accounts_lt_hash),
2161 accounts_lt_hash_async_progress: AccountsLtHashAsyncProgress::new(),
2162 block_id: RwLock::new(fields.block_id),
2163 bank_hash_stats: AtomicBankHashStats::new(&fields.bank_hash_stats),
2164 epoch_rewards_calculation_cache: Arc::new(Mutex::new(HashMap::default())),
2165 expected_bank_hash: RwLock::new(None),
2166 block_component_processor: RwLock::new(BlockComponentProcessor::default()),
2167 is_alpenglow: AtomicBool::new(false),
2168 };
2169
2170 if bank.get_alpenglow_genesis_certificate().is_some() {
2171 bank.set_is_alpenglow();
2172 }
2173
2174 assert_eq!(
2179 bank.genesis_creation_time, genesis_config.creation_time,
2180 "Bank snapshot genesis creation time does not match genesis.bin creation time. The \
2181 snapshot and genesis.bin might pertain to different clusters"
2182 );
2183 assert_eq!(bank.ticks_per_slot, genesis_config.ticks_per_slot);
2184 assert_eq!(bank.max_tick_height, (bank.slot + 1) * bank.ticks_per_slot);
2185 assert_eq!(bank.epoch_schedule, genesis_config.epoch_schedule);
2186
2187 bank.refresh_slot_params_from_snapshot(genesis_config);
2188 bank.initialize_after_snapshot_restore(|| rewards_calculation_thread_pool);
2189
2190 datapoint_info!(
2191 "bank-new-from-fields",
2192 (
2193 "accounts_data_len-from-snapshot",
2194 fields.accounts_data_len as i64,
2195 i64
2196 ),
2197 (
2198 "accounts_data_len-from-generate_index",
2199 accounts_data_size_initial as i64,
2200 i64
2201 ),
2202 (
2203 "stakes_accounts_load_duration_us",
2204 stakes_accounts_load_duration.as_micros(),
2205 i64
2206 ),
2207 );
2208 bank
2209 }
2210
2211 fn slot_leader_from_epoch_stakes(
2213 slot: Slot,
2214 epoch_schedule: &EpochSchedule,
2215 epoch_stakes: &HashMap<Epoch, VersionedEpochStakes>,
2216 ) -> SlotLeader {
2217 let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(slot);
2218 let epoch_vote_accounts = epoch_stakes
2219 .get(&epoch)
2220 .expect("epoch stakes should contain current epoch")
2221 .stakes()
2222 .vote_accounts();
2223 let leader_schedule =
2224 leader_schedule_from_vote_accounts(epoch, epoch_schedule, epoch_vote_accounts.as_ref())
2225 .expect("leader schedule should be computable from epoch stakes");
2226 leader_schedule.get_slot_leader_at_index(slot_index as usize)
2227 }
2228
2229 pub(crate) fn get_fields_to_serialize(&self) -> BankFieldsToSerialize {
2231 BankFieldsToSerialize {
2232 blockhash_queue: self.blockhash_queue.read().unwrap().clone(),
2233 hash: *self.hash.read().unwrap(),
2234 parent_hash: self.parent_hash,
2235 parent_slot: self.parent_slot,
2236 hard_forks: self.hard_forks.read().unwrap().clone(),
2237 transaction_count: self.transaction_count.load(Relaxed),
2238 tick_height: self.tick_height.load(Relaxed),
2239 signature_count: self.signature_count.load(Relaxed),
2240 capitalization: self.capitalization.load(Relaxed),
2241 max_tick_height: self.max_tick_height,
2242 hashes_per_tick: *self.hashes_per_tick.read().unwrap(),
2243 ticks_per_slot: self.ticks_per_slot,
2244 ns_per_slot: self.ns_per_slot,
2245 genesis_creation_time: self.genesis_creation_time,
2246 slots_per_year: self.slots_per_year,
2247 slot: self.slot,
2248 block_height: self.block_height,
2249 leader_id: self.leader.id,
2250 fee_rate_governor: self.fee_rate_governor.clone(),
2251 epoch_schedule: self.epoch_schedule.clone(),
2252 inflation: *self.inflation.read().unwrap(),
2253 stakes: self.stakes_cache.stakes().clone(),
2254 is_delta: self.is_delta.load(Relaxed),
2255 accounts_data_len: self.load_accounts_data_size(),
2256 versioned_epoch_stakes: self.epoch_stakes.clone(),
2257 accounts_lt_hash: self.accounts_lt_hash.lock().unwrap().clone(),
2258 block_id: self.block_id().expect("block id must be set"),
2259 }
2260 }
2261
2262 pub fn leader(&self) -> &SlotLeader {
2263 &self.leader
2264 }
2265
2266 pub fn leader_id(&self) -> &Pubkey {
2267 &self.leader.id
2268 }
2269
2270 pub fn genesis_creation_time(&self) -> UnixTimestamp {
2271 self.genesis_creation_time
2272 }
2273
2274 pub fn slot(&self) -> Slot {
2275 self.slot
2276 }
2277
2278 pub fn bank_id(&self) -> BankId {
2279 self.bank_id
2280 }
2281
2282 pub fn epoch(&self) -> Epoch {
2283 self.epoch
2284 }
2285
2286 pub fn first_normal_epoch(&self) -> Epoch {
2287 self.epoch_schedule().first_normal_epoch
2288 }
2289
2290 pub fn freeze_lock(&self) -> RwLockReadGuard<'_, Hash> {
2291 self.hash.read().unwrap()
2292 }
2293
2294 pub fn wait_for_inflight_commits(&self) {
2301 drop(self.hash.write().unwrap());
2302 }
2303
2304 pub fn hash(&self) -> Hash {
2305 *self.hash.read().unwrap()
2306 }
2307
2308 pub fn is_frozen(&self) -> bool {
2309 *self.hash.read().unwrap() != Hash::default()
2310 }
2311
2312 pub fn freeze_started(&self) -> bool {
2313 self.freeze_started.load(Relaxed)
2314 }
2315
2316 pub fn status_cache_ancestors(&self) -> Vec<u64> {
2317 let (min, mut ancestors) = {
2318 let status_cache = self.status_cache.read().unwrap();
2319 let roots = status_cache.roots();
2320 let mut ancestors = Vec::with_capacity(roots.len() + self.ancestors.len());
2321 let mut min = Slot::MAX;
2322 for root in roots {
2323 ancestors.push(*root);
2324 min = min.min(*root);
2325 }
2326 (if roots.is_empty() { 0 } else { min }, ancestors)
2327 };
2328
2329 ancestors.extend(self.ancestors.iter().filter(|ancestor| *ancestor >= min));
2330 ancestors.sort_unstable();
2331 ancestors.dedup();
2332 ancestors
2333 }
2334
2335 pub fn unix_timestamp_from_genesis(&self) -> i64 {
2337 self.genesis_creation_time.saturating_add(
2338 (self.slot as u128)
2339 .saturating_mul(self.ns_per_slot)
2340 .saturating_div(1_000_000_000) as i64,
2341 )
2342 }
2343
2344 pub fn epoch_stakes_from_slot(&self, slot: Slot) -> Option<&VersionedEpochStakes> {
2346 let epoch = self.epoch_schedule().get_epoch(slot);
2347 self.epoch_stakes(epoch)
2348 }
2349
2350 pub fn get_rank_map(&self, slot: Slot) -> Option<&Arc<BLSPubkeyToRankMap>> {
2352 self.epoch_stakes_from_slot(slot)
2353 .map(|stake| stake.bls_pubkey_to_rank_map())
2354 }
2355
2356 fn update_sysvar_account<F>(&self, pubkey: &Pubkey, updater: F)
2357 where
2358 F: Fn(&Option<AccountSharedData>) -> AccountSharedData,
2359 {
2360 let old_account = self.get_account_with_fixed_root(pubkey);
2361 let mut new_account = updater(&old_account);
2362
2363 self.adjust_sysvar_balance_for_rent(&mut new_account);
2369 self.store_account_and_update_capitalization(pubkey, &new_account);
2370 }
2371
2372 fn inherit_specially_retained_account_fields(
2373 &self,
2374 old_account: &Option<AccountSharedData>,
2375 ) -> InheritableAccountFields {
2376 const RENT_UNADJUSTED_INITIAL_BALANCE: u64 = 1;
2377
2378 (
2379 old_account
2380 .as_ref()
2381 .map(|a| a.lamports())
2382 .unwrap_or(RENT_UNADJUSTED_INITIAL_BALANCE),
2383 old_account
2384 .as_ref()
2385 .map(|a| a.rent_epoch())
2386 .unwrap_or(INITIAL_RENT_EPOCH),
2387 )
2388 }
2389
2390 pub fn clock(&self) -> sysvar::clock::Clock {
2391 from_account(&self.get_account(&sysvar::clock::id()).unwrap_or_default())
2392 .unwrap_or_default()
2393 }
2394
2395 fn update_clock(&self, parent_epoch: Option<Epoch>) {
2396 let mut unix_timestamp = self.clock().unix_timestamp;
2397 let epoch_start_timestamp = {
2399 let epoch = if let Some(epoch) = parent_epoch {
2400 epoch
2401 } else {
2402 self.epoch()
2403 };
2404 let first_slot_in_epoch = self.epoch_schedule().get_first_slot_in_epoch(epoch);
2405 Some((first_slot_in_epoch, self.clock().epoch_start_timestamp))
2406 };
2407 let max_allowable_drift = MaxAllowableDrift {
2408 fast: MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST,
2409 slow: MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW_V2,
2410 };
2411
2412 let ancestor_timestamp = self.clock().unix_timestamp;
2413 if let Some(timestamp_estimate) =
2414 self.get_timestamp_estimate(max_allowable_drift, epoch_start_timestamp)
2415 {
2416 unix_timestamp = timestamp_estimate;
2417 if timestamp_estimate < ancestor_timestamp {
2418 unix_timestamp = ancestor_timestamp;
2419 }
2420 }
2421 datapoint_info!(
2422 "bank-timestamp-correction",
2423 ("slot", self.slot(), i64),
2424 ("from_genesis", self.unix_timestamp_from_genesis(), i64),
2425 ("corrected", unix_timestamp, i64),
2426 ("ancestor_timestamp", ancestor_timestamp, i64),
2427 );
2428 let mut epoch_start_timestamp =
2429 if parent_epoch.is_some() && parent_epoch.unwrap() != self.epoch() {
2431 unix_timestamp
2432 } else {
2433 self.clock().epoch_start_timestamp
2434 };
2435 if self.slot == 0 {
2436 unix_timestamp = self.unix_timestamp_from_genesis();
2437 epoch_start_timestamp = self.unix_timestamp_from_genesis();
2438 }
2439 let clock = sysvar::clock::Clock {
2440 slot: self.slot,
2441 epoch_start_timestamp,
2442 epoch: self.epoch_schedule().get_epoch(self.slot),
2443 leader_schedule_epoch: self.epoch_schedule().get_leader_schedule_epoch(self.slot),
2444 unix_timestamp,
2445 };
2446 self.update_sysvar_account(&sysvar::clock::id(), |account| {
2447 create_account(
2448 &clock,
2449 self.inherit_specially_retained_account_fields(account),
2450 )
2451 });
2452 }
2453
2454 fn update_clock_slot_for_alpenglow(&self) {
2463 let clock = self.clock();
2464 let clock = sysvar::clock::Clock {
2465 slot: self.slot,
2466 epoch: self.epoch_schedule().get_epoch(self.slot),
2467 leader_schedule_epoch: self.epoch_schedule().get_leader_schedule_epoch(self.slot),
2468 epoch_start_timestamp: clock.epoch_start_timestamp,
2469 unix_timestamp: clock.unix_timestamp,
2470 };
2471 self.update_sysvar_account(&sysvar::clock::id(), |account| {
2472 create_account(
2473 &clock,
2474 self.inherit_specially_retained_account_fields(account),
2475 )
2476 });
2477 }
2478
2479 pub fn update_last_restart_slot(&self) {
2480 let current_last_restart_slot = self
2482 .get_account(&sysvar::last_restart_slot::id())
2483 .and_then(|account| {
2484 let lrs: Option<LastRestartSlot> = from_account(&account);
2485 lrs
2486 })
2487 .map(|account| account.last_restart_slot);
2488
2489 let last_restart_slot = {
2490 let slot = self.slot;
2491 let hard_forks_r = self.hard_forks.read().unwrap();
2492
2493 hard_forks_r
2496 .iter()
2497 .rev()
2498 .find(|(hard_fork, _)| *hard_fork <= slot)
2499 .map(|(slot, _)| *slot)
2500 .unwrap_or(0)
2501 };
2502
2503 if current_last_restart_slot != Some(last_restart_slot) {
2505 self.update_sysvar_account(&sysvar::last_restart_slot::id(), |account| {
2506 create_account(
2507 &LastRestartSlot { last_restart_slot },
2508 self.inherit_specially_retained_account_fields(account),
2509 )
2510 });
2511 }
2512 }
2513
2514 pub fn set_sysvar_for_tests<T>(&self, sysvar: &T)
2515 where
2516 T: SysvarSerialize + SysvarId,
2517 {
2518 self.update_sysvar_account(&T::id(), |account| {
2519 create_account(
2520 sysvar,
2521 self.inherit_specially_retained_account_fields(account),
2522 )
2523 });
2524 self.transaction_processor
2527 .reset_and_fill_sysvar_cache_entries(self);
2528 }
2529
2530 fn update_slot_history(&self) {
2531 self.update_sysvar_account(&sysvar::slot_history::id(), |account| {
2532 let mut slot_history = account
2533 .as_ref()
2534 .map(|account| wincode::deserialize::<SlotHistory>(account.data()).unwrap())
2535 .unwrap_or_default();
2536 slot_history.add(self.slot());
2537 create_account(
2538 &slot_history,
2539 self.inherit_specially_retained_account_fields(account),
2540 )
2541 });
2542 }
2543
2544 fn update_slot_hashes(&self) {
2545 self.update_sysvar_account(&sysvar::slot_hashes::id(), |account| {
2546 let mut slot_hashes = account
2547 .as_ref()
2548 .map(|account| wincode::deserialize::<SlotHashes>(account.data()).unwrap())
2549 .unwrap_or_default();
2550 slot_hashes.add(self.parent_slot, self.parent_hash);
2551 create_account(
2552 &slot_hashes,
2553 self.inherit_specially_retained_account_fields(account),
2554 )
2555 });
2556 }
2557
2558 pub fn get_slot_history(&self) -> Option<SlotHistory> {
2559 wincode::deserialize::<SlotHistory>(self.get_account(&sysvar::slot_history::id())?.data())
2560 .ok()
2561 }
2562
2563 fn update_epoch_stakes(
2564 &mut self,
2565 leader_schedule_epoch: Epoch,
2566 prefiltered_distribution_vote_accounts: Option<VoteAccounts>,
2567 ) {
2568 if !self.epoch_stakes.contains_key(&leader_schedule_epoch) {
2572 self.epoch_stakes.retain(|&epoch, _| {
2573 epoch >= leader_schedule_epoch.saturating_sub(MAX_LEADER_SCHEDULE_STAKES - 1)
2576 });
2577 let stakes = match prefiltered_distribution_vote_accounts {
2583 Some(prefiltered) => Stakes::new(prefiltered, self.epoch()),
2584 None => self.get_top_epoch_stakes(),
2585 };
2586 let stakes = SerdeStakesToStakeFormat::from(stakes);
2587 let new_epoch_stakes = VersionedEpochStakes::new(stakes, leader_schedule_epoch);
2588 info!(
2589 "new epoch stakes, epoch: {}, total_stake: {}",
2590 leader_schedule_epoch,
2591 new_epoch_stakes.total_stake(),
2592 );
2593
2594 self.maybe_burn_vat_from_staked_accounts(&new_epoch_stakes);
2595
2596 if log::log_enabled!(log::Level::Trace) {
2599 let vote_stakes: HashMap<_, _> = self
2600 .stakes_cache
2601 .stakes()
2602 .vote_accounts()
2603 .delegated_stakes()
2604 .map(|(pubkey, stake)| (*pubkey, stake))
2605 .collect();
2606 trace!("new epoch stakes, stakes: {vote_stakes:#?}");
2607 }
2608 self.epoch_stakes
2609 .insert(leader_schedule_epoch, new_epoch_stakes);
2610 }
2611 }
2612
2613 fn maybe_burn_vat_from_staked_accounts(&mut self, epoch_stakes: &VersionedEpochStakes) {
2619 let feature_snapshot = self.feature_set.snapshot();
2621 if !feature_snapshot.alpenglow || !feature_snapshot.validator_admission_ticket {
2622 return;
2623 }
2624
2625 let vat_to_burn_per_epoch = self.vat_to_burn_per_epoch();
2626 let vote_accounts = epoch_stakes.stakes().vote_accounts();
2627 debug_assert!(vote_accounts.len() <= 2000);
2628 let mut accounts_to_store: Vec<(Pubkey, AccountSharedData)> =
2630 Vec::with_capacity(vote_accounts.len() + 1);
2631 let mut total_vat = 0u64;
2632
2633 for (vote_pubkey, _stake) in vote_accounts.delegated_stakes() {
2636 let mut account = self.get_account(vote_pubkey).unwrap();
2637 total_vat += vat_to_burn_per_epoch;
2638 account.set_lamports(
2639 account
2640 .lamports()
2641 .checked_sub(vat_to_burn_per_epoch)
2642 .expect(
2643 "Vote accounts should have already been filtered to contain enough \
2644 balance for the VAT",
2645 ),
2646 );
2647 accounts_to_store.push((*vote_pubkey, account));
2648 }
2649
2650 let mut incinerator_account = self.get_account(&incinerator::id()).unwrap_or_default();
2652 incinerator_account.set_lamports(
2653 incinerator_account
2654 .lamports()
2655 .checked_add(total_vat)
2656 .unwrap(),
2657 );
2658 accounts_to_store.push((incinerator::id(), incinerator_account));
2659
2660 self.store_accounts((self.slot, accounts_to_store.as_slice()), None);
2661 info!(
2662 "Transferred total VAT of {total_vat} lamports to incinerator from staked vote \
2663 accounts"
2664 );
2665 }
2666
2667 #[cfg(feature = "dev-context-only-utils")]
2668 pub fn set_epoch_stakes_for_test(&mut self, epoch: Epoch, stakes: VersionedEpochStakes) {
2669 self.epoch_stakes.insert(epoch, stakes);
2670 }
2671
2672 fn update_rent(&self) {
2673 self.update_sysvar_account(&sysvar::rent::id(), |account| {
2674 create_account(
2675 &self.rent_collector.rent,
2676 self.inherit_specially_retained_account_fields(account),
2677 )
2678 });
2679 }
2680
2681 fn update_epoch_schedule(&self) {
2682 self.update_sysvar_account(&sysvar::epoch_schedule::id(), |account| {
2683 create_account(
2684 self.epoch_schedule(),
2685 self.inherit_specially_retained_account_fields(account),
2686 )
2687 });
2688 }
2689
2690 fn update_stake_history(&self, epoch: Option<Epoch>) {
2691 if epoch == Some(self.epoch()) {
2692 return;
2693 }
2694 self.update_sysvar_account(&stake_history::id(), |account| {
2696 create_stake_history_account(
2697 self.stakes_cache.stakes().history(),
2698 self.inherit_specially_retained_account_fields(account),
2699 )
2700 });
2701 }
2702
2703 fn refresh_slot_params(&mut self) {
2705 self.refresh_slot_params_with_baseline(self.slot_params.baseline_params());
2706 }
2707
2708 fn refresh_slot_params_from_snapshot(&mut self, genesis_config: &GenesisConfig) {
2709 let (feature_set, _) = self.compute_active_feature_set(false);
2710 self.refresh_slot_params_with_baseline(
2711 self.snapshot_restore_slot_params_baseline(genesis_config, &feature_set),
2712 );
2713 }
2714
2715 fn refresh_slot_params_with_baseline(&mut self, baseline_params: SlotParams) {
2720 self.slot_params =
2721 SlotParamsArchive::new(&self.feature_set, &self.epoch_schedule, baseline_params);
2722 }
2723
2724 fn genesis_config_slot_params(
2726 genesis_config: &GenesisConfig,
2727 partitioned_rewards_stake_account_stores_per_block: u64,
2728 ) -> SlotParams {
2729 SlotParams::genesis_baseline(
2730 genesis_config.ns_per_slot(),
2731 genesis_config.slots_per_year(),
2732 genesis_config.hashes_per_tick(),
2733 partitioned_rewards_stake_account_stores_per_block,
2734 )
2735 }
2736
2737 fn restored_bank_slot_params(&self) -> SlotParams {
2743 SlotParams::genesis_baseline(
2744 self.ns_per_slot,
2745 self.slots_per_year,
2746 self.hashes_per_tick(),
2747 self.partitioned_rewards_stake_account_stores_per_block,
2748 )
2749 }
2750
2751 fn any_slot_time_reduction_effective(
2756 &self,
2757 feature_set: &FeatureSet,
2758 ns_per_slot: u128,
2759 ) -> bool {
2760 SlotParamsArchive::any_slot_time_reduction_effective(
2761 &self.epoch_schedule,
2762 self.slot,
2763 feature_set,
2764 ns_per_slot,
2765 )
2766 }
2767
2768 fn snapshot_restore_slot_params_baseline(
2776 &self,
2777 genesis_config: &GenesisConfig,
2778 feature_set: &FeatureSet,
2779 ) -> SlotParams {
2780 if self.any_slot_time_reduction_effective(feature_set, genesis_config.ns_per_slot()) {
2781 Self::genesis_config_slot_params(
2782 genesis_config,
2783 self.partitioned_rewards_stake_account_stores_per_block,
2784 )
2785 } else {
2786 self.restored_bank_slot_params()
2790 }
2791 }
2792
2793 fn slot_params_at_slot(&self, slot: Slot) -> SlotParams {
2795 self.slot_params.params_at_slot(slot)
2796 }
2797
2798 fn current_slot_params(&self) -> SlotParams {
2800 self.slot_params_at_slot(self.slot)
2801 }
2802
2803 pub(crate) fn vat_to_burn_per_epoch(&self) -> u64 {
2805 self.current_slot_params().vat_to_burn_per_epoch()
2806 }
2807
2808 pub fn get_vat_health_for_next_epoch(
2809 &self,
2810 vote_account_pubkey: &Pubkey,
2811 ) -> std::result::Result<(), VATHealthError> {
2812 let vote_accounts = self.vote_accounts();
2813
2814 let Some((_, vote_account)) = vote_accounts.get(vote_account_pubkey) else {
2815 return Err(VATHealthError::VoteAccountNotFound);
2816 };
2817
2818 if vote_account
2819 .vote_state_view()
2820 .bls_pubkey_compressed()
2821 .is_none()
2822 {
2823 return Err(VATHealthError::NoBLSPubkey);
2824 }
2825
2826 let my_balance = vote_account.lamports();
2827 let minimum_vote_account_balance_for_vat = self.minimum_vote_account_balance_for_vat();
2828 if vote_account.lamports() < minimum_vote_account_balance_for_vat {
2829 return Err(VATHealthError::InsufficientFundsInVoteAccount(
2830 my_balance,
2831 minimum_vote_account_balance_for_vat,
2832 ));
2833 }
2834
2835 Ok(())
2836 }
2837
2838 pub fn ns_per_slot_at_slot(&self, slot: Slot) -> u128 {
2840 self.slot_params_at_slot(slot).ns_per_slot()
2841 }
2842
2843 fn slots_per_year_for_epoch(&self, epoch: Epoch) -> f64 {
2845 let first_slot = self.epoch_schedule().get_first_slot_in_epoch(epoch);
2846 self.slot_params_at_slot(first_slot).slots_per_year()
2847 }
2848
2849 fn slot_range_duration_in_years(&self, start_slot: Slot, end_slot: Slot) -> f64 {
2851 if start_slot >= end_slot {
2852 return 0.0;
2853 }
2854
2855 let mut cursor = start_slot;
2856 let mut params = self.slot_params.baseline_params();
2857 let mut duration = 0.0;
2858
2859 for (effective_slot, effective_params) in self.slot_params.param_transitions() {
2860 if effective_slot <= start_slot {
2861 params = effective_params;
2862 continue;
2863 }
2864 if effective_slot >= end_slot {
2865 break;
2866 }
2867
2868 duration += (effective_slot - cursor) as f64 / params.slots_per_year();
2869 cursor = effective_slot;
2870 params = effective_params;
2871 }
2872
2873 duration + (end_slot - cursor) as f64 / params.slots_per_year()
2874 }
2875
2876 pub fn slot_range_duration_nanos(&self, start_slot: Slot, end_slot: Slot) -> u128 {
2878 self.slot_params
2879 .slot_range_duration_nanos(start_slot, end_slot)
2880 }
2881
2882 pub fn epoch_duration_in_years(&self, epoch: Epoch) -> f64 {
2883 self.epoch_schedule().get_slots_in_epoch(epoch) as f64
2887 / self.slots_per_year_for_epoch(epoch)
2888 }
2889
2890 pub fn max_processing_age(&self) -> usize {
2891 self.max_processing_age
2892 }
2893
2894 fn get_inflation_start_slot(&self) -> Slot {
2900 let mut slots = self
2901 .feature_set
2902 .full_inflation_features_enabled()
2903 .iter()
2904 .filter_map(|id| self.feature_set.activated_slot(id))
2905 .collect::<Vec<_>>();
2906 slots.sort_unstable();
2907 slots.first().cloned().unwrap_or_else(|| {
2908 self.feature_set
2909 .activated_slot(&feature_set::pico_inflation::id())
2910 .unwrap_or(0)
2911 })
2912 }
2913
2914 fn get_inflation_num_slots(&self) -> u64 {
2916 let inflation_start_slot = self.inflation_start_slot_aligned_to_rewards();
2917 self.epoch_schedule().get_first_slot_in_epoch(self.epoch()) - inflation_start_slot
2918 }
2919
2920 fn inflation_start_slot_aligned_to_rewards(&self) -> Slot {
2922 let inflation_activation_slot = self.get_inflation_start_slot();
2923 self.epoch_schedule().get_first_slot_in_epoch(
2924 self.epoch_schedule()
2925 .get_epoch(inflation_activation_slot)
2926 .saturating_sub(1),
2927 )
2928 }
2929
2930 pub fn slot_in_year_for_inflation(&self) -> f64 {
2932 let num_slots = self.get_inflation_num_slots();
2933 let inflation_start_slot = self.inflation_start_slot_aligned_to_rewards();
2934 self.slot_range_duration_in_years(inflation_start_slot, inflation_start_slot + num_slots)
2935 }
2936
2937 pub(crate) fn calculate_epoch_inflation_rewards(
2940 &self,
2941 capitalization: u64,
2942 epoch: Epoch,
2943 ) -> u64 {
2944 let slot_in_year = self.slot_in_year_for_inflation();
2945 let validator_rate = self.inflation.read().unwrap().validator(slot_in_year);
2946 let epoch_duration_in_years = self.epoch_duration_in_years(epoch);
2947 (validator_rate * capitalization as f64 * epoch_duration_in_years) as u64
2948 }
2949
2950 fn update_recent_blockhashes_locked(&self, locked_blockhash_queue: &BlockhashQueue) {
2951 #[expect(deprecated)]
2952 self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |account| {
2953 let recent_blockhash_iter = locked_blockhash_queue.get_recent_blockhashes();
2954 recent_blockhashes_account::create_account_with_data_and_fields(
2955 recent_blockhash_iter,
2956 self.inherit_specially_retained_account_fields(account),
2957 )
2958 });
2959 }
2960
2961 pub fn update_recent_blockhashes(&self) {
2962 let blockhash_queue = self.blockhash_queue.read().unwrap();
2963 self.update_recent_blockhashes_locked(&blockhash_queue);
2964 }
2965
2966 fn get_timestamp_estimate(
2967 &self,
2968 max_allowable_drift: MaxAllowableDrift,
2969 epoch_start_timestamp: Option<(Slot, UnixTimestamp)>,
2970 ) -> Option<UnixTimestamp> {
2971 let mut get_timestamp_estimate_time = Measure::start("get_timestamp_estimate");
2972 let slots_per_epoch = self.epoch_schedule().slots_per_epoch;
2973 let vote_accounts = self.vote_accounts();
2974 let recent_timestamps = vote_accounts.iter().filter_map(|(pubkey, (_, account))| {
2975 let vote_state = account.vote_state_view();
2976 let last_timestamp = vote_state.last_timestamp();
2977 let slot_delta = self.slot().checked_sub(last_timestamp.slot)?;
2978 (slot_delta <= slots_per_epoch)
2979 .then_some((*pubkey, (last_timestamp.slot, last_timestamp.timestamp)))
2980 });
2981 let elapsed_slot_duration = |from_slot: Slot, to_slot: Slot| {
2982 if from_slot >= to_slot {
2983 Duration::ZERO
2984 } else {
2985 Duration::from_nanos_u128(
2986 self.slot_range_duration_nanos(from_slot.saturating_add(1), to_slot),
2987 )
2988 }
2989 };
2990 let epoch = self.epoch_schedule().get_epoch(self.slot());
2991 let stakes = self.epoch_vote_accounts(epoch)?;
2992 let stake_weighted_timestamp = calculate_stake_weighted_timestamp(
2993 recent_timestamps,
2994 stakes,
2995 self.slot(),
2996 elapsed_slot_duration,
2997 epoch_start_timestamp,
2998 max_allowable_drift,
2999 );
3000 get_timestamp_estimate_time.stop();
3001 datapoint_info!(
3002 "bank-timestamp",
3003 (
3004 "get_timestamp_estimate_us",
3005 get_timestamp_estimate_time.as_us(),
3006 i64
3007 ),
3008 );
3009 stake_weighted_timestamp
3010 }
3011
3012 pub fn rehash(&self) {
3020 let mut hash = self.hash.write().unwrap();
3021 let new = self.hash_internal_state();
3022 if new != *hash {
3023 warn!("Updating bank hash to {new}");
3024 *hash = new;
3025 }
3026 }
3027
3028 pub fn freeze(&self) {
3029 let mut hash = self.hash.write().unwrap();
3041 if *hash == Hash::default() {
3042 self.distribute_transaction_fee_details();
3044 self.update_slot_history();
3045 self.run_incinerator();
3046
3047 self.freeze_started.store(true, Relaxed);
3049 self.finish_accounts_lt_hash_updates();
3052 *hash = self.hash_internal_state();
3053 self.rc.accounts.accounts_db.mark_slot_frozen(self.slot());
3054 }
3055 }
3056
3057 pub fn freeze_and_verify_bank_hash(&self) -> std::result::Result<(), (Hash, Hash)> {
3060 self.freeze();
3061 let computed_hash = self.hash();
3062
3063 if let Some(expected_hash) = self.expected_bank_hash()
3064 && expected_hash != computed_hash
3065 {
3066 return Err((expected_hash, computed_hash));
3067 }
3068 Ok(())
3069 }
3070
3071 pub fn set_expected_bank_hash(&self, hash: Hash) {
3074 *self.expected_bank_hash.write().unwrap() = Some(hash);
3075 }
3076
3077 pub fn expected_bank_hash(&self) -> Option<Hash> {
3079 *self.expected_bank_hash.read().unwrap()
3080 }
3081
3082 #[cfg(feature = "dev-context-only-utils")]
3084 pub fn unfreeze_for_ledger_tool(&self) {
3085 self.freeze_started.store(false, Relaxed);
3086 }
3087
3088 pub fn epoch_schedule(&self) -> &EpochSchedule {
3089 &self.epoch_schedule
3090 }
3091
3092 pub fn squash(&self) -> SquashTiming {
3098 self.freeze();
3099
3100 let mut roots = Vec::with_capacity(self.ancestors.len());
3102 roots.push(self.slot());
3103 roots.extend(self.parents_iter().map(|parent| parent.slot()));
3104
3105 let mut total_index_us = 0;
3106 let mut total_cache_us = 0;
3107
3108 let mut squash_accounts_time = Measure::start("squash_accounts_time");
3109 for slot in roots.iter().rev() {
3110 let add_root_timing = self.rc.accounts.add_root(*slot);
3112 total_index_us += add_root_timing.index_us;
3113 total_cache_us += add_root_timing.cache_us;
3114 }
3115 squash_accounts_time.stop();
3116
3117 *self.rc.parent.write().unwrap() = None;
3118
3119 let mut squash_cache_time = Measure::start("squash_cache_time");
3120 self.status_cache
3121 .write()
3122 .unwrap()
3123 .add_roots(roots.iter().copied());
3124 squash_cache_time.stop();
3125
3126 SquashTiming {
3127 squash_accounts_ms: squash_accounts_time.as_ms(),
3128 squash_accounts_index_ms: total_index_us / 1000,
3129 squash_accounts_cache_ms: total_cache_us / 1000,
3130 squash_cache_ms: squash_cache_time.as_ms(),
3131 }
3132 }
3133
3134 pub fn parent(&self) -> Option<Arc<Bank>> {
3136 self.rc.parent.read().unwrap().clone()
3137 }
3138
3139 pub fn parent_slot(&self) -> Slot {
3140 self.parent_slot
3141 }
3142
3143 pub fn parent_hash(&self) -> Hash {
3144 self.parent_hash
3145 }
3146
3147 fn process_genesis_config(
3148 &mut self,
3149 genesis_config: &GenesisConfig,
3150 #[cfg(feature = "dev-context-only-utils")] leader_for_tests: Option<SlotLeader>,
3151 #[cfg(feature = "dev-context-only-utils")] genesis_hash: Option<Hash>,
3152 ) {
3153 self.fee_rate_governor = genesis_config.fee_rate_governor.clone();
3155
3156 for (pubkey, account) in genesis_config.accounts.iter() {
3157 assert!(
3158 self.get_account(pubkey).is_none(),
3159 "{pubkey} repeated in genesis config"
3160 );
3161 let account_shared_data = create_account_shared_data(account);
3162 self.store_account_without_stakes_cache(pubkey, &account_shared_data);
3163 self.capitalization.fetch_add(account.lamports(), Relaxed);
3164 self.accounts_data_size_initial += account.data().len() as u64;
3165 }
3166
3167 for (pubkey, account) in genesis_config.rewards_pools.iter() {
3168 assert!(
3169 self.get_account(pubkey).is_none(),
3170 "{pubkey} repeated in genesis config"
3171 );
3172 let account_shared_data = create_account_shared_data(account);
3173 self.store_account_without_stakes_cache(pubkey, &account_shared_data);
3174 self.accounts_data_size_initial += account.data().len() as u64;
3175 }
3176
3177 self.stakes_cache = StakesCache::new(Stakes::new_from_accounts_for_genesis(
3178 self.new_warmup_cooldown_rate_epoch(),
3179 genesis_config.accounts.iter(),
3180 self.use_fixed_point_stake_math(),
3181 ));
3182
3183 let leader = self.stakes_cache.stakes().highest_staked_node();
3187 #[cfg(feature = "dev-context-only-utils")]
3189 let leader = leader_for_tests
3190 .or(leader)
3191 .or(Some(SlotLeader::new_unique()));
3192 self.leader = leader.expect("genesis processing failed because no staked nodes exist");
3193
3194 #[cfg(not(feature = "dev-context-only-utils"))]
3195 let genesis_hash = genesis_config.hash();
3196 #[cfg(feature = "dev-context-only-utils")]
3197 let genesis_hash = genesis_hash.unwrap_or(genesis_config.hash());
3198
3199 self.blockhash_queue.write().unwrap().genesis_hash(
3200 &genesis_hash,
3201 genesis_config.fee_rate_governor.lamports_per_signature,
3202 );
3203
3204 self.hashes_per_tick = RwLock::new(genesis_config.hashes_per_tick());
3205 self.ticks_per_slot = genesis_config.ticks_per_slot();
3206 self.ns_per_slot = genesis_config.ns_per_slot();
3207 self.genesis_creation_time = genesis_config.creation_time;
3208 self.max_tick_height = (self.slot + 1) * self.ticks_per_slot;
3209 self.slots_per_year = genesis_config.slots_per_year();
3210
3211 self.epoch_schedule = genesis_config.epoch_schedule.clone();
3212 self.refresh_slot_params_with_baseline(Self::genesis_config_slot_params(
3213 genesis_config,
3214 self.partitioned_rewards_stake_account_stores_per_block,
3215 ));
3216
3217 self.inflation = Arc::new(RwLock::new(genesis_config.inflation));
3218
3219 self.rent_collector = RentCollector::new(
3220 self.epoch,
3221 self.epoch_schedule().clone(),
3222 self.slots_per_year,
3223 genesis_config.rent.clone(),
3224 );
3225 }
3226
3227 fn burn_and_purge_account(&self, program_id: &Pubkey, mut account: AccountSharedData) {
3228 let old_data_size = account.data().len();
3229 self.capitalization.fetch_sub(account.lamports(), Relaxed);
3230 account.set_lamports(0);
3233 account.data_as_mut_slice().fill(0);
3234 self.store_account(program_id, &account);
3235 self.calculate_and_update_accounts_data_size_delta_off_chain(old_data_size, 0);
3236 }
3237
3238 pub fn add_precompiled_account(&self, program_id: &Pubkey) {
3240 self.add_precompiled_account_with_owner(program_id, native_loader::id())
3241 }
3242
3243 fn add_precompiled_account_with_owner(&self, program_id: &Pubkey, owner: Pubkey) {
3245 if let Some(account) = self.get_account_with_fixed_root(program_id) {
3246 if account.executable() {
3247 return;
3248 } else {
3249 self.burn_and_purge_account(program_id, account);
3251 }
3252 };
3253
3254 assert!(
3255 !self.freeze_started(),
3256 "Can't change frozen bank by adding not-existing new precompiled program \
3257 ({program_id}). Maybe, inconsistent program activation is detected on snapshot \
3258 restore?"
3259 );
3260
3261 let (lamports, rent_epoch) = self.inherit_specially_retained_account_fields(&None);
3263
3264 let account = AccountSharedData::from(Account {
3265 lamports,
3266 owner,
3267 data: vec![],
3268 executable: true,
3269 rent_epoch,
3270 });
3271 self.store_account_and_update_capitalization(program_id, &account);
3272 }
3273
3274 #[allow(deprecated)]
3275 pub fn set_rent_burn_percentage(&mut self, burn_percent: u8) {
3276 self.rent_collector.rent.burn_percent = burn_percent;
3277 }
3278
3279 pub fn set_hashes_per_tick(&self, hashes_per_tick: Option<u64>) {
3280 *self.hashes_per_tick.write().unwrap() = hashes_per_tick;
3281 }
3282
3283 pub fn last_blockhash(&self) -> Hash {
3285 self.blockhash_queue.read().unwrap().last_hash()
3286 }
3287
3288 pub fn last_blockhash_and_lamports_per_signature(&self) -> (Hash, u64) {
3289 let blockhash_queue = self.blockhash_queue.read().unwrap();
3290 let last_hash = blockhash_queue.last_hash();
3291 let last_lamports_per_signature = blockhash_queue
3292 .get_lamports_per_signature(&last_hash)
3293 .unwrap(); (last_hash, last_lamports_per_signature)
3295 }
3296
3297 pub fn is_blockhash_valid(&self, hash: &Hash) -> bool {
3298 let blockhash_queue = self.blockhash_queue.read().unwrap();
3299 blockhash_queue.is_hash_valid_for_age(hash, self.max_processing_age())
3300 }
3301
3302 pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> u64 {
3303 self.rent_collector.rent.minimum_balance(data_len).max(1)
3304 }
3305
3306 pub fn get_lamports_per_signature(&self) -> u64 {
3307 self.fee_rate_governor.lamports_per_signature
3308 }
3309
3310 pub fn get_lamports_per_signature_for_blockhash(&self, hash: &Hash) -> Option<u64> {
3311 let blockhash_queue = self.blockhash_queue.read().unwrap();
3312 blockhash_queue.get_lamports_per_signature(hash)
3313 }
3314
3315 pub fn get_fee_for_message(&self, message: &SanitizedMessage) -> Option<u64> {
3316 {
3317 let blockhash_queue = self.blockhash_queue.read().unwrap();
3318 blockhash_queue.get_lamports_per_signature(message.recent_blockhash())
3319 }
3320 .or_else(|| {
3321 self.load_message_nonce_data(message, false)
3322 .map(|(_nonce_address, nonce_data)| nonce_data.get_lamports_per_signature())
3323 })?;
3324
3325 let transaction_configuration =
3326 TransactionConfiguration::try_from_sanitized_message(message, &self.feature_set)
3327 .ok()?;
3328 Some(solana_fee::calculate_fee(
3329 message,
3330 self.fee_structure().lamports_per_signature,
3331 transaction_configuration.priority_fee_lamports,
3332 FeeFeatures::from(self.feature_set.as_ref()),
3333 ))
3334 }
3335
3336 pub fn get_blockhash_last_valid_block_height(&self, blockhash: &Hash) -> Option<Slot> {
3337 let blockhash_queue = self.blockhash_queue.read().unwrap();
3338 blockhash_queue
3341 .get_hash_age(blockhash)
3342 .map(|age| self.block_height + self.max_processing_age() as u64 - age)
3343 }
3344
3345 pub fn get_alpenglow_genesis_certificate(&self) -> Option<Certificate> {
3354 let acct = self.get_account(&GENESIS_CERTIFICATE_ACCOUNT)?;
3355 (!acct.data().is_empty()).then(|| {
3356 let cert: WireBlockCertMessage = wincode::deserialize(acct.data())
3360 .expect("Programmer error deserializing genesis certificate");
3361 Certificate {
3362 cert_type: CertificateType::Genesis(cert.block),
3363 signature: cert.signature.signature,
3364 bitmap: cert.signature.bitmap,
3365 }
3366 })
3367 }
3368
3369 pub fn is_alpenglow(&self) -> bool {
3370 self.is_alpenglow.load(Relaxed)
3371 }
3372
3373 fn set_is_alpenglow(&self) {
3374 self.is_alpenglow.store(true, Relaxed);
3375 }
3376
3377 pub fn set_alpenglow_genesis_certificate(&self, cert: &Certificate) {
3379 debug_assert!(cert.cert_type.is_genesis());
3380 let block = cert.cert_type.to_block().unwrap();
3381 let cert = WireBlockCertMessage {
3382 block,
3383 signature: WireCertSignature {
3384 signature: cert.signature,
3385 bitmap: cert.bitmap.clone(),
3386 },
3387 };
3388 let data = wincode::serialize(&cert).unwrap();
3389 let lamports = Rent::default().minimum_balance(data.len());
3390 let mut cert_acct = AccountSharedData::new(lamports, data.len(), &system_program::ID);
3391 cert_acct.set_data_from_slice(&data);
3392
3393 self.store_account_and_update_capitalization(&GENESIS_CERTIFICATE_ACCOUNT, &cert_acct);
3394 self.set_is_alpenglow();
3395 }
3396
3397 pub fn update_clock_from_footer(&self, unix_timestamp_nanos: i64) {
3400 if !self.feature_set.snapshot().alpenglow {
3401 return;
3402 }
3403
3404 let unix_timestamp_s = unix_timestamp_nanos / 1_000_000_000;
3413 let epoch_start_timestamp = match (self.slot, self.parent()) {
3414 (0, _) => self.unix_timestamp_from_genesis(),
3415 (_, Some(parent)) if parent.epoch() != self.epoch() => unix_timestamp_s,
3416 _ => self.clock().epoch_start_timestamp,
3417 };
3418
3419 let clock = sysvar::clock::Clock {
3423 slot: self.slot,
3424 epoch_start_timestamp,
3425 epoch: self.epoch_schedule().get_epoch(self.slot),
3426 leader_schedule_epoch: self.epoch_schedule().get_leader_schedule_epoch(self.slot),
3427 unix_timestamp: unix_timestamp_s,
3428 };
3429
3430 self.update_sysvar_account(&sysvar::clock::id(), |account| {
3431 create_account(
3432 &clock,
3433 self.inherit_specially_retained_account_fields(account),
3434 )
3435 });
3436
3437 let data = wincode::serialize(&unix_timestamp_nanos).unwrap();
3439 let lamports = Rent::default().minimum_balance(data.len());
3440 let mut alpenclock_acct = AccountSharedData::new(lamports, data.len(), &system_program::ID);
3441 alpenclock_acct.set_data_from_slice(&data);
3442
3443 self.store_account_and_update_capitalization(&NANOSECOND_CLOCK_ACCOUNT, &alpenclock_acct);
3444
3445 self.transaction_processor
3446 .reset_and_fill_sysvar_cache_entries(self);
3447 }
3448
3449 pub fn get_nanosecond_clock(&self) -> Option<i64> {
3452 let acct = self.get_account(&NANOSECOND_CLOCK_ACCOUNT)?;
3453 (!acct.data().is_empty()).then(|| {
3454 wincode::deserialize(acct.data())
3457 .expect("Couldn't deserialize nanosecond resolution clock")
3458 })
3459 }
3460
3461 pub fn confirmed_last_blockhash(&self) -> Hash {
3462 const NUM_BLOCKHASH_CONFIRMATIONS: usize = 3;
3463
3464 let mut last_parent = None;
3465 for (index, parent) in self.parents_iter().enumerate() {
3466 if index == NUM_BLOCKHASH_CONFIRMATIONS {
3467 return parent.last_blockhash();
3468 }
3469 last_parent = Some(parent);
3470 }
3471 last_parent.map_or_else(|| self.last_blockhash(), |parent| parent.last_blockhash())
3472 }
3473
3474 #[cfg(feature = "dev-context-only-utils")]
3476 pub fn clear_signatures(&self) {
3477 self.status_cache.write().unwrap().clear();
3478 }
3479
3480 pub fn clear_slot_signatures(&self, slot: Slot) {
3481 self.status_cache.write().unwrap().clear_slot_entries(slot);
3482 }
3483
3484 fn update_transaction_statuses(
3485 &self,
3486 sanitized_txs: &[impl TransactionWithMeta],
3487 processing_results: &[TransactionProcessingResult],
3488 ) {
3489 let mut status_cache = self.status_cache.write().unwrap();
3490 assert_eq!(sanitized_txs.len(), processing_results.len());
3491 for (tx, processing_result) in sanitized_txs.iter().zip(processing_results) {
3492 if let Ok(processed_tx) = &processing_result {
3493 status_cache.insert(
3496 tx.recent_blockhash(),
3497 tx.message_hash(),
3498 self.slot(),
3499 processed_tx.status(),
3500 );
3501 status_cache.insert(
3505 tx.recent_blockhash(),
3506 tx.signature(),
3507 self.slot(),
3508 processed_tx.status(),
3509 );
3510 }
3511 }
3512 }
3513
3514 fn register_recent_blockhash(&self, blockhash: &Hash, scheduler: &InstalledSchedulerRwLock) {
3518 BankWithScheduler::wait_for_paused_scheduler(self, scheduler);
3521
3522 let mut w_blockhash_queue = self.blockhash_queue.write().unwrap();
3526
3527 #[cfg(feature = "dev-context-only-utils")]
3528 let blockhash_override = self
3529 .hash_overrides
3530 .lock()
3531 .unwrap()
3532 .get_blockhash_override(self.slot())
3533 .copied()
3534 .inspect(|blockhash_override| {
3535 if blockhash_override != blockhash {
3536 info!(
3537 "bank: slot: {}: overrode blockhash: {} with {}",
3538 self.slot(),
3539 blockhash,
3540 blockhash_override
3541 );
3542 }
3543 });
3544 #[cfg(feature = "dev-context-only-utils")]
3545 let blockhash = blockhash_override.as_ref().unwrap_or(blockhash);
3546
3547 w_blockhash_queue.register_hash(blockhash, self.fee_rate_governor.lamports_per_signature);
3548 self.update_recent_blockhashes_locked(&w_blockhash_queue);
3549 }
3550
3551 pub fn register_unique_recent_blockhash_for_test(&self) {
3554 self.register_recent_blockhash(
3555 &Hash::new_unique(),
3556 &BankWithScheduler::no_scheduler_available(),
3557 )
3558 }
3559
3560 #[cfg(feature = "dev-context-only-utils")]
3561 pub fn register_recent_blockhash_for_test(
3562 &self,
3563 blockhash: &Hash,
3564 lamports_per_signature: Option<u64>,
3565 ) {
3566 let mut w_blockhash_queue = self.blockhash_queue.write().unwrap();
3570 if let Some(lamports_per_signature) = lamports_per_signature {
3571 w_blockhash_queue.register_hash(blockhash, lamports_per_signature);
3572 } else {
3573 w_blockhash_queue
3574 .register_hash(blockhash, self.fee_rate_governor.lamports_per_signature);
3575 }
3576 }
3577
3578 pub fn register_tick(&self, hash: &Hash, scheduler: &InstalledSchedulerRwLock) {
3585 assert!(
3586 !self.freeze_started(),
3587 "register_tick() working on a bank that is already frozen or is undergoing freezing!"
3588 );
3589
3590 if self.is_block_boundary(self.tick_height.load(Relaxed) + 1) {
3591 self.register_recent_blockhash(hash, scheduler);
3592 }
3593
3594 self.tick_height.fetch_add(1, Relaxed);
3600 }
3601
3602 #[cfg(feature = "dev-context-only-utils")]
3603 pub fn register_tick_for_test(&self, hash: &Hash) {
3604 self.register_tick(hash, &BankWithScheduler::no_scheduler_available())
3605 }
3606
3607 #[cfg(feature = "dev-context-only-utils")]
3608 pub fn register_default_tick_for_test(&self) {
3609 self.register_tick_for_test(&Hash::default())
3610 }
3611
3612 pub fn is_complete(&self) -> bool {
3613 self.tick_height() == self.max_tick_height()
3614 }
3615
3616 pub fn is_block_boundary(&self, tick_height: u64) -> bool {
3617 tick_height == self.max_tick_height
3618 }
3619
3620 pub fn get_transaction_account_lock_limit(&self) -> usize {
3622 if let Some(transaction_account_lock_limit) = self.transaction_account_lock_limit {
3623 transaction_account_lock_limit
3624 } else if self.feature_set.snapshot().increase_tx_account_lock_limit {
3625 MAX_TX_ACCOUNT_LOCKS
3626 } else {
3627 64
3628 }
3629 }
3630
3631 pub fn prepare_entry_batch(
3634 &self,
3635 txs: Vec<VersionedTransaction>,
3636 ) -> Result<TransactionBatch<'_, '_, RuntimeTransaction<SanitizedTransaction>>> {
3637 let enable_instruction_account_limit =
3638 self.feature_set.snapshot().limit_instruction_accounts;
3639 let sanitized_txs = txs
3640 .into_iter()
3641 .map(|tx| {
3642 RuntimeTransaction::try_create(
3643 tx,
3644 MessageHash::Compute,
3645 None,
3646 self,
3647 self.get_reserved_account_keys(),
3648 enable_instruction_account_limit,
3649 )
3650 })
3651 .collect::<Result<Vec<_>>>()?;
3652 Ok(TransactionBatch::new(
3653 self.try_lock_accounts(&sanitized_txs),
3654 self,
3655 OwnedOrBorrowed::Owned(sanitized_txs),
3656 ))
3657 }
3658
3659 pub fn try_lock_accounts(&self, txs: &[impl TransactionWithMeta]) -> Vec<Result<()>> {
3661 self.try_lock_accounts_with_results(txs, txs.iter().map(|_| Ok(())))
3662 }
3663
3664 pub fn try_lock_accounts_with_results(
3667 &self,
3668 txs: &[impl TransactionWithMeta],
3669 tx_results: impl Iterator<Item = Result<()>>,
3670 ) -> Vec<Result<()>> {
3671 let tx_account_lock_limit = self.get_transaction_account_lock_limit();
3672
3673 let mut batch_message_hashes = AHashSet::with_capacity(txs.len());
3675 let tx_results = tx_results
3676 .enumerate()
3677 .map(|(i, tx_result)| match tx_result {
3678 Ok(()) => {
3679 if batch_message_hashes.insert(txs[i].message_hash()) {
3681 Ok(())
3682 } else {
3683 Err(TransactionError::AlreadyProcessed)
3684 }
3685 }
3686 Err(e) => Err(e),
3687 });
3688
3689 self.rc
3690 .accounts
3691 .lock_accounts(txs.iter(), tx_results, tx_account_lock_limit)
3692 }
3693
3694 pub fn prepare_sanitized_batch<'a, 'b, Tx: TransactionWithMeta>(
3696 &'a self,
3697 txs: &'b [Tx],
3698 ) -> TransactionBatch<'a, 'b, Tx> {
3699 self.prepare_sanitized_batch_with_results(txs, txs.iter().map(|_| Ok(())))
3700 }
3701
3702 pub fn prepare_sanitized_batch_with_results<'a, 'b, Tx: TransactionWithMeta>(
3705 &'a self,
3706 transactions: &'b [Tx],
3707 transaction_results: impl Iterator<Item = Result<()>>,
3708 ) -> TransactionBatch<'a, 'b, Tx> {
3709 TransactionBatch::new(
3711 self.try_lock_accounts_with_results(transactions, transaction_results),
3712 self,
3713 OwnedOrBorrowed::Borrowed(transactions),
3714 )
3715 }
3716
3717 pub fn prepare_unlocked_batch_from_single_tx<'a, Tx: SVMMessage>(
3719 &'a self,
3720 transaction: &'a Tx,
3721 ) -> TransactionBatch<'a, 'a, Tx> {
3722 let tx_account_lock_limit = self.get_transaction_account_lock_limit();
3723 let lock_result = validate_account_locks(transaction.account_keys(), tx_account_lock_limit);
3724 let mut batch = TransactionBatch::new(
3725 vec![lock_result],
3726 self,
3727 OwnedOrBorrowed::Borrowed(slice::from_ref(transaction)),
3728 );
3729 batch.set_needs_unlock(false);
3730 batch
3731 }
3732
3733 pub fn prepare_locked_batch_from_single_tx<'a, Tx: TransactionWithMeta>(
3735 &'a self,
3736 transaction: &'a Tx,
3737 ) -> TransactionBatch<'a, 'a, Tx> {
3738 self.prepare_sanitized_batch(slice::from_ref(transaction))
3739 }
3740
3741 pub fn resanitize_transaction_minimally(
3742 &self,
3743 transaction: &impl TransactionWithMeta,
3744 sanitized_epoch: Epoch,
3745 alt_invalidation_slot: Slot,
3746 ) -> Result<()> {
3747 if self.vote_only_bank() && !vote_parser::is_valid_vote_only_transaction(transaction) {
3748 return Err(TransactionError::SanitizeFailure);
3749 }
3750
3751 if self.epoch() != sanitized_epoch {
3754 self.check_reserved_keys(transaction)?;
3757
3758 if self.feature_set.snapshot().limit_instruction_accounts {
3759 for instr in transaction.instructions_iter() {
3760 if instr.accounts.len()
3761 > solana_transaction_context::MAX_ACCOUNTS_PER_INSTRUCTION
3762 {
3763 return Err(solana_transaction_error::TransactionError::SanitizeFailure);
3764 }
3765 }
3766 }
3767 }
3768
3769 if self.slot() > alt_invalidation_slot {
3770 let (_addresses, _deactivation_slot) =
3778 self.load_addresses_from_ref(transaction.message_address_table_lookups())?;
3779 }
3780
3781 Ok(())
3782 }
3783
3784 pub fn simulate_transaction(
3786 &self,
3787 transaction: &impl TransactionWithMeta,
3788 enable_cpi_recording: bool,
3789 ) -> TransactionSimulationResult {
3790 assert!(self.is_frozen(), "simulation bank must be frozen");
3791
3792 self.simulate_transaction_unchecked(transaction, enable_cpi_recording)
3793 }
3794
3795 pub fn simulate_transaction_unchecked(
3798 &self,
3799 transaction: &impl TransactionWithMeta,
3800 enable_cpi_recording: bool,
3801 ) -> TransactionSimulationResult {
3802 let account_keys = transaction.account_keys();
3803 let number_of_accounts = account_keys.len();
3804 let account_overrides = self.get_account_overrides_for_simulation(&account_keys);
3805 let batch = self.prepare_unlocked_batch_from_single_tx(transaction);
3806 let mut timings = ExecuteTimings::default();
3807
3808 let LoadAndExecuteTransactionsOutput {
3809 mut processing_results,
3810 balance_collector,
3811 ..
3812 } = self.load_and_execute_transactions(
3813 &batch,
3814 self.max_processing_age()
3818 .saturating_sub(MAX_TRANSACTION_FORWARDING_DELAY),
3819 &mut timings,
3820 &mut TransactionErrorMetrics::default(),
3821 TransactionProcessingConfig {
3822 account_overrides: Some(&account_overrides),
3823 check_program_deployment_slot: self.check_program_deployment_slot,
3824 log_messages_bytes_limit: None,
3825 limit_to_load_programs: true,
3826 recording_config: ExecutionRecordingConfig {
3827 enable_cpi_recording,
3828 enable_log_recording: true,
3829 enable_return_data_recording: true,
3830 enable_transaction_balance_recording: true,
3831 },
3832 drop_on_failure: false,
3833 all_or_nothing: false,
3834 strict_nonce_size_check: false,
3835 },
3836 );
3837
3838 debug!("simulate_transaction: {timings:?}");
3839
3840 let processing_result = processing_results
3841 .pop()
3842 .unwrap_or(Err(TransactionError::InvalidProgramForExecution));
3843 let (
3844 post_simulation_accounts,
3845 result,
3846 fee,
3847 logs,
3848 return_data,
3849 inner_instructions,
3850 units_consumed,
3851 loaded_accounts_data_size,
3852 ) = match processing_result {
3853 Ok(processed_tx) => {
3854 let executed_units = processed_tx.executed_units();
3855 let loaded_accounts_data_size = processed_tx.loaded_accounts_data_size();
3856
3857 match processed_tx {
3858 ProcessedTransaction::Executed(executed_tx) => {
3859 let details = executed_tx.execution_details;
3860 let post_simulation_accounts = executed_tx
3861 .loaded_transaction
3862 .accounts
3863 .into_iter()
3864 .take(number_of_accounts)
3865 .collect::<Vec<_>>();
3866 (
3867 post_simulation_accounts,
3868 details.status,
3869 Some(executed_tx.loaded_transaction.fee_details.total_fee()),
3870 details.log_messages,
3871 details.return_data,
3872 details.inner_instructions,
3873 executed_units,
3874 loaded_accounts_data_size,
3875 )
3876 }
3877 ProcessedTransaction::FeesOnly(fees_only_tx) => (
3878 vec![],
3879 Err(fees_only_tx.load_error),
3880 Some(fees_only_tx.fee_details.total_fee()),
3881 None,
3882 None,
3883 None,
3884 executed_units,
3885 loaded_accounts_data_size,
3886 ),
3887 }
3888 }
3889 Err(error) => (vec![], Err(error), None, None, None, None, 0, 0),
3890 };
3891 let logs = logs.unwrap_or_default();
3892
3893 let (pre_balances, post_balances, pre_token_balances, post_token_balances) =
3894 match balance_collector {
3895 Some(balance_collector) => {
3896 let (mut native_pre, mut native_post, mut token_pre, mut token_post) =
3897 balance_collector.into_vecs();
3898
3899 (
3900 native_pre.pop(),
3901 native_post.pop(),
3902 token_pre.pop(),
3903 token_post.pop(),
3904 )
3905 }
3906 None => (None, None, None, None),
3907 };
3908
3909 TransactionSimulationResult {
3910 result,
3911 logs,
3912 post_simulation_accounts,
3913 units_consumed,
3914 loaded_accounts_data_size,
3915 return_data,
3916 inner_instructions,
3917 fee,
3918 pre_balances,
3919 post_balances,
3920 pre_token_balances,
3921 post_token_balances,
3922 }
3923 }
3924
3925 fn get_account_overrides_for_simulation(&self, account_keys: &AccountKeys) -> AccountOverrides {
3926 let mut account_overrides = AccountOverrides::default();
3927 let slot_history_id = sysvar::slot_history::id();
3928 if account_keys.iter().any(|pubkey| *pubkey == slot_history_id) {
3929 let current_account = self.get_account_with_fixed_root(&slot_history_id);
3930 let slot_history = current_account
3931 .as_ref()
3932 .map(|account| wincode::deserialize::<SlotHistory>(account.data()).unwrap())
3933 .unwrap_or_default();
3934 if slot_history.check(self.slot()) == Check::Found {
3935 let ancestors = Ancestors::from(self.proper_ancestors().collect::<Vec<_>>());
3936 if let Some((account, _)) =
3937 self.load_slow_with_fixed_root(&ancestors, &slot_history_id)
3938 {
3939 account_overrides.set_slot_history(Some(account));
3940 }
3941 }
3942 }
3943 account_overrides
3944 }
3945
3946 pub fn unlock_accounts<'a, Tx: SVMMessage + 'a>(
3947 &self,
3948 txs_and_results: impl Iterator<Item = (&'a Tx, &'a Result<()>)> + Clone,
3949 ) {
3950 self.rc.accounts.unlock_accounts(txs_and_results)
3951 }
3952
3953 pub fn remove_unrooted_slots(&self, slots: &[(Slot, BankId)]) {
3954 self.rc.accounts.accounts_db.remove_unrooted_slots(slots)
3955 }
3956
3957 pub fn get_hash_age(&self, hash: &Hash) -> Option<u64> {
3958 self.blockhash_queue.read().unwrap().get_hash_age(hash)
3959 }
3960
3961 pub fn is_hash_valid_for_age(&self, hash: &Hash, max_age: usize) -> bool {
3962 self.blockhash_queue
3963 .read()
3964 .unwrap()
3965 .is_hash_valid_for_age(hash, max_age)
3966 }
3967
3968 pub fn collect_balances(
3969 &self,
3970 batch: &TransactionBatch<impl SVMMessage>,
3971 ) -> TransactionBalances {
3972 let mut balances: TransactionBalances = vec![];
3973 for transaction in batch.sanitized_transactions() {
3974 let mut transaction_balances: Vec<u64> = vec![];
3975 for account_key in transaction.account_keys().iter() {
3976 transaction_balances.push(self.get_balance(account_key));
3977 }
3978 balances.push(transaction_balances);
3979 }
3980 balances
3981 }
3982
3983 pub fn load_and_execute_transactions(
3984 &self,
3985 batch: &TransactionBatch<impl TransactionWithMeta>,
3986 max_age: usize,
3987 timings: &mut ExecuteTimings,
3988 error_counters: &mut TransactionErrorMetrics,
3989 processing_config: TransactionProcessingConfig,
3990 ) -> LoadAndExecuteTransactionsOutput {
3991 let sanitized_txs = batch.sanitized_transactions();
3992
3993 let (check_results, check_us) = measure_us!(self.check_transactions(
3994 sanitized_txs,
3995 batch.lock_results(),
3996 max_age,
3997 processing_config.strict_nonce_size_check,
3998 error_counters,
3999 ));
4000 timings.saturating_add_in_place(ExecuteTimingType::CheckUs, check_us);
4001
4002 let (blockhash, blockhash_lamports_per_signature) =
4003 self.last_blockhash_and_lamports_per_signature();
4004 let effective_epoch_of_deployments =
4005 self.epoch_schedule().get_epoch(self.slot.saturating_add(
4006 solana_program_runtime::program_cache_entry::DELAY_VISIBILITY_SLOT_OFFSET,
4007 ));
4008 let processing_environment = TransactionProcessingEnvironment {
4009 blockhash,
4010 blockhash_lamports_per_signature,
4011 alpenglow_migration_succeeded: self.is_alpenglow(),
4012 epoch_total_stake: self.get_current_epoch_total_stake(),
4013 feature_set: self.feature_set.runtime_features(),
4014 program_runtime_environments: ProgramRuntimeEnvironments::new(
4015 self.transaction_processor
4016 .program_runtime_environment
4017 .clone(),
4018 self.transaction_processor
4019 .program_runtime_environment_for_epoch(effective_epoch_of_deployments),
4020 ),
4021 rent: self.rent_collector.rent.clone(),
4022 };
4023
4024 let sanitized_output = self
4025 .transaction_processor
4026 .load_and_execute_sanitized_transactions(
4027 self,
4028 sanitized_txs,
4029 check_results,
4030 &processing_environment,
4031 &processing_config,
4032 );
4033
4034 error_counters.accumulate(&sanitized_output.error_metrics);
4036
4037 timings.accumulate(&sanitized_output.execute_timings);
4039
4040 let ((), collect_logs_us) =
4041 measure_us!(self.collect_logs(sanitized_txs, &sanitized_output.processing_results));
4042 timings.saturating_add_in_place(ExecuteTimingType::CollectLogsUs, collect_logs_us);
4043
4044 let mut processed_counts = ProcessedTransactionCounts::default();
4045 let err_count = &mut error_counters.total;
4046
4047 for (processing_result, tx) in sanitized_output
4048 .processing_results
4049 .iter()
4050 .zip(sanitized_txs)
4051 {
4052 if let Some(debug_keys) = &self.transaction_debug_keys {
4053 for key in tx.account_keys().iter() {
4054 if debug_keys.contains(key) {
4055 let result = processing_result.flattened_result();
4056 info!("slot: {} result: {:?} tx: {:?}", self.slot, result, tx);
4057 break;
4058 }
4059 }
4060 }
4061
4062 if processing_result.was_processed() {
4063 processed_counts.signature_count +=
4067 tx.signature_details().num_transaction_signatures();
4068 processed_counts.processed_transactions_count += 1;
4069
4070 if !tx.is_simple_vote_transaction() {
4071 processed_counts.processed_non_vote_transactions_count += 1;
4072 }
4073 }
4074
4075 match processing_result.flattened_result() {
4076 Ok(()) => {
4077 processed_counts.processed_with_successful_result_count += 1;
4078 }
4079 Err(err) => {
4080 if err_count.0 == 0 {
4081 debug!("tx error: {err:?} {tx:?}");
4082 }
4083 *err_count += 1;
4084 }
4085 }
4086 }
4087
4088 LoadAndExecuteTransactionsOutput {
4089 processing_results: sanitized_output.processing_results,
4090 processed_counts,
4091 balance_collector: sanitized_output.balance_collector,
4092 }
4093 }
4094
4095 fn collect_logs(
4096 &self,
4097 transactions: &[impl TransactionWithMeta],
4098 processing_results: &[TransactionProcessingResult],
4099 ) {
4100 let transaction_log_collector_config =
4101 self.transaction_log_collector_config.read().unwrap();
4102 if transaction_log_collector_config.filter == TransactionLogCollectorFilter::None {
4103 return;
4104 }
4105
4106 let collected_logs: Vec<_> = processing_results
4107 .iter()
4108 .zip(transactions)
4109 .filter_map(|(processing_result, transaction)| {
4110 let processed_tx = processing_result.processed_transaction()?;
4112 let execution_details = processed_tx.execution_details()?;
4114 Self::collect_transaction_logs(
4115 &transaction_log_collector_config,
4116 transaction,
4117 execution_details,
4118 )
4119 })
4120 .collect();
4121
4122 if !collected_logs.is_empty() {
4123 let mut transaction_log_collector = self.transaction_log_collector.write().unwrap();
4124 for (log, filtered_mentioned_addresses) in collected_logs {
4125 let transaction_log_index = transaction_log_collector.logs.len();
4126 transaction_log_collector.logs.push(log);
4127 for key in filtered_mentioned_addresses.into_iter() {
4128 transaction_log_collector
4129 .mentioned_address_map
4130 .entry(key)
4131 .or_default()
4132 .push(transaction_log_index);
4133 }
4134 }
4135 }
4136 }
4137
4138 fn collect_transaction_logs(
4139 transaction_log_collector_config: &TransactionLogCollectorConfig,
4140 transaction: &impl TransactionWithMeta,
4141 execution_details: &TransactionExecutionDetails,
4142 ) -> Option<(TransactionLogInfo, Vec<Pubkey>)> {
4143 let log_messages = execution_details.log_messages.as_ref()?;
4145
4146 let mut filtered_mentioned_addresses = Vec::new();
4147 if !transaction_log_collector_config
4148 .mentioned_addresses
4149 .is_empty()
4150 {
4151 for key in transaction.account_keys().iter() {
4152 if transaction_log_collector_config
4153 .mentioned_addresses
4154 .contains(key)
4155 {
4156 filtered_mentioned_addresses.push(*key);
4157 }
4158 }
4159 }
4160
4161 let is_vote = transaction.is_simple_vote_transaction();
4162 let store = match transaction_log_collector_config.filter {
4163 TransactionLogCollectorFilter::All => {
4164 !is_vote || !filtered_mentioned_addresses.is_empty()
4165 }
4166 TransactionLogCollectorFilter::AllWithVotes => true,
4167 TransactionLogCollectorFilter::None => false,
4168 TransactionLogCollectorFilter::OnlyMentionedAddresses => {
4169 !filtered_mentioned_addresses.is_empty()
4170 }
4171 };
4172
4173 if store {
4174 Some((
4175 TransactionLogInfo {
4176 signature: *transaction.signature(),
4177 result: execution_details.status.clone(),
4178 is_vote,
4179 log_messages: log_messages.clone(),
4180 },
4181 filtered_mentioned_addresses,
4182 ))
4183 } else {
4184 None
4185 }
4186 }
4187
4188 pub fn load_accounts_data_size(&self) -> u64 {
4190 self.accounts_data_size_initial
4191 .saturating_add_signed(self.load_accounts_data_size_delta())
4192 }
4193
4194 pub fn load_accounts_data_size_delta(&self) -> i64 {
4196 let delta_on_chain = self.load_accounts_data_size_delta_on_chain();
4197 let delta_off_chain = self.load_accounts_data_size_delta_off_chain();
4198 delta_on_chain.saturating_add(delta_off_chain)
4199 }
4200
4201 pub fn load_accounts_data_size_delta_on_chain(&self) -> i64 {
4204 self.accounts_data_size_delta_on_chain.load(Acquire)
4205 }
4206
4207 pub fn load_accounts_data_size_delta_off_chain(&self) -> i64 {
4210 self.accounts_data_size_delta_off_chain.load(Acquire)
4211 }
4212
4213 fn update_accounts_data_size_delta_on_chain(&self, amount: i64) {
4216 if amount == 0 {
4217 return;
4218 }
4219
4220 self.accounts_data_size_delta_on_chain
4221 .fetch_update(AcqRel, Acquire, |accounts_data_size_delta_on_chain| {
4222 Some(accounts_data_size_delta_on_chain.saturating_add(amount))
4223 })
4224 .unwrap();
4226 }
4227
4228 fn update_accounts_data_size_delta_off_chain(&self, amount: i64) {
4231 if amount == 0 {
4232 return;
4233 }
4234
4235 self.accounts_data_size_delta_off_chain
4236 .fetch_update(AcqRel, Acquire, |accounts_data_size_delta_off_chain| {
4237 Some(accounts_data_size_delta_off_chain.saturating_add(amount))
4238 })
4239 .unwrap();
4241 }
4242
4243 fn calculate_and_update_accounts_data_size_delta_off_chain(
4245 &self,
4246 old_data_size: usize,
4247 new_data_size: usize,
4248 ) {
4249 let data_size_delta = calculate_data_size_delta(old_data_size, new_data_size);
4250 self.update_accounts_data_size_delta_off_chain(data_size_delta);
4251 }
4252
4253 fn filter_program_errors_and_collect_fee_details(
4254 &self,
4255 processing_results: &[TransactionProcessingResult],
4256 ) {
4257 let mut accumulated_fee_details = FeeDetails::default();
4258
4259 processing_results.iter().for_each(|processing_result| {
4260 if let Ok(processed_tx) = processing_result {
4261 accumulated_fee_details.accumulate(&processed_tx.fee_details());
4262 }
4263 });
4264
4265 self.collector_fee_details
4266 .write()
4267 .unwrap()
4268 .accumulate(&accumulated_fee_details);
4269 }
4270
4271 fn update_bank_hash_stats<'a>(&self, accounts: &impl StorableAccounts<'a>) {
4272 let mut stats = BankHashStats::default();
4273 (0..accounts.len()).for_each(|i| {
4274 accounts.account(i, |account| {
4275 stats.update(&account);
4276 })
4277 });
4278 self.bank_hash_stats.accumulate(&stats);
4279 }
4280
4281 pub fn commit_transactions(
4282 &self,
4283 sanitized_txs: &[impl TransactionWithMeta],
4284 processing_results: Vec<TransactionProcessingResult>,
4285 processed_counts: &ProcessedTransactionCounts,
4286 timings: &mut ExecuteTimings,
4287 ) -> Vec<TransactionCommitResult> {
4288 assert!(
4289 !self.freeze_started(),
4290 "commit_transactions() working on a bank that is already frozen or is undergoing \
4291 freezing!"
4292 );
4293
4294 let ProcessedTransactionCounts {
4295 processed_transactions_count,
4296 processed_non_vote_transactions_count,
4297 processed_with_successful_result_count,
4298 signature_count,
4299 } = *processed_counts;
4300
4301 self.increment_transaction_count(processed_transactions_count);
4302 self.increment_non_vote_transaction_count_since_restart(
4303 processed_non_vote_transactions_count,
4304 );
4305 self.increment_signature_count(signature_count);
4306
4307 let processed_with_failure_result_count =
4308 processed_transactions_count.saturating_sub(processed_with_successful_result_count);
4309 self.transaction_error_count
4310 .fetch_add(processed_with_failure_result_count, Relaxed);
4311
4312 if processed_transactions_count > 0 {
4313 self.is_delta.store(true, Relaxed);
4314 self.transaction_entries_count.fetch_add(1, Relaxed);
4315 self.transactions_per_entry_max
4316 .fetch_max(processed_transactions_count, Relaxed);
4317 }
4318
4319 let ((), store_accounts_us) = measure_us!({
4320 let maybe_transaction_refs = self
4324 .accounts()
4325 .accounts_db
4326 .has_accounts_update_notifier()
4327 .then(|| {
4328 sanitized_txs
4329 .iter()
4330 .map(|tx| tx.as_sanitized_transaction())
4331 .collect::<Vec<_>>()
4332 });
4333
4334 let (accounts_to_store, transactions) = collect_accounts_to_store(
4335 sanitized_txs,
4336 &maybe_transaction_refs,
4337 &processing_results,
4338 );
4339
4340 let to_store = (self.slot(), accounts_to_store.as_slice());
4341 self.update_bank_hash_stats(&to_store);
4342 self.enqueue_on_chain_accounts_lt_hash_updates(&to_store);
4343 self.rc
4346 .accounts
4347 .store_accounts_seq(to_store, transactions.as_deref(), &self.ancestors);
4348 });
4349
4350 let ((), update_stakes_cache_us) =
4353 measure_us!(self.update_stakes_cache(sanitized_txs, &processing_results));
4354
4355 let ((), update_executors_us) = measure_us!({
4356 let mut cache = None;
4357 for processing_result in &processing_results {
4358 if let Some(ProcessedTransaction::Executed(executed_tx)) =
4359 processing_result.processed_transaction()
4360 {
4361 let programs_modified_by_tx = &executed_tx.programs_modified_by_tx;
4362 if executed_tx.was_successful() && !programs_modified_by_tx.is_empty() {
4363 cache
4364 .get_or_insert_with(|| {
4365 self.transaction_processor
4366 .global_program_cache
4367 .write()
4368 .unwrap()
4369 })
4370 .merge(
4371 &self.transaction_processor.program_runtime_environment,
4372 self.slot,
4373 programs_modified_by_tx,
4374 );
4375 }
4376 }
4377 }
4378 });
4379
4380 let accounts_data_len_delta = processing_results
4381 .iter()
4382 .filter_map(|processing_result| processing_result.processed_transaction())
4383 .filter_map(|processed_tx| processed_tx.execution_details())
4384 .filter_map(|details| details.accounts_deltas.as_ref())
4385 .map(|deltas| {
4386 deltas
4387 .accounts_resize_delta
4388 .saturating_sub_unsigned(deltas.accounts_uninitialized_size)
4389 })
4390 .sum();
4391 self.update_accounts_data_size_delta_on_chain(accounts_data_len_delta);
4392
4393 let ((), update_transaction_statuses_us) =
4394 measure_us!(self.update_transaction_statuses(sanitized_txs, &processing_results));
4395
4396 self.filter_program_errors_and_collect_fee_details(&processing_results);
4397
4398 timings.saturating_add_in_place(ExecuteTimingType::StoreUs, store_accounts_us);
4399 timings.saturating_add_in_place(
4400 ExecuteTimingType::UpdateStakesCacheUs,
4401 update_stakes_cache_us,
4402 );
4403 timings.saturating_add_in_place(ExecuteTimingType::UpdateExecutorsUs, update_executors_us);
4404 timings.saturating_add_in_place(
4405 ExecuteTimingType::UpdateTransactionStatuses,
4406 update_transaction_statuses_us,
4407 );
4408
4409 Self::create_commit_results(processing_results)
4410 }
4411
4412 fn create_commit_results(
4413 processing_results: Vec<TransactionProcessingResult>,
4414 ) -> Vec<TransactionCommitResult> {
4415 processing_results
4416 .into_iter()
4417 .map(|processing_result| {
4418 let processing_result = processing_result?;
4419 let executed_units = processing_result.executed_units();
4420 let loaded_accounts_data_size = processing_result.loaded_accounts_data_size();
4421
4422 match processing_result {
4423 ProcessedTransaction::Executed(executed_tx) => {
4424 let successful = executed_tx.was_successful();
4425 let execution_details = executed_tx.execution_details;
4426 let LoadedTransaction {
4427 accounts: loaded_accounts,
4428 fee_details,
4429 rollback_accounts,
4430 ..
4431 } = executed_tx.loaded_transaction;
4432
4433 let fee_payer_post_balance = if successful {
4435 loaded_accounts[0].1.lamports()
4436 } else {
4437 rollback_accounts.fee_payer().1.lamports()
4438 };
4439
4440 Ok(CommittedTransaction {
4441 status: execution_details.status,
4442 log_messages: execution_details.log_messages,
4443 inner_instructions: execution_details.inner_instructions,
4444 return_data: execution_details.return_data,
4445 executed_units,
4446 fee_details,
4447 loaded_account_stats: TransactionLoadedAccountsStats {
4448 loaded_accounts_count: loaded_accounts.len(),
4449 loaded_accounts_data_size,
4450 },
4451 fee_payer_post_balance,
4452 })
4453 }
4454 ProcessedTransaction::FeesOnly(fees_only_tx) => Ok(CommittedTransaction {
4455 status: Err(fees_only_tx.load_error),
4456 log_messages: None,
4457 inner_instructions: None,
4458 return_data: None,
4459 executed_units,
4460 fee_details: fees_only_tx.fee_details,
4461 loaded_account_stats: TransactionLoadedAccountsStats {
4462 loaded_accounts_count: fees_only_tx.rollback_accounts.count(),
4463 loaded_accounts_data_size,
4464 },
4465 fee_payer_post_balance: fees_only_tx
4466 .rollback_accounts
4467 .fee_payer()
4468 .1
4469 .lamports(),
4470 }),
4471 }
4472 })
4473 .collect()
4474 }
4475
4476 fn run_incinerator(&self) {
4477 if let Some((account, _)) =
4478 self.get_account_modified_since_parent_with_fixed_root(&incinerator::id())
4479 {
4480 self.capitalization.fetch_sub(account.lamports(), Relaxed);
4481 self.store_account(&incinerator::id(), &AccountSharedData::default());
4482 }
4483 }
4484
4485 pub(crate) fn get_accounts_for_bank_hash_details(&self) -> Vec<(Pubkey, AccountSharedData)> {
4488 let mut accounts = self
4489 .rc
4490 .accounts
4491 .accounts_db
4492 .get_pubkey_account_for_slot(self.slot());
4493 accounts.sort_unstable_by_key(|a| a.0);
4495 accounts
4496 }
4497
4498 pub fn cluster_type(&self) -> ClusterType {
4499 self.cluster_type.unwrap()
4502 }
4503
4504 #[must_use]
4506 pub fn load_execute_and_commit_transactions(
4507 &self,
4508 batch: &TransactionBatch<impl TransactionWithMeta>,
4509 recording_config: ExecutionRecordingConfig,
4510 timings: &mut ExecuteTimings,
4511 log_messages_bytes_limit: Option<usize>,
4512 ) -> (Vec<TransactionCommitResult>, Option<BalanceCollector>) {
4513 self.do_load_execute_and_commit_transactions_with_pre_commit_callback(
4514 batch,
4515 recording_config,
4516 timings,
4517 log_messages_bytes_limit,
4518 None::<fn(&mut _, &_) -> _>,
4519 )
4520 .unwrap()
4521 }
4522
4523 pub fn load_execute_and_commit_transactions_with_pre_commit_callback<'a>(
4524 &'a self,
4525 batch: &TransactionBatch<impl TransactionWithMeta>,
4526 recording_config: ExecutionRecordingConfig,
4527 timings: &mut ExecuteTimings,
4528 log_messages_bytes_limit: Option<usize>,
4529 pre_commit_callback: impl FnOnce(
4530 &mut ExecuteTimings,
4531 &[TransactionProcessingResult],
4532 ) -> PreCommitResult<'a>,
4533 ) -> Result<(Vec<TransactionCommitResult>, Option<BalanceCollector>)> {
4534 self.do_load_execute_and_commit_transactions_with_pre_commit_callback(
4535 batch,
4536 recording_config,
4537 timings,
4538 log_messages_bytes_limit,
4539 Some(pre_commit_callback),
4540 )
4541 }
4542
4543 fn do_load_execute_and_commit_transactions_with_pre_commit_callback<'a>(
4544 &'a self,
4545 batch: &TransactionBatch<impl TransactionWithMeta>,
4546 recording_config: ExecutionRecordingConfig,
4547 timings: &mut ExecuteTimings,
4548 log_messages_bytes_limit: Option<usize>,
4549 pre_commit_callback: Option<
4550 impl FnOnce(&mut ExecuteTimings, &[TransactionProcessingResult]) -> PreCommitResult<'a>,
4551 >,
4552 ) -> Result<(Vec<TransactionCommitResult>, Option<BalanceCollector>)> {
4553 let LoadAndExecuteTransactionsOutput {
4554 processing_results,
4555 processed_counts,
4556 balance_collector,
4557 } = self.load_and_execute_transactions(
4558 batch,
4559 self.max_processing_age(),
4560 timings,
4561 &mut TransactionErrorMetrics::default(),
4562 TransactionProcessingConfig {
4563 account_overrides: None,
4564 check_program_deployment_slot: self.check_program_deployment_slot,
4565 log_messages_bytes_limit,
4566 limit_to_load_programs: false,
4567 recording_config,
4568 drop_on_failure: false,
4569 all_or_nothing: false,
4570 strict_nonce_size_check: false,
4571 },
4572 );
4573
4574 let freeze_lock = if let Some(pre_commit_callback) = pre_commit_callback {
4579 pre_commit_callback(timings, &processing_results)?
4580 } else {
4581 None
4582 };
4583 let commit_results = self.commit_transactions(
4584 batch.sanitized_transactions(),
4585 processing_results,
4586 &processed_counts,
4587 timings,
4588 );
4589 drop(freeze_lock);
4590 Ok((commit_results, balance_collector))
4591 }
4592
4593 pub fn process_transaction(&self, tx: &Transaction) -> Result<()> {
4596 self.try_process_transactions(std::iter::once(tx))?[0].clone()
4597 }
4598
4599 pub fn process_transaction_with_metadata(
4602 &self,
4603 tx: impl Into<VersionedTransaction>,
4604 ) -> Result<CommittedTransaction> {
4605 let txs = vec![tx.into()];
4606 let batch = self.prepare_entry_batch(txs)?;
4607
4608 let (mut commit_results, ..) = self.load_execute_and_commit_transactions(
4609 &batch,
4610 ExecutionRecordingConfig {
4611 enable_cpi_recording: false,
4612 enable_log_recording: true,
4613 enable_return_data_recording: true,
4614 enable_transaction_balance_recording: false,
4615 },
4616 &mut ExecuteTimings::default(),
4617 Some(1000 * 1000),
4618 );
4619
4620 commit_results.remove(0)
4621 }
4622
4623 pub fn try_process_transactions<'a>(
4626 &self,
4627 txs: impl Iterator<Item = &'a Transaction>,
4628 ) -> Result<Vec<Result<()>>> {
4629 let txs = txs
4630 .map(|tx| VersionedTransaction::from(tx.clone()))
4631 .collect();
4632 self.try_process_entry_transactions(txs)
4633 }
4634
4635 pub fn try_process_entry_transactions(
4638 &self,
4639 txs: Vec<VersionedTransaction>,
4640 ) -> Result<Vec<Result<()>>> {
4641 let batch = self.prepare_entry_batch(txs)?;
4642 Ok(self.process_transaction_batch(&batch))
4643 }
4644
4645 #[must_use]
4646 fn process_transaction_batch(
4647 &self,
4648 batch: &TransactionBatch<impl TransactionWithMeta>,
4649 ) -> Vec<Result<()>> {
4650 self.load_execute_and_commit_transactions(
4651 batch,
4652 ExecutionRecordingConfig::new_single_setting(false),
4653 &mut ExecuteTimings::default(),
4654 None,
4655 )
4656 .0
4657 .into_iter()
4658 .map(|commit_result| commit_result.and_then(|committed_tx| committed_tx.status))
4659 .collect()
4660 }
4661
4662 pub fn transfer(&self, n: u64, keypair: &Keypair, to: &Pubkey) -> Result<Signature> {
4665 let blockhash = self.last_blockhash();
4666 let tx = system_transaction::transfer(keypair, to, n, blockhash);
4667 let signature = tx.signatures[0];
4668 self.process_transaction(&tx).map(|_| signature)
4669 }
4670
4671 pub fn read_balance(account: &AccountSharedData) -> u64 {
4672 account.lamports()
4673 }
4674 pub fn get_balance(&self, pubkey: &Pubkey) -> u64 {
4677 self.get_account(pubkey)
4678 .map(|x| Self::read_balance(&x))
4679 .unwrap_or(0)
4680 }
4681
4682 pub fn parents(&self) -> Vec<Arc<Bank>> {
4684 self.parents_iter().collect()
4685 }
4686
4687 pub(crate) fn parents_iter(&self) -> impl Iterator<Item = Arc<Bank>> + '_ {
4688 let mut bank = self.parent();
4689 core::iter::from_fn(move || {
4690 let parent = bank.take()?;
4691 bank = parent.parent();
4692 Some(parent)
4693 })
4694 }
4695
4696 pub fn parents_inclusive(self: Arc<Self>) -> Vec<Arc<Bank>> {
4698 let mut parents = Vec::with_capacity(self.ancestors.len());
4699 parents.push(Arc::clone(&self));
4700 parents.extend(self.parents_iter());
4701 parents
4702 }
4703
4704 pub fn store_account(&self, pubkey: &Pubkey, account: &AccountSharedData) {
4707 self.store_accounts((self.slot(), &[(pubkey, account)][..]), None)
4708 }
4709
4710 pub fn store_accounts<'a>(
4716 &self,
4717 accounts: impl StorableAccounts<'a>,
4718 thread_pool_for_loading_accounts: Option<&ThreadPool>,
4719 ) {
4720 assert!(!self.freeze_started());
4721 let mut m = Measure::start("stakes_cache.check_and_store");
4722 let new_warmup_cooldown_rate_epoch = self.new_warmup_cooldown_rate_epoch();
4723 let use_fixed_point_stake_math = self.use_fixed_point_stake_math();
4724
4725 (0..accounts.len()).for_each(|i| {
4726 accounts.account(i, |account| {
4727 self.stakes_cache.check_and_store(
4728 account.pubkey(),
4729 &account,
4730 new_warmup_cooldown_rate_epoch,
4731 use_fixed_point_stake_math,
4732 )
4733 })
4734 });
4735 self.store_accounts_without_stakes_cache(accounts, thread_pool_for_loading_accounts);
4736 m.stop();
4737 self.rc
4738 .accounts
4739 .accounts_db
4740 .stats
4741 .stakes_cache_check_and_store_us
4742 .fetch_add(m.as_us(), Relaxed);
4743 }
4744
4745 fn store_account_without_stakes_cache(&self, pubkey: &Pubkey, account: &AccountSharedData) {
4746 self.store_accounts_without_stakes_cache((self.slot(), &[(pubkey, account)][..]), None)
4747 }
4748
4749 fn store_accounts_without_stakes_cache<'a>(
4755 &self,
4756 accounts: impl StorableAccounts<'a>,
4757 thread_pool_for_loading_accounts: Option<&ThreadPool>,
4758 ) {
4759 assert!(!self.freeze_started());
4760 self.update_bank_hash_stats(&accounts);
4761 self.enqueue_off_chain_accounts_lt_hash_updates(
4762 &accounts,
4763 thread_pool_for_loading_accounts,
4764 );
4765 self.rc
4766 .accounts
4767 .store_accounts_par(accounts, None, &self.ancestors);
4768 }
4769
4770 pub fn force_flush_accounts_cache(&self) {
4771 self.rc
4772 .accounts
4773 .accounts_db
4774 .flush_accounts_cache(true, Some(self.slot()))
4775 }
4776
4777 pub(crate) fn store_account_and_update_capitalization(
4780 &self,
4781 pubkey: &Pubkey,
4782 new_account: &AccountSharedData,
4783 ) {
4784 let old_account_data_size = if let Some(old_account) =
4785 self.get_account_with_fixed_root_no_cache(pubkey)
4786 {
4787 match new_account.lamports().cmp(&old_account.lamports()) {
4788 std::cmp::Ordering::Greater => {
4789 let diff = new_account.lamports() - old_account.lamports();
4790 trace!("store_account_and_update_capitalization: increased: {pubkey} {diff}");
4791 self.capitalization.fetch_add(diff, Relaxed);
4792 }
4793 std::cmp::Ordering::Less => {
4794 let diff = old_account.lamports() - new_account.lamports();
4795 trace!("store_account_and_update_capitalization: decreased: {pubkey} {diff}");
4796 self.capitalization.fetch_sub(diff, Relaxed);
4797 }
4798 std::cmp::Ordering::Equal => {}
4799 }
4800 old_account.data().len()
4801 } else {
4802 trace!(
4803 "store_account_and_update_capitalization: created: {pubkey} {}",
4804 new_account.lamports()
4805 );
4806 self.capitalization
4807 .fetch_add(new_account.lamports(), Relaxed);
4808 0
4809 };
4810
4811 self.store_account(pubkey, new_account);
4812
4813 let new_account_data_size = if new_account.lamports() == 0 {
4815 0
4816 } else {
4817 new_account.data().len()
4818 };
4819 self.calculate_and_update_accounts_data_size_delta_off_chain(
4820 old_account_data_size,
4821 new_account_data_size,
4822 );
4823 }
4824
4825 pub fn accounts(&self) -> Arc<Accounts> {
4826 self.rc.accounts.clone()
4827 }
4828
4829 fn apply_cost_tracker_limits_for_active_features(&mut self) {
4831 let params = self.current_slot_params();
4832 let cost_limits =
4833 params.cost_limits(self.feature_set.snapshot().raise_block_limits_to_100m);
4834
4835 let mut cost_tracker = self.write_cost_tracker().unwrap();
4836 cost_tracker.set_limits(cost_limits);
4837 }
4838
4839 fn apply_partitioned_epoch_rewards_config_for_active_features(&mut self) {
4841 self.partitioned_rewards_stake_account_stores_per_block = self
4842 .current_slot_params()
4843 .partitioned_epoch_rewards_stake_account_stores_per_block();
4844 }
4845
4846 fn apply_slot_time_persistent_changes(&mut self) {
4848 let params = self.current_slot_params();
4849 self.ns_per_slot = params.ns_per_slot();
4850 self.slots_per_year = params.slots_per_year();
4851 self.rent_collector.slots_per_year = params.slots_per_year();
4852 if !self.feature_set.is_active(&feature_set::alpenglow::id())
4853 && self.hashes_per_tick().is_some()
4854 {
4855 self.set_hashes_per_tick(params.hashes_per_tick());
4856 }
4857 }
4858
4859 fn assert_bank_matches_slot_params(&self) {
4861 let params = self.current_slot_params();
4862 assert_eq!(
4863 self.ns_per_slot,
4864 params.ns_per_slot(),
4865 "snapshot slot-time ns_per_slot mismatch"
4866 );
4867 assert_eq!(
4868 self.slots_per_year.to_bits(),
4869 params.slots_per_year().to_bits(),
4870 "snapshot slot-time slots_per_year mismatch"
4871 );
4872 assert_eq!(
4873 self.rent_collector.slots_per_year.to_bits(),
4874 params.slots_per_year().to_bits(),
4875 "snapshot slot-time rent_collector.slots_per_year mismatch"
4876 );
4877 let hashes_per_tick = self.hashes_per_tick();
4878 if !self.feature_set.is_active(&feature_set::alpenglow::id()) && hashes_per_tick.is_some() {
4879 assert_eq!(
4880 hashes_per_tick,
4881 params.hashes_per_tick(),
4882 "snapshot slot-time hashes_per_tick mismatch"
4883 );
4884 }
4885 assert_eq!(
4886 self.entry_bytes_budget().slot_limit(),
4887 params.max_entry_bytes_per_slot(),
4888 "snapshot slot-time entry byte budget mismatch"
4889 );
4890 }
4891
4892 fn apply_slot_time_runtime_changes(&mut self) {
4895 self.entry_bytes_consumed =
4896 EntryBytesBudget::new(self.current_slot_params().max_entry_bytes_per_slot());
4897 self.apply_cost_tracker_limits_for_active_features();
4898 self.apply_partitioned_epoch_rewards_config_for_active_features();
4899 }
4900
4901 fn apply_simd_0339_invoke_cost_changes(&mut self) {
4902 let simd_0268_active = self.feature_set.snapshot().raise_cpi_nesting_limit_to_8;
4903 let compute_budget = self
4904 .compute_budget()
4905 .as_ref()
4906 .unwrap_or(&ComputeBudget::new_with_defaults(simd_0268_active))
4907 .to_cost();
4908
4909 self.transaction_processor
4910 .set_execution_cost(compute_budget);
4911 }
4912
4913 fn apply_activated_features(&mut self) {
4915 self.reserved_account_keys = {
4917 let mut reserved_keys = ReservedAccountKeys::clone(&self.reserved_account_keys);
4918 reserved_keys.update_active_set(&self.feature_set);
4919 Arc::new(reserved_keys)
4920 };
4921
4922 self.refresh_slot_params();
4925 self.apply_slot_time_runtime_changes();
4926 self.apply_simd_0339_invoke_cost_changes();
4927
4928 let program_runtime_environment =
4929 self.create_program_runtime_environment(&self.feature_set);
4930 self.transaction_processor
4931 .global_program_cache
4932 .write()
4933 .unwrap()
4934 .latest_root_slot = self.slot;
4935 self.transaction_processor
4936 .epoch_boundary_preparation
4937 .write()
4938 .unwrap()
4939 .upcoming_epoch = self.epoch;
4940 self.transaction_processor.program_runtime_environment = program_runtime_environment;
4941
4942 self.add_active_builtin_programs();
4944 }
4945
4946 fn create_program_runtime_environment(
4947 &self,
4948 feature_set: &FeatureSet,
4949 ) -> ProgramRuntimeEnvironment {
4950 let simd_0268_active = feature_set.snapshot().raise_cpi_nesting_limit_to_8;
4951 let compute_budget = self
4952 .compute_budget()
4953 .as_ref()
4954 .unwrap_or(&ComputeBudget::new_with_defaults(simd_0268_active))
4955 .to_budget();
4956 create_program_runtime_environment(
4957 &feature_set.runtime_features(),
4958 &compute_budget,
4959 false, false, )
4962 .unwrap()
4963 }
4964
4965 pub fn set_tick_height(&self, tick_height: u64) {
4966 self.tick_height.store(tick_height, Relaxed)
4967 }
4968
4969 pub fn set_inflation(&self, inflation: Inflation) {
4970 *self.inflation.write().unwrap() = inflation;
4971 }
4972
4973 pub fn hard_forks(&self) -> HardForks {
4975 self.hard_forks.read().unwrap().clone()
4976 }
4977
4978 pub fn register_hard_fork(&self, new_hard_fork_slot: Slot) {
4979 let bank_slot = self.slot();
4980
4981 let lock = self.freeze_lock();
4982 let bank_frozen = *lock != Hash::default();
4983 if new_hard_fork_slot < bank_slot {
4984 warn!(
4985 "Hard fork at slot {new_hard_fork_slot} ignored, the hard fork is older than the \
4986 bank at slot {bank_slot} that attempted to register it."
4987 );
4988 } else if (new_hard_fork_slot == bank_slot) && bank_frozen {
4989 warn!(
4990 "Hard fork at slot {new_hard_fork_slot} ignored, the hard fork is the same slot \
4991 as the bank at slot {bank_slot} that attempted to register it, but that bank is \
4992 already frozen."
4993 );
4994 } else {
4995 self.hard_forks
4996 .write()
4997 .unwrap()
4998 .register(new_hard_fork_slot);
4999 }
5000 }
5001
5002 pub fn register_hard_forks(&self, new_hard_fork_slots: Option<&Vec<Slot>>) {
5003 if let Some(slots) = new_hard_fork_slots {
5004 slots
5005 .iter()
5006 .for_each(|hard_fork_slot| self.register_hard_fork(*hard_fork_slot));
5007 }
5008 }
5009
5010 pub fn get_account_with_fixed_root_no_cache(
5011 &self,
5012 pubkey: &Pubkey,
5013 ) -> Option<AccountSharedData> {
5014 self.rc
5015 .accounts
5016 .load_with_fixed_root_do_not_populate_read_cache(&self.ancestors, pubkey)
5017 .map(|(acc, _slot)| acc)
5018 }
5019
5020 pub fn get_account(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
5024 self.get_account_modified_slot(pubkey)
5025 .map(|(acc, _slot)| acc)
5026 }
5027
5028 pub fn get_account_with_fixed_root(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
5035 self.get_account_modified_slot_with_fixed_root(pubkey)
5036 .map(|(acc, _slot)| acc)
5037 }
5038
5039 pub fn get_account_modified_slot_with_fixed_root(
5041 &self,
5042 pubkey: &Pubkey,
5043 ) -> Option<(AccountSharedData, Slot)> {
5044 self.load_slow_with_fixed_root(&self.ancestors, pubkey)
5045 }
5046
5047 pub fn get_account_modified_slot(&self, pubkey: &Pubkey) -> Option<(AccountSharedData, Slot)> {
5048 self.load_slow(&self.ancestors, pubkey)
5049 }
5050
5051 fn load_slow(
5052 &self,
5053 ancestors: &Ancestors,
5054 pubkey: &Pubkey,
5055 ) -> Option<(AccountSharedData, Slot)> {
5056 self.rc.accounts.load_without_fixed_root(ancestors, pubkey)
5060 }
5061
5062 fn load_slow_with_fixed_root(
5063 &self,
5064 ancestors: &Ancestors,
5065 pubkey: &Pubkey,
5066 ) -> Option<(AccountSharedData, Slot)> {
5067 self.rc.accounts.load_with_fixed_root(ancestors, pubkey)
5068 }
5069
5070 pub fn get_program_accounts(
5071 &self,
5072 program_id: &Pubkey,
5073 ) -> ScanResult<Vec<KeyedAccountSharedData>> {
5074 self.rc
5075 .accounts
5076 .load_by_program(&self.ancestors, self.bank_id, program_id)
5077 }
5078
5079 pub fn get_filtered_program_accounts<F: Fn(&AccountSharedData) -> bool>(
5080 &self,
5081 program_id: &Pubkey,
5082 filter: F,
5083 ) -> ScanResult<Vec<KeyedAccountSharedData>> {
5084 self.rc.accounts.load_by_program_with_filter(
5085 &self.ancestors,
5086 self.bank_id,
5087 program_id,
5088 filter,
5089 )
5090 }
5091
5092 pub fn get_filtered_indexed_accounts<F: Fn(&AccountSharedData) -> bool>(
5093 &self,
5094 index_key: &IndexKey,
5095 filter: F,
5096 byte_limit_for_scan: Option<usize>,
5097 ) -> ScanResult<Vec<KeyedAccountSharedData>> {
5098 self.rc.accounts.load_by_index_key_with_filter(
5099 &self.ancestors,
5100 self.bank_id,
5101 index_key,
5102 filter,
5103 byte_limit_for_scan,
5104 )
5105 }
5106
5107 pub fn account_indexes_include_key(&self, key: &Pubkey) -> bool {
5108 self.rc.accounts.account_indexes_include_key(key)
5109 }
5110
5111 pub fn scan_all_accounts<F>(&self, scan_func: F) -> ScanResult<()>
5113 where
5114 F: FnMut(Option<(&Pubkey, AccountSharedData, Slot)>),
5115 {
5116 self.rc
5117 .accounts
5118 .scan_all(&self.ancestors, self.bank_id, scan_func)
5119 }
5120
5121 pub fn get_program_accounts_modified_since_parent(
5122 &self,
5123 program_id: &Pubkey,
5124 ) -> Vec<KeyedAccountSharedData> {
5125 self.rc
5126 .accounts
5127 .load_by_program_slot(self.slot(), Some(program_id))
5128 }
5129
5130 pub fn get_transaction_logs(
5131 &self,
5132 address: Option<&Pubkey>,
5133 ) -> Option<Vec<TransactionLogInfo>> {
5134 self.transaction_log_collector
5135 .read()
5136 .unwrap()
5137 .get_logs_for_address(address)
5138 }
5139
5140 pub fn get_all_accounts_modified_since_parent(&self) -> Vec<KeyedAccountSharedData> {
5142 self.rc.accounts.load_by_program_slot(self.slot(), None)
5143 }
5144
5145 fn get_account_modified_since_parent_with_fixed_root(
5147 &self,
5148 pubkey: &Pubkey,
5149 ) -> Option<(AccountSharedData, Slot)> {
5150 let just_self: Ancestors = Ancestors::from(vec![self.slot()]);
5151 if let Some((account, slot)) = self.load_slow_with_fixed_root(&just_self, pubkey)
5152 && slot == self.slot()
5153 {
5154 return Some((account, slot));
5155 }
5156 None
5157 }
5158
5159 pub fn get_largest_accounts(
5160 &self,
5161 num: usize,
5162 filter_by_address: &HashSet<Pubkey>,
5163 filter: AccountAddressFilter,
5164 ) -> ScanResult<Vec<(Pubkey, u64)>> {
5165 self.rc.accounts.load_largest_accounts(
5166 &self.ancestors,
5167 self.bank_id,
5168 num,
5169 filter_by_address,
5170 filter,
5171 )
5172 }
5173
5174 pub fn transaction_count(&self) -> u64 {
5176 self.transaction_count.load(Relaxed)
5177 }
5178
5179 pub fn non_vote_transaction_count_since_restart(&self) -> u64 {
5184 self.non_vote_transaction_count_since_restart.load(Relaxed)
5185 }
5186
5187 pub fn executed_transaction_count(&self) -> u64 {
5189 self.transaction_count()
5190 .saturating_sub(self.parent().map_or(0, |parent| parent.transaction_count()))
5191 }
5192
5193 pub fn transaction_error_count(&self) -> u64 {
5194 self.transaction_error_count.load(Relaxed)
5195 }
5196
5197 pub fn transaction_entries_count(&self) -> u64 {
5198 self.transaction_entries_count.load(Relaxed)
5199 }
5200
5201 pub fn transactions_per_entry_max(&self) -> u64 {
5202 self.transactions_per_entry_max.load(Relaxed)
5203 }
5204
5205 pub fn max_data_shreds_per_slot(&self) -> u32 {
5206 self.max_data_shreds_per_slot_for_slot(self.slot())
5207 }
5208
5209 pub fn max_code_shreds_per_slot(&self) -> u32 {
5210 self.max_code_shreds_per_slot_for_slot(self.slot())
5211 }
5212
5213 pub fn max_data_shreds_per_slot_for_slot(&self, slot: Slot) -> u32 {
5218 self.slot_params_at_slot(slot).max_data_shreds_per_slot()
5219 }
5220
5221 pub fn max_code_shreds_per_slot_for_slot(&self, slot: Slot) -> u32 {
5226 self.slot_params_at_slot(slot).max_code_shreds_per_slot()
5227 }
5228
5229 pub fn max_entry_bytes_per_slot(&self) -> u64 {
5230 self.entry_bytes_budget().slot_limit()
5231 }
5232
5233 pub fn entry_bytes_budget(&self) -> &EntryBytesBudget {
5234 &self.entry_bytes_consumed
5235 }
5236
5237 fn increment_transaction_count(&self, tx_count: u64) {
5238 self.transaction_count.fetch_add(tx_count, Relaxed);
5239 }
5240
5241 fn increment_non_vote_transaction_count_since_restart(&self, tx_count: u64) {
5242 self.non_vote_transaction_count_since_restart
5243 .fetch_add(tx_count, Relaxed);
5244 }
5245
5246 pub fn signature_count(&self) -> u64 {
5247 self.signature_count.load(Relaxed)
5248 }
5249
5250 fn increment_signature_count(&self, signature_count: u64) {
5251 self.signature_count.fetch_add(signature_count, Relaxed);
5252 }
5253
5254 pub fn get_signature_status_processed_since_parent(
5255 &self,
5256 signature: &Signature,
5257 ) -> Option<Result<()>> {
5258 if let Some((slot, status)) = self.get_signature_status_slot(signature)
5259 && slot <= self.slot()
5260 {
5261 return Some(status);
5262 }
5263 None
5264 }
5265
5266 pub fn get_signature_status_with_blockhash(
5267 &self,
5268 signature: &Signature,
5269 blockhash: &Hash,
5270 ) -> Option<Result<()>> {
5271 let rcache = self.status_cache.read().unwrap();
5272 rcache
5273 .get_status(signature, blockhash, &self.ancestors)
5274 .map(|v| v.1)
5275 }
5276
5277 pub fn get_committed_transaction_status_and_slot(
5278 &self,
5279 message_hash: &Hash,
5280 transaction_blockhash: &Hash,
5281 ) -> Option<(Slot, bool)> {
5282 let rcache = self.status_cache.read().unwrap();
5283 rcache
5284 .get_status(message_hash, transaction_blockhash, &self.ancestors)
5285 .map(|(slot, status)| (slot, status.is_ok()))
5286 }
5287
5288 pub fn get_signature_status_slot(&self, signature: &Signature) -> Option<(Slot, Result<()>)> {
5289 let rcache = self.status_cache.read().unwrap();
5290 rcache.get_status_any_blockhash(signature, &self.ancestors)
5291 }
5292
5293 pub fn get_signature_status(&self, signature: &Signature) -> Option<Result<()>> {
5294 self.get_signature_status_slot(signature).map(|v| v.1)
5295 }
5296
5297 pub fn has_signature(&self, signature: &Signature) -> bool {
5298 self.get_signature_status_slot(signature).is_some()
5299 }
5300
5301 fn hash_internal_state(&self) -> Hash {
5304 let measure_total = Measure::start("");
5305 let slot = self.slot();
5306
5307 let mut hash = hashv(&[
5308 self.parent_hash.as_ref(),
5309 &self.signature_count().to_le_bytes(),
5310 self.last_blockhash().as_ref(),
5311 ]);
5312
5313 let accounts_lt_hash_checksum = {
5314 let accounts_lt_hash = &*self.accounts_lt_hash.lock().unwrap();
5315 let lt_hash_bytes = bytemuck::must_cast_slice(&accounts_lt_hash.0.0);
5316 hash = hashv(&[hash.as_ref(), lt_hash_bytes]);
5317 accounts_lt_hash.0.checksum()
5318 };
5319
5320 let buf = self
5321 .hard_forks
5322 .read()
5323 .unwrap()
5324 .get_hash_data(slot, self.parent_slot());
5325 if let Some(buf) = buf {
5326 let hard_forked_hash = hashv(&[hash.as_ref(), &buf]);
5327 warn!("hard fork at slot {slot} by hashing {buf:?}: {hash} => {hard_forked_hash}");
5328 hash = hard_forked_hash;
5329 }
5330
5331 #[cfg(feature = "dev-context-only-utils")]
5332 let hash_override = self
5333 .hash_overrides
5334 .lock()
5335 .unwrap()
5336 .get_bank_hash_override(slot)
5337 .copied()
5338 .inspect(|&hash_override| {
5339 if hash_override != hash {
5340 info!(
5341 "bank: slot: {}: overrode bank hash: {} with {}",
5342 self.slot(),
5343 hash,
5344 hash_override
5345 );
5346 }
5347 });
5348 #[cfg(feature = "dev-context-only-utils")]
5352 let hash = hash_override.unwrap_or(std::hint::black_box(hash));
5353
5354 let bank_hash_stats = self.bank_hash_stats.load();
5355
5356 let total_us = measure_total.end_as_us();
5357
5358 datapoint_info!(
5359 "bank-hash_internal_state",
5360 ("slot", slot, i64),
5361 ("total_us", total_us, i64),
5362 );
5363 info!(
5364 "bank frozen: {slot} hash: {hash} signature_count: {} last_blockhash: {} \
5365 capitalization: {}, accounts_lt_hash checksum: {accounts_lt_hash_checksum}, stats: \
5366 {bank_hash_stats:?}",
5367 self.signature_count(),
5368 self.last_blockhash(),
5369 self.capitalization(),
5370 );
5371 hash
5372 }
5373
5374 pub fn run_final_hash_calc(&self) {
5377 self.force_flush_accounts_cache();
5378 _ = self.verify_accounts(None);
5380 }
5381
5382 #[must_use]
5395 fn verify_accounts(&self, calculated_accounts_lt_hash: Option<&AccountsLtHash>) -> bool {
5396 let accounts_db = &self.rc.accounts.accounts_db;
5397
5398 fn check_lt_hash(
5399 expected_accounts_lt_hash: &AccountsLtHash,
5400 calculated_accounts_lt_hash: &AccountsLtHash,
5401 ) -> bool {
5402 let is_ok = calculated_accounts_lt_hash == expected_accounts_lt_hash;
5403 if !is_ok {
5404 let expected = expected_accounts_lt_hash.0.checksum();
5405 let calculated = calculated_accounts_lt_hash.0.checksum();
5406 error!(
5407 "Verifying accounts failed: accounts lattice hashes do not match, expected: \
5408 {expected}, calculated: {calculated}",
5409 );
5410 }
5411 is_ok
5412 }
5413
5414 info!("Verifying accounts...");
5415 let start = Instant::now();
5416 let expected_accounts_lt_hash = self.accounts_lt_hash.lock().unwrap().clone();
5417 let is_ok = if let Some(calculated_accounts_lt_hash) = calculated_accounts_lt_hash {
5418 check_lt_hash(&expected_accounts_lt_hash, calculated_accounts_lt_hash)
5419 } else {
5420 let calculated_accounts_lt_hash =
5421 accounts_db.calculate_accounts_lt_hash_at_startup_from_index(&self.ancestors);
5422 check_lt_hash(&expected_accounts_lt_hash, &calculated_accounts_lt_hash)
5423 };
5424 info!("Verifying accounts... Done in {:?}", start.elapsed());
5425 is_ok
5426 }
5427
5428 pub fn get_snapshot_storages(&self, base_slot: Option<Slot>) -> Vec<Arc<AccountStorageEntry>> {
5432 let start_slot = base_slot.map_or(0, |slot| slot.saturating_add(1));
5434 let requested_slots = start_slot..=self.slot();
5436
5437 self.rc.accounts.accounts_db.get_storages(requested_slots).0
5438 }
5439
5440 #[must_use]
5441 fn verify_hash(&self) -> bool {
5442 assert!(self.is_frozen());
5443 let calculated_hash = self.hash_internal_state();
5444 let expected_hash = self.hash();
5445
5446 if calculated_hash == expected_hash {
5447 true
5448 } else {
5449 warn!(
5450 "verify failed: slot: {}, {} (calculated) != {} (expected)",
5451 self.slot(),
5452 calculated_hash,
5453 expected_hash
5454 );
5455 false
5456 }
5457 }
5458
5459 pub fn verify_transaction(
5461 &self,
5462 tx: VersionedTransaction,
5463 verification_mode: TransactionVerificationMode,
5464 ) -> Result<RuntimeTransaction<SanitizedTransaction>> {
5465 if !self.feature_set.snapshot().enable_tx_v1
5467 && tx.version() == TransactionVersion::Number(1)
5468 {
5469 return Err(TransactionError::UnsupportedVersion);
5470 }
5471
5472 let serialized_message = tx.message.serialize();
5473 self.verify_transaction_with_serialized_message(tx, &serialized_message, verification_mode)
5474 }
5475
5476 pub fn verify_transaction_with_serialized_message(
5483 &self,
5484 tx: VersionedTransaction,
5485 serialized_message: &[u8],
5486 verification_mode: TransactionVerificationMode,
5487 ) -> Result<RuntimeTransaction<SanitizedTransaction>> {
5488 let enable_tx_v1 = self.feature_set.snapshot().enable_tx_v1;
5490 if !enable_tx_v1 && tx.version() == TransactionVersion::Number(1) {
5491 return Err(TransactionError::UnsupportedVersion);
5492 }
5493 let max_transaction_size = match tx.version() {
5494 TransactionVersion::Number(1) if enable_tx_v1 => {
5495 solana_message::v1::MAX_TRANSACTION_SIZE
5496 }
5497 _ => PACKET_DATA_SIZE,
5498 } as u64;
5499
5500 let enable_instruction_account_limit =
5501 self.feature_set.snapshot().limit_instruction_accounts;
5502
5503 let sanitized_tx = {
5506 let size =
5507 wincode::serialized_size(&tx).map_err(|_| TransactionError::SanitizeFailure)?;
5508 if size > max_transaction_size {
5509 return Err(TransactionError::SanitizeFailure);
5510 }
5511
5512 if tx.message.instructions().len()
5514 > solana_transaction_context::MAX_INSTRUCTION_TRACE_LENGTH
5515 {
5516 return Err(solana_transaction_error::TransactionError::SanitizeFailure);
5517 }
5518
5519 let message_hash = if verification_mode == TransactionVerificationMode::FullVerification
5520 {
5521 tx.verify_and_hash_message()?
5522 } else {
5523 VersionedMessage::hash_raw_message(serialized_message)
5524 };
5525
5526 RuntimeTransaction::try_create(
5527 tx,
5528 MessageHash::Precomputed(message_hash),
5529 None,
5530 self,
5531 self.get_reserved_account_keys(),
5532 enable_instruction_account_limit,
5533 )
5534 }?;
5535
5536 Ok(sanitized_tx)
5537 }
5538
5539 pub fn check_reserved_keys(&self, tx: &impl SVMMessage) -> Result<()> {
5543 let reserved_keys = self.get_reserved_account_keys();
5546 for (index, key) in tx.account_keys().iter().enumerate() {
5547 if tx.is_writable(index) && reserved_keys.contains(key) {
5548 return Err(TransactionError::ResanitizationNeeded);
5549 }
5550 }
5551
5552 Ok(())
5553 }
5554
5555 pub fn calculate_capitalization_for_tests(&self) -> u64 {
5565 self.rc
5566 .accounts
5567 .accounts_db
5568 .calculate_capitalization_at_startup_from_index(&self.ancestors)
5569 }
5570
5571 pub fn set_capitalization_for_tests(&self, capitalization: u64) {
5576 self.capitalization.store(capitalization, Relaxed);
5577 }
5578
5579 pub fn get_snapshot_hash(&self) -> SnapshotHash {
5583 SnapshotHash::new(self.accounts_lt_hash.lock().unwrap().0.checksum())
5584 }
5585
5586 pub fn verify_snapshot_bank(
5589 &self,
5590 skip_shrink: bool,
5591 force_clean: bool,
5592 latest_full_snapshot_slot: Slot,
5593 calculated_accounts_lt_hash: Option<&AccountsLtHash>,
5594 ) -> bool {
5595 let (verified_accounts, verify_accounts_time_us) = measure_us!({
5596 let should_verify_accounts = !self.rc.accounts.accounts_db.skip_initial_hash_calc;
5597 if should_verify_accounts {
5598 self.verify_accounts(calculated_accounts_lt_hash)
5599 } else {
5600 info!("Verifying accounts... Skipped.");
5601 true
5602 }
5603 });
5604
5605 let (_, clean_time_us) = measure_us!({
5606 let should_clean = force_clean || (!skip_shrink && self.slot() > 0);
5607 if should_clean {
5608 info!("Cleaning...");
5609 self.rc
5614 .accounts
5615 .accounts_db
5616 .clean_accounts(Some(latest_full_snapshot_slot), true);
5617 info!("Cleaning... Done.");
5618 } else {
5619 info!("Cleaning... Skipped.");
5620 }
5621 });
5622
5623 let (_, shrink_time_us) = measure_us!({
5624 let should_shrink = !skip_shrink && self.slot() > 0;
5625 if should_shrink {
5626 info!("Shrinking...");
5627 self.rc.accounts.accounts_db.shrink_all_slots(
5628 true,
5629 Some(self.slot()),
5631 );
5632 info!("Shrinking... Done.");
5633 } else {
5634 info!("Shrinking... Skipped.");
5635 }
5636 });
5637
5638 info!("Verifying bank...");
5639 let (verified_bank, verify_bank_time_us) = measure_us!(self.verify_hash());
5640 info!("Verifying bank... Done.");
5641
5642 datapoint_info!(
5643 "verify_snapshot_bank",
5644 ("clean_us", clean_time_us, i64),
5645 ("shrink_us", shrink_time_us, i64),
5646 ("verify_accounts_us", verify_accounts_time_us, i64),
5647 ("verify_bank_us", verify_bank_time_us, i64),
5648 );
5649
5650 verified_accounts && verified_bank
5651 }
5652
5653 pub fn hashes_per_tick(&self) -> Option<u64> {
5655 *self.hashes_per_tick.read().unwrap()
5656 }
5657
5658 pub fn ticks_per_slot(&self) -> u64 {
5660 self.ticks_per_slot
5661 }
5662
5663 pub fn ticks_per_second(&self) -> u64 {
5665 let ticks_per_slot = u128::from(self.ticks_per_slot.max(1));
5666 let ns_per_tick = self.ns_per_slot.saturating_div(ticks_per_slot).max(1);
5667 u64::try_from(1_000_000_000u128.saturating_div(ns_per_tick))
5668 .expect("ticks per second must fit in u64")
5669 }
5670
5671 pub fn slots_per_year(&self) -> f64 {
5673 self.slots_per_year
5674 }
5675
5676 pub fn tick_height(&self) -> u64 {
5678 self.tick_height.load(Relaxed)
5679 }
5680
5681 pub fn inflation(&self) -> Inflation {
5683 *self.inflation.read().unwrap()
5684 }
5685
5686 pub fn rent_collector(&self) -> &RentCollector {
5688 &self.rent_collector
5689 }
5690
5691 pub fn capitalization(&self) -> u64 {
5693 self.capitalization.load(Relaxed)
5694 }
5695
5696 pub fn max_tick_height(&self) -> u64 {
5698 self.max_tick_height
5699 }
5700
5701 pub fn block_height(&self) -> u64 {
5703 self.block_height
5704 }
5705
5706 pub fn get_slots_in_epoch(&self, epoch: Epoch) -> u64 {
5708 self.epoch_schedule().get_slots_in_epoch(epoch)
5709 }
5710
5711 pub fn get_leader_schedule_epoch(&self, slot: Slot) -> Epoch {
5714 self.epoch_schedule().get_leader_schedule_epoch(slot)
5715 }
5716
5717 fn update_stakes_cache(
5719 &self,
5720 txs: &[impl SVMMessage],
5721 processing_results: &[TransactionProcessingResult],
5722 ) {
5723 debug_assert_eq!(txs.len(), processing_results.len());
5724 let new_warmup_cooldown_rate_epoch = self.new_warmup_cooldown_rate_epoch();
5725 let use_fixed_point_stake_math = self.use_fixed_point_stake_math();
5726 txs.iter()
5727 .zip(processing_results)
5728 .filter_map(|(tx, processing_result)| {
5729 processing_result
5730 .processed_transaction()
5731 .map(|processed_tx| (tx, processed_tx))
5732 })
5733 .filter_map(|(tx, processed_tx)| {
5734 processed_tx
5735 .executed_transaction()
5736 .map(|executed_tx| (tx, executed_tx))
5737 })
5738 .filter(|(_, executed_tx)| executed_tx.was_successful())
5739 .flat_map(|(tx, executed_tx)| {
5740 let num_account_keys = tx.account_keys().len();
5741 let loaded_tx = &executed_tx.loaded_transaction;
5742 loaded_tx.accounts.iter().take(num_account_keys)
5743 })
5744 .for_each(|(pubkey, account)| {
5745 self.stakes_cache.check_and_store(
5748 pubkey,
5749 account,
5750 new_warmup_cooldown_rate_epoch,
5751 use_fixed_point_stake_math,
5752 );
5753 });
5754 }
5755
5756 pub fn vote_accounts(&self) -> Arc<VoteAccountsHashMap> {
5759 let stakes = self.stakes_cache.stakes();
5760 Arc::from(stakes.vote_accounts())
5761 }
5762
5763 pub fn get_vote_account(&self, vote_account: &Pubkey) -> Option<VoteAccount> {
5765 let stakes = self.stakes_cache.stakes();
5766 let vote_account = stakes.vote_accounts().get(vote_account)?;
5767 Some(vote_account.clone())
5768 }
5769
5770 pub fn current_epoch_stakes(&self) -> &VersionedEpochStakes {
5772 self.epoch_stakes
5775 .get(&self.epoch.saturating_add(1))
5776 .expect("Current epoch stakes must exist")
5777 }
5778
5779 pub fn epoch_stakes(&self, epoch: Epoch) -> Option<&VersionedEpochStakes> {
5781 self.epoch_stakes.get(&epoch)
5782 }
5783
5784 pub fn verify_certificate(
5786 &self,
5787 cert: UnverifiedCertificate,
5788 ) -> std::result::Result<Certificate, CertVerifyError> {
5789 let slot = cert.cert_type.slot();
5790 let epoch_stakes = self
5791 .epoch_stakes_from_slot(slot)
5792 .ok_or(CertVerifyError::MissingRankMap)?;
5793 let key_to_rank_map = epoch_stakes.bls_pubkey_to_rank_map();
5794 let total_stake = key_to_rank_map.total_stake();
5795
5796 let cert =
5797 cert_verify::verify_certificate(cert, key_to_rank_map.len(), total_stake, |rank| {
5798 key_to_rank_map
5799 .get_pubkey_stake_entry(rank)
5800 .map(|entry| (entry.stake, entry.bls_pubkey))
5801 })?;
5802
5803 Ok(cert)
5804 }
5805
5806 pub fn epoch_stakes_map(&self) -> &HashMap<Epoch, VersionedEpochStakes> {
5807 &self.epoch_stakes
5808 }
5809
5810 pub fn current_epoch_staked_nodes(&self) -> Arc<HashMap<Pubkey, u64>> {
5812 self.current_epoch_stakes().stakes().staked_nodes()
5813 }
5814
5815 pub fn epoch_staked_nodes(&self, epoch: Epoch) -> Option<Arc<HashMap<Pubkey, u64>>> {
5817 Some(self.epoch_stakes.get(&epoch)?.stakes().staked_nodes())
5818 }
5819
5820 pub fn epoch_total_stake(&self, epoch: Epoch) -> Option<u64> {
5822 self.epoch_stakes
5823 .get(&epoch)
5824 .map(|epoch_stakes| epoch_stakes.total_stake())
5825 }
5826
5827 pub fn get_current_epoch_total_stake(&self) -> u64 {
5829 self.current_epoch_stakes().total_stake()
5830 }
5831
5832 pub fn epoch_vote_accounts(&self, epoch: Epoch) -> Option<&VoteAccountsHashMap> {
5834 let epoch_stakes = self.epoch_stakes.get(&epoch)?.stakes();
5835 Some(epoch_stakes.vote_accounts().as_ref())
5836 }
5837
5838 pub fn get_current_epoch_vote_accounts(&self) -> &VoteAccountsHashMap {
5840 self.current_epoch_stakes()
5841 .stakes()
5842 .vote_accounts()
5843 .as_ref()
5844 }
5845
5846 pub fn epoch_authorized_voter(&self, vote_account: &Pubkey) -> Option<&Pubkey> {
5849 self.epoch_stakes
5850 .get(&self.epoch)
5851 .expect("Epoch stakes for bank's own epoch must exist")
5852 .epoch_authorized_voters()
5853 .get(vote_account)
5854 }
5855
5856 pub fn epoch_vote_accounts_for_node_id(&self, node_id: &Pubkey) -> Option<&NodeVoteAccounts> {
5859 self.epoch_stakes
5860 .get(&self.epoch)
5861 .expect("Epoch stakes for bank's own epoch must exist")
5862 .node_id_to_vote_accounts()
5863 .get(node_id)
5864 }
5865
5866 pub fn epoch_node_id_to_stake(&self, epoch: Epoch, node_id: &Pubkey) -> Option<u64> {
5868 self.epoch_stakes(epoch)
5869 .and_then(|epoch_stakes| epoch_stakes.node_id_to_stake(node_id))
5870 }
5871
5872 pub fn total_epoch_stake(&self) -> u64 {
5874 self.epoch_stakes
5875 .get(&self.epoch)
5876 .expect("Epoch stakes for bank's own epoch must exist")
5877 .total_stake()
5878 }
5879
5880 pub fn epoch_vote_account_stake(&self, vote_account: &Pubkey) -> u64 {
5882 *self
5883 .epoch_vote_accounts(self.epoch())
5884 .expect("Bank epoch vote accounts must contain entry for the bank's own epoch")
5885 .get(vote_account)
5886 .map(|(stake, _)| stake)
5887 .unwrap_or(&0)
5888 }
5889
5890 pub fn get_epoch_and_slot_index(&self, slot: Slot) -> (Epoch, SlotIndex) {
5896 self.epoch_schedule().get_epoch_and_slot_index(slot)
5897 }
5898
5899 pub fn get_epoch_info(&self) -> EpochInfo {
5900 let absolute_slot = self.slot();
5901 let block_height = self.block_height();
5902 let (epoch, slot_index) = self.get_epoch_and_slot_index(absolute_slot);
5903 let slots_in_epoch = self.get_slots_in_epoch(epoch);
5904 let transaction_count = Some(self.transaction_count());
5905 EpochInfo {
5906 epoch,
5907 slot_index,
5908 slots_in_epoch,
5909 absolute_slot,
5910 block_height,
5911 transaction_count,
5912 }
5913 }
5914
5915 pub fn is_empty(&self) -> bool {
5916 !self.is_delta.load(Relaxed)
5917 }
5918
5919 pub fn add_mockup_builtin(&mut self, program_id: Pubkey, builtin: BuiltinFunctionRegisterer) {
5920 self.add_builtin(
5921 program_id,
5922 "mockup",
5923 ProgramCacheEntry::new_builtin(self.slot, 0, builtin),
5924 );
5925 }
5926
5927 pub fn add_precompile(&mut self, program_id: &Pubkey) {
5928 debug!("Adding precompiled program {program_id}");
5929 self.add_precompiled_account(program_id);
5930 debug!("Added precompiled program {program_id:?}");
5931 }
5932
5933 pub(crate) fn clean_accounts(&self) {
5938 let highest_slot_to_clean = self.slot().saturating_sub(1);
5945
5946 self.rc
5947 .accounts
5948 .accounts_db
5949 .clean_accounts(Some(highest_slot_to_clean), false);
5950 }
5951
5952 pub fn print_accounts_stats(&self) {
5953 self.rc.accounts.accounts_db.print_accounts_stats("");
5954 }
5955
5956 pub fn shrink_candidate_slots(&self) -> usize {
5957 self.rc
5958 .accounts
5959 .accounts_db
5960 .shrink_candidate_slots(self.epoch_schedule())
5961 }
5962
5963 pub(crate) fn shrink_ancient_slots(&self) {
5964 self.rc
5965 .accounts
5966 .accounts_db
5967 .shrink_ancient_slots(self.epoch_schedule())
5968 }
5969
5970 pub fn read_cost_tracker(&self) -> LockResult<RwLockReadGuard<'_, CostTracker>> {
5971 self.cost_tracker.read()
5972 }
5973
5974 pub fn write_cost_tracker(&self) -> LockResult<RwLockWriteGuard<'_, CostTracker>> {
5975 self.cost_tracker.write()
5976 }
5977
5978 pub fn should_bank_still_be_processing_txs(
5981 bank_creation_time: &Instant,
5982 max_tx_ingestion_nanos: u128,
5983 ) -> bool {
5984 bank_creation_time.elapsed().as_nanos() <= max_tx_ingestion_nanos
5986 }
5987
5988 pub fn deactivate_feature(&mut self, id: &Pubkey) {
5989 let mut feature_set = Arc::make_mut(&mut self.feature_set).clone();
5990 feature_set.deactivate(id);
5991 self.feature_set = Arc::new(feature_set);
5992 self.refresh_slot_params();
5993 }
5994
5995 pub fn activate_feature(&mut self, id: &Pubkey) {
5996 let mut feature_set = Arc::make_mut(&mut self.feature_set).clone();
5997 feature_set.activate(id, 0);
5998 self.feature_set = Arc::new(feature_set);
5999 self.refresh_slot_params();
6000 }
6001
6002 pub fn fill_bank_with_ticks_for_tests(&self) {
6003 self.do_fill_bank_with_ticks_for_tests(&BankWithScheduler::no_scheduler_available())
6004 }
6005
6006 pub(crate) fn do_fill_bank_with_ticks_for_tests(&self, scheduler: &InstalledSchedulerRwLock) {
6007 if self.tick_height.load(Relaxed) < self.max_tick_height {
6008 let last_blockhash = self.last_blockhash();
6009 while self.last_blockhash() == last_blockhash {
6010 self.register_tick(&Hash::new_unique(), scheduler)
6011 }
6012 } else {
6013 warn!("Bank already reached max tick height, cannot fill it with more ticks");
6014 }
6015 }
6016
6017 pub fn get_reserved_account_keys(&self) -> &HashSet<Pubkey> {
6020 &self.reserved_account_keys.active
6021 }
6022
6023 fn initialize_after_snapshot_restore<F, TP>(&mut self, rewards_thread_pool_builder: F)
6026 where
6027 F: FnOnce() -> TP,
6028 TP: std::borrow::Borrow<ThreadPool>,
6029 {
6030 self.transaction_processor =
6031 TransactionBatchProcessor::new_uninitialized(self.slot, self.epoch);
6032 if let Some(compute_budget) = &self.compute_budget {
6033 self.transaction_processor
6034 .set_execution_cost(compute_budget.to_cost());
6035 }
6036
6037 self.compute_and_apply_features_after_snapshot_restore();
6038 self.stakes_cache.refresh_delegated_stakes(
6039 self.new_warmup_cooldown_rate_epoch(),
6040 self.use_fixed_point_stake_math(),
6041 );
6042
6043 self.recalculate_partitioned_rewards_if_active(rewards_thread_pool_builder);
6044
6045 self.transaction_processor
6046 .fill_missing_sysvar_cache_entries(self);
6047 }
6048
6049 fn compute_and_apply_genesis_features(&mut self) {
6051 let feature_set = self.compute_active_feature_set(false).0;
6053 self.feature_set = Arc::new(feature_set);
6054
6055 if self
6058 .feature_set
6059 .snapshot()
6060 .deprecate_rent_exemption_threshold
6061 {
6062 self.rent_collector.deprecate_rent_exemption_threshold();
6063 }
6064
6065 self.add_builtin_program_accounts();
6067
6068 self.apply_activated_features();
6069 }
6070
6071 fn compute_and_apply_features_after_snapshot_restore(&mut self) {
6074 let feature_set = self.compute_active_feature_set(false).0;
6076 self.feature_set = Arc::new(feature_set);
6077
6078 self.apply_activated_features();
6079 self.assert_bank_matches_slot_params();
6080 }
6081
6082 fn compute_and_apply_new_feature_activations(&mut self) {
6084 let include_pending = true;
6085 let (feature_set, new_feature_activations) =
6086 self.compute_active_feature_set(include_pending);
6087 self.feature_set = Arc::new(feature_set);
6088 self.refresh_slot_params();
6089
6090 for feature_id in new_feature_activations.iter() {
6092 if let Some(mut account) = self.get_account_with_fixed_root(feature_id)
6093 && let Some(mut feature) = feature::state::from_account(&account)
6094 {
6095 feature.activated_at = Some(self.slot());
6096 if feature::state::to_account(&feature, &mut account).is_some() {
6097 self.store_account(feature_id, &account);
6098 }
6099 info!("Feature {} activated at slot {}", feature_id, self.slot());
6100 }
6101 }
6102
6103 self.reserved_account_keys = {
6105 let mut reserved_keys = ReservedAccountKeys::clone(&self.reserved_account_keys);
6106 reserved_keys.update_active_set(&self.feature_set);
6107 Arc::new(reserved_keys)
6108 };
6109
6110 if new_feature_activations.contains(&feature_set::deprecate_rent_exemption_threshold::id())
6111 {
6112 self.rent_collector.deprecate_rent_exemption_threshold();
6113 self.update_rent();
6114 }
6115
6116 let rent_feature_gates = [
6122 (
6123 feature_set::set_lamports_per_byte_to_6333::id(),
6124 feature_set::set_lamports_per_byte_to_6333::LAMPORTS_PER_BYTE,
6125 ),
6126 (
6127 feature_set::set_lamports_per_byte_to_5080::id(),
6128 feature_set::set_lamports_per_byte_to_5080::LAMPORTS_PER_BYTE,
6129 ),
6130 (
6131 feature_set::set_lamports_per_byte_to_2575::id(),
6132 feature_set::set_lamports_per_byte_to_2575::LAMPORTS_PER_BYTE,
6133 ),
6134 (
6135 feature_set::set_lamports_per_byte_to_1322::id(),
6136 feature_set::set_lamports_per_byte_to_1322::LAMPORTS_PER_BYTE,
6137 ),
6138 (
6139 feature_set::set_lamports_per_byte_to_696::id(),
6140 feature_set::set_lamports_per_byte_to_696::LAMPORTS_PER_BYTE,
6141 ),
6142 ];
6143 for (feature_id, lamports_per_byte) in rent_feature_gates {
6144 if new_feature_activations.contains(&feature_id) {
6145 self.rent_collector.rent.lamports_per_byte = lamports_per_byte;
6146 self.update_rent();
6147 }
6148 }
6149
6150 if new_feature_activations.contains(&feature_set::set_lamports_per_byte_to_6960::id()) {
6155 self.rent_collector.rent.lamports_per_byte =
6156 feature_set::set_lamports_per_byte_to_6960::LAMPORTS_PER_BYTE;
6157 self.update_rent();
6158 }
6159
6160 if new_feature_activations.contains(&feature_set::pico_inflation::id()) {
6161 *self.inflation.write().unwrap() = Inflation::pico();
6162 self.fee_rate_governor.burn_percent = solana_fee_calculator::DEFAULT_BURN_PERCENT;
6163 }
6164
6165 if !new_feature_activations.is_disjoint(&self.feature_set.full_inflation_features_enabled())
6166 {
6167 *self.inflation.write().unwrap() = Inflation::full();
6168 self.fee_rate_governor.burn_percent = solana_fee_calculator::DEFAULT_BURN_PERCENT;
6169 }
6170
6171 self.apply_slot_time_persistent_changes();
6173 self.apply_slot_time_runtime_changes();
6174
6175 self.apply_new_builtin_program_feature_transitions(&new_feature_activations);
6176
6177 if new_feature_activations.contains(&feature_set::replace_spl_token_with_p_token::id())
6178 && let Err(e) = self.upgrade_loader_v2_program_with_loader_v3_program(
6179 &feature_set::replace_spl_token_with_p_token::SPL_TOKEN_PROGRAM_ID,
6180 &feature_set::replace_spl_token_with_p_token::PTOKEN_PROGRAM_BUFFER,
6181 self.feature_set
6182 .snapshot()
6183 .relax_programdata_account_check_migration,
6184 "replace_spl_token_with_p_token",
6185 )
6186 {
6187 warn!(
6188 "Failed to replace SPL Token with p-token buffer '{}': {e}",
6189 feature_set::replace_spl_token_with_p_token::PTOKEN_PROGRAM_BUFFER,
6190 );
6191 }
6192
6193 if new_feature_activations.contains(&feature_set::upgrade_bpf_stake_program_to_v5::id())
6194 && let Err(e) = self.upgrade_core_bpf_program(
6195 &solana_sdk_ids::stake::id(),
6196 &feature_set::upgrade_bpf_stake_program_to_v5::buffer::id(),
6197 "upgrade_stake_program_to_v5",
6198 )
6199 {
6200 error!("Failed to upgrade Core BPF Stake program: {e}");
6201 }
6202
6203 if new_feature_activations.contains(&feature_set::upgrade_bpf_stake_program_to_v5_1::id())
6204 && let Err(e) = self.upgrade_core_bpf_program(
6205 &solana_sdk_ids::stake::id(),
6206 &feature_set::upgrade_bpf_stake_program_to_v5_1::buffer::id(),
6207 "upgrade_stake_program_to_v5_1",
6208 )
6209 {
6210 error!("Failed to upgrade Core BPF Stake program: {e}");
6211 }
6212 }
6213
6214 fn apply_new_builtin_program_feature_transitions(
6215 &mut self,
6216 new_feature_activations: &AHashSet<Pubkey>,
6217 ) {
6218 for builtin in BUILTINS.iter() {
6219 if let Some(feature_id) = builtin.enable_feature_id
6220 && new_feature_activations.contains(&feature_id)
6221 {
6222 self.add_builtin(
6223 builtin.program_id,
6224 builtin.name,
6225 ProgramCacheEntry::new_builtin(
6226 self.feature_set.activated_slot(&feature_id).unwrap_or(0),
6227 builtin.name.len(),
6228 builtin.register_fn,
6229 ),
6230 );
6231 }
6232
6233 if let Some(core_bpf_migration_config) = &builtin.core_bpf_migration_config {
6234 if new_feature_activations.contains(&core_bpf_migration_config.feature_id)
6238 && let Err(e) = self.migrate_builtin_to_core_bpf(
6239 &builtin.program_id,
6240 core_bpf_migration_config,
6241 self.feature_set
6242 .snapshot()
6243 .relax_programdata_account_check_migration,
6244 )
6245 {
6246 warn!(
6247 "Failed to migrate builtin {} to Core BPF: {}",
6248 builtin.name, e
6249 );
6250 }
6251 };
6252 }
6253
6254 for stateless_builtin in STATELESS_BUILTINS.iter() {
6258 if let Some(core_bpf_migration_config) = &stateless_builtin.core_bpf_migration_config
6259 && new_feature_activations.contains(&core_bpf_migration_config.feature_id)
6260 && let Err(e) = self.migrate_builtin_to_core_bpf(
6261 &stateless_builtin.program_id,
6262 core_bpf_migration_config,
6263 self.feature_set
6264 .snapshot()
6265 .relax_programdata_account_check_migration,
6266 )
6267 {
6268 warn!(
6269 "Failed to migrate stateless builtin {} to Core BPF: {}",
6270 stateless_builtin.name, e
6271 );
6272 }
6273 }
6274
6275 for precompile in get_precompiles() {
6276 if let Some(feature_id) = &precompile.feature
6277 && new_feature_activations.contains(feature_id)
6278 {
6279 self.add_precompile(&precompile.program_id);
6280 }
6281 }
6282 }
6283
6284 fn adjust_sysvar_balance_for_rent(&self, account: &mut AccountSharedData) {
6285 account.set_lamports(
6286 self.get_minimum_balance_for_rent_exemption(account.data().len())
6287 .max(account.lamports()),
6288 );
6289 }
6290
6291 fn compute_active_feature_set(&self, include_pending: bool) -> (FeatureSet, AHashSet<Pubkey>) {
6294 let mut active = self.feature_set.active().clone();
6295 let mut inactive = AHashSet::new();
6296 let mut pending = AHashSet::new();
6297 let slot = self.slot();
6298
6299 for feature_id in self.feature_set.inactive() {
6300 let mut activated = None;
6301 if let Some(account) = self.get_account_with_fixed_root(feature_id)
6302 && let Some(feature) = feature::state::from_account(&account)
6303 {
6304 match feature.activated_at {
6305 None if include_pending => {
6306 pending.insert(*feature_id);
6308 activated = Some(slot);
6309 }
6310 Some(activation_slot) if slot >= activation_slot => {
6311 activated = Some(activation_slot);
6313 }
6314 _ => {}
6315 }
6316 }
6317 if let Some(slot) = activated {
6318 active.insert(*feature_id, slot);
6319 } else {
6320 inactive.insert(*feature_id);
6321 }
6322 }
6323
6324 (FeatureSet::new(active, inactive), pending)
6325 }
6326
6327 pub fn compute_pending_activation_slot(&self, feature_id: &Pubkey) -> Option<Slot> {
6330 let account = self.get_account_with_fixed_root(feature_id)?;
6331 let feature = feature::from_account(&account)?;
6332 if feature.activated_at.is_some() {
6333 return None;
6335 }
6336 let active_epoch = self.epoch + 1;
6338 Some(self.epoch_schedule.get_first_slot_in_epoch(active_epoch))
6339 }
6340
6341 fn add_active_builtin_programs(&mut self) {
6342 for builtin in BUILTINS.iter() {
6343 let builtin_is_bpf = builtin.core_bpf_migration_config.is_some() && {
6360 self.get_account(&builtin.program_id)
6361 .map(|a| a.owner() == &bpf_loader_upgradeable::id())
6362 .unwrap_or(false)
6363 };
6364
6365 if builtin_is_bpf {
6368 continue;
6369 }
6370
6371 let builtin_is_active = builtin
6372 .enable_feature_id
6373 .map(|feature_id| self.feature_set.is_active(&feature_id))
6374 .unwrap_or(true);
6375
6376 if builtin_is_active {
6377 let activation_slot = builtin
6378 .enable_feature_id
6379 .and_then(|feature_id| self.feature_set.activated_slot(&feature_id))
6380 .unwrap_or(0);
6381 self.transaction_processor.add_builtin(
6382 builtin.program_id,
6383 ProgramCacheEntry::new_builtin(
6384 activation_slot,
6385 builtin.name.len(),
6386 builtin.register_fn,
6387 ),
6388 );
6389 }
6390 }
6391 }
6392
6393 fn add_builtin_program_accounts(&mut self) {
6394 for builtin in BUILTINS.iter() {
6395 let builtin_is_bpf = builtin.core_bpf_migration_config.is_some() && {
6412 self.get_account(&builtin.program_id)
6413 .map(|a| a.owner() == &bpf_loader_upgradeable::id())
6414 .unwrap_or(false)
6415 };
6416
6417 if builtin_is_bpf {
6420 continue;
6421 }
6422
6423 let builtin_is_active = builtin
6424 .enable_feature_id
6425 .map(|feature_id| self.feature_set.is_active(&feature_id))
6426 .unwrap_or(true);
6427
6428 if builtin_is_active {
6429 self.add_builtin_account(builtin.name, &builtin.program_id);
6430 }
6431 }
6432
6433 for precompile in get_precompiles() {
6434 let precompile_is_active = precompile
6435 .feature
6436 .as_ref()
6437 .map(|feature_id| self.feature_set.is_active(feature_id))
6438 .unwrap_or(true);
6439
6440 if precompile_is_active {
6441 self.add_precompile(&precompile.program_id);
6442 }
6443 }
6444 }
6445
6446 pub fn calculate_accounts_data_size(&self) -> ScanResult<u64> {
6454 let mut accounts_data_size: u64 = 0;
6455 self.scan_all_accounts(|address_account_slot| {
6456 let Some((_address, account, _slot)) = address_account_slot else {
6457 return;
6458 };
6459 accounts_data_size = accounts_data_size
6460 .checked_add(account.data().len() as u64)
6461 .expect("accounts data size cannot overflow");
6462 })?;
6463 Ok(accounts_data_size)
6464 }
6465
6466 pub fn is_in_slot_hashes_history(&self, slot: &Slot) -> bool {
6467 if slot < &self.slot
6468 && let Ok(slot_hashes) = self.transaction_processor.sysvar_cache().get_slot_hashes()
6469 {
6470 return slot_hashes.get(slot).is_some();
6471 }
6472 false
6473 }
6474
6475 pub fn check_program_deployment_slot(&self) -> bool {
6476 self.check_program_deployment_slot
6477 }
6478
6479 pub fn set_check_program_deployment_slot(&mut self, check: bool) {
6480 self.check_program_deployment_slot = check;
6481 }
6482
6483 pub fn fee_structure(&self) -> &FeeStructure {
6484 &self.fee_structure
6485 }
6486
6487 pub fn parent_block_id(&self) -> Option<Hash> {
6488 self.parent().and_then(|p| p.block_id())
6489 }
6490
6491 pub fn block_id(&self) -> Option<Hash> {
6492 *self.block_id.read().unwrap()
6493 }
6494
6495 pub fn set_block_id(&self, block_id: Option<Hash>) {
6496 let mut block_id_w = self.block_id.write().unwrap();
6497 debug_assert!(block_id_w.is_none() || *block_id_w == block_id);
6498 *block_id_w = block_id
6499 }
6500
6501 pub fn compute_budget(&self) -> Option<ComputeBudget> {
6502 self.compute_budget
6503 }
6504
6505 pub fn add_builtin(&self, program_id: Pubkey, name: &str, builtin: ProgramCacheEntry) {
6506 debug!("Adding program {name} under {program_id:?}");
6507 self.add_builtin_account(name, &program_id);
6508 self.transaction_processor.add_builtin(program_id, builtin);
6509 debug!("Added program {name} under {program_id:?}");
6510 }
6511
6512 fn add_builtin_account(&self, name: &str, program_id: &Pubkey) {
6515 let existing_genuine_program =
6516 self.get_account_with_fixed_root(program_id)
6517 .and_then(|account| {
6518 if native_loader::check_id(account.owner()) {
6522 Some(account)
6523 } else {
6524 self.burn_and_purge_account(program_id, account);
6526 None
6527 }
6528 });
6529
6530 if existing_genuine_program.is_some() {
6532 return;
6534 }
6535
6536 assert!(
6537 !self.freeze_started(),
6538 "Can't change frozen bank by adding not-existing new builtin program ({name}, \
6539 {program_id}). Maybe, inconsistent program activation is detected on snapshot \
6540 restore?"
6541 );
6542
6543 let (lamports, rent_epoch) =
6545 self.inherit_specially_retained_account_fields(&existing_genuine_program);
6546 let account: AccountSharedData = AccountSharedData::from(Account {
6547 lamports,
6548 data: name.as_bytes().to_vec(),
6549 owner: solana_sdk_ids::native_loader::id(),
6550 executable: true,
6551 rent_epoch,
6552 });
6553 self.store_account_and_update_capitalization(program_id, &account);
6554 }
6555
6556 pub fn get_bank_hash_stats(&self) -> BankHashStats {
6557 self.bank_hash_stats.load()
6558 }
6559
6560 pub fn clear_epoch_rewards_cache(&self) {
6561 self.epoch_rewards_calculation_cache.lock().unwrap().clear();
6562 }
6563
6564 pub fn set_accounts_lt_hash_for_snapshot_minimizer(&self, accounts_lt_hash: AccountsLtHash) {
6566 *self.accounts_lt_hash.lock().unwrap() = accounts_lt_hash;
6567 }
6568
6569 pub fn get_collector_fee_details(&self) -> CollectorFeeDetails {
6571 self.collector_fee_details.read().unwrap().clone()
6572 }
6573
6574 pub fn minimum_vote_account_balance_for_vat(&self) -> u64 {
6578 let vote_account_rent_exempt_minimum = self
6579 .rent_collector
6580 .rent
6581 .minimum_balance(VoteStateV4::size_of());
6582 if self.feature_set.snapshot().alpenglow {
6583 vote_account_rent_exempt_minimum + self.vat_to_burn_per_epoch()
6584 } else {
6585 vote_account_rent_exempt_minimum
6586 }
6587 }
6588
6589 pub fn get_top_epoch_stakes(&self) -> Stakes<StakeAccount<Delegation>> {
6594 if self.feature_set.snapshot().validator_admission_ticket {
6595 self.stakes_cache.stakes().clone_and_filter_for_vat(
6596 MAX_ALPENGLOW_VOTE_ACCOUNTS,
6597 self.minimum_vote_account_balance_for_vat(),
6598 )
6599 } else {
6600 self.stakes_cache.stakes().clone()
6601 }
6602 }
6603
6604 pub fn calculate_and_set_block_id_for_dcou(bank: &Bank) {
6616 if bank.block_id().is_some() {
6617 return;
6619 }
6620
6621 let Some(parent) = bank.parent() else {
6622 bank.freeze();
6626 bank.set_block_id(Some(bank.hash()));
6627 return;
6628 };
6629
6630 let parent_block_id = parent.block_id().unwrap_or_else(|| {
6631 Self::calculate_and_set_block_id_for_dcou(&parent);
6633 parent.block_id().unwrap()
6634 });
6635
6636 bank.freeze();
6638 let block_id =
6639 solana_sha256_hasher::hashv(&[parent_block_id.as_ref(), bank.hash().as_ref()]);
6640 bank.set_block_id(Some(block_id));
6641 }
6642
6643 pub(crate) fn get_alpenglow_migration_slot(&self) -> Option<Slot> {
6644 let genesis_cert = self.get_alpenglow_genesis_certificate()?;
6645 debug_assert!(
6646 genesis_cert.cert_type.is_genesis(),
6647 "cert_type={:?}",
6648 genesis_cert.cert_type
6649 );
6650 Some(genesis_cert.cert_type.slot())
6651 }
6652}
6653
6654impl InvokeContextCallback for Bank {
6655 fn get_epoch_stake(&self) -> u64 {
6656 self.get_current_epoch_total_stake()
6657 }
6658
6659 fn get_epoch_stake_for_vote_account(&self, vote_address: &Pubkey) -> u64 {
6660 self.get_current_epoch_vote_accounts()
6661 .get(vote_address)
6662 .map(|(stake, _)| *stake)
6663 .unwrap_or(0)
6664 }
6665
6666 fn is_precompile(&self, program_id: &Pubkey) -> bool {
6667 is_precompile(program_id, |feature_id: &Pubkey| {
6668 self.feature_set.is_active(feature_id)
6669 })
6670 }
6671
6672 fn process_precompile(
6673 &self,
6674 program_id: &Pubkey,
6675 data: &[u8],
6676 instruction_datas: Vec<&[u8]>,
6677 ) -> std::result::Result<(), PrecompileError> {
6678 if let Some(precompile) = get_precompile(program_id, |feature_id: &Pubkey| {
6679 self.feature_set.is_active(feature_id)
6680 }) {
6681 precompile.verify(data, &instruction_datas, &self.feature_set)
6682 } else {
6683 Err(PrecompileError::InvalidPublicKey)
6684 }
6685 }
6686}
6687
6688impl TransactionProcessingCallback for Bank {
6689 fn get_account_shared_data(&self, pubkey: &Pubkey) -> Option<(AccountSharedData, Slot)> {
6690 self.rc
6691 .accounts
6692 .load_with_fixed_root(&self.ancestors, pubkey)
6693 }
6694
6695 fn inspect_account(&self, _address: &Pubkey, _account_state: AccountState, _is_writable: bool) {
6696 }
6698}
6699
6700impl fmt::Debug for Bank {
6701 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6702 f.debug_struct("Bank")
6703 .field("slot", &self.slot)
6704 .field("bank_id", &self.bank_id)
6705 .field("block_height", &self.block_height)
6706 .field("parent_slot", &self.parent_slot)
6707 .field("capitalization", &self.capitalization())
6708 .finish_non_exhaustive()
6709 }
6710}
6711
6712#[cfg(feature = "dev-context-only-utils")]
6713impl Bank {
6714 fn new_from_fields_for_tests(
6721 bank_rc: BankRc,
6722 fields: BankFieldsToDeserialize,
6723 feature_set: FeatureSet,
6724 epoch_stakes: HashMap<Epoch, VersionedEpochStakes>,
6725 leader: SlotLeader,
6726 stakes_cache: StakesCache,
6727 accounts_data_size_initial: u64,
6728 ) -> Self {
6729 let slot = fields.slot;
6730 let epoch = fields.epoch_schedule.get_epoch(slot);
6731 let ancestors = Ancestors::from(vec![slot]);
6732 let rent = Self::load_rent_from_account_for_snapshot_load(&bank_rc.accounts, &ancestors);
6733
6734 let accounts = Accounts::new(Arc::clone(&bank_rc.accounts.accounts_db));
6735 let mut bank = Self::default_with_accounts(accounts);
6736
6737 bank.rc = bank_rc;
6738 bank.blockhash_queue = RwLock::new(fields.blockhash_queue);
6739 bank.ancestors = ancestors;
6740 bank.hash = RwLock::new(fields.hash);
6741 bank.parent_hash = fields.parent_hash;
6742 bank.parent_slot = fields.parent_slot;
6743 bank.hard_forks = Arc::new(RwLock::new(fields.hard_forks));
6744 bank.transaction_count = AtomicU64::new(fields.transaction_count);
6745 bank.tick_height = AtomicU64::new(fields.tick_height);
6746 bank.signature_count = AtomicU64::new(fields.signature_count);
6747 bank.capitalization = AtomicU64::new(fields.capitalization);
6748 bank.max_tick_height = fields.max_tick_height;
6749 bank.hashes_per_tick = RwLock::new(fields.hashes_per_tick);
6750 bank.ticks_per_slot = fields.ticks_per_slot;
6751 bank.ns_per_slot = fields.ns_per_slot;
6752 bank.genesis_creation_time = fields.genesis_creation_time;
6753 bank.slots_per_year = fields.slots_per_year;
6754 bank.slot = slot;
6755 bank.epoch = epoch;
6756 bank.block_height = fields.block_height;
6757 bank.leader = leader;
6758 bank.fee_rate_governor = fields.fee_rate_governor;
6759 bank.rent_collector = RentCollector::new(
6760 epoch,
6761 fields.epoch_schedule.clone(),
6762 fields.slots_per_year,
6763 rent,
6764 );
6765 bank.epoch_schedule = fields.epoch_schedule;
6766 bank.inflation = Arc::new(RwLock::new(fields.inflation));
6767 bank.stakes_cache = stakes_cache;
6768 bank.epoch_stakes = epoch_stakes;
6769 bank.is_delta = AtomicBool::new(fields.is_delta);
6770 bank.cluster_type = Some(ClusterType::Development);
6771 bank.feature_set = Arc::new(feature_set);
6772 bank.freeze_started = AtomicBool::new(fields.hash != Hash::default());
6773 bank.accounts_data_size_initial = accounts_data_size_initial;
6774 bank.transaction_processor = TransactionBatchProcessor::new_uninitialized(slot, epoch);
6775 bank.accounts_lt_hash = Mutex::new(fields.accounts_lt_hash);
6776 bank.bank_hash_stats = AtomicBankHashStats::new(&fields.bank_hash_stats);
6777 bank.refresh_slot_params_with_baseline(SlotParams::genesis_baseline(
6778 bank.ns_per_slot,
6779 bank.slots_per_year,
6780 bank.hashes_per_tick(),
6781 bank.partitioned_rewards_stake_account_stores_per_block,
6782 ));
6783
6784 bank
6785 }
6786
6787 pub fn new_for_txn_tests(
6798 bank_rc: BankRc,
6799 fields: BankFieldsToDeserialize,
6800 feature_set: FeatureSet,
6801 epoch_stakes: HashMap<Epoch, VersionedEpochStakes>,
6802 ) -> Self {
6803 let leader = SlotLeader {
6804 id: fields.leader_id,
6805 vote_address: Pubkey::default(),
6806 };
6807 let mut bank = Self::new_from_fields_for_tests(
6808 bank_rc,
6809 fields,
6810 feature_set,
6811 epoch_stakes,
6812 leader,
6813 StakesCache::default(), 0, );
6816
6817 bank.apply_activated_features();
6818 bank.transaction_processor
6819 .fill_missing_sysvar_cache_entries(&bank);
6820
6821 bank
6822 }
6823
6824 pub fn new_for_block_tests(
6834 bank_rc: BankRc,
6835 fields: BankFieldsToDeserialize,
6836 feature_set: FeatureSet,
6837 epoch_stakes: HashMap<Epoch, VersionedEpochStakes>,
6838 stakes: Stakes<StakeAccount<Delegation>>,
6839 accounts_data_size_initial: u64,
6840 ) -> Self {
6841 let parent_epoch = fields.epoch_schedule.get_epoch(fields.parent_slot);
6842 let parent_capitalization = fields.capitalization;
6843 let leader =
6844 Self::slot_leader_from_epoch_stakes(fields.slot, &fields.epoch_schedule, &epoch_stakes);
6845
6846 let mut bank = Self::new_from_fields_for_tests(
6847 bank_rc,
6848 fields,
6849 feature_set,
6850 epoch_stakes,
6851 leader,
6852 StakesCache::new(stakes),
6853 accounts_data_size_initial,
6854 );
6855
6856 bank.apply_activated_features();
6857
6858 bank.recalculate_partitioned_rewards_if_active(|| {
6861 rayon::ThreadPoolBuilder::new()
6862 .num_threads(1)
6863 .build()
6864 .expect("single-threaded rayon pool")
6865 });
6866
6867 bank.prepare_for_block_execution(
6868 parent_epoch,
6869 bank.parent_slot,
6870 parent_capitalization,
6871 bank.block_height.saturating_sub(1),
6872 null_tracer(),
6873 );
6874
6875 bank
6876 }
6877
6878 pub fn wrap_with_bank_forks_for_tests(self) -> (Arc<Self>, Arc<RwLock<BankForks>>) {
6879 let bank_forks = BankForks::new_rw_arc(self);
6880 let bank = bank_forks.read().unwrap().root_bank();
6881 (bank, bank_forks)
6882 }
6883
6884 pub fn default_for_tests() -> Self {
6885 let accounts_db = AccountsDb::default_for_tests();
6886 let accounts = Accounts::new(Arc::new(accounts_db));
6887 Self::default_with_accounts(accounts)
6888 }
6889
6890 pub fn new_with_bank_forks_for_tests(
6891 genesis_config: &GenesisConfig,
6892 ) -> (Arc<Self>, Arc<RwLock<BankForks>>) {
6893 let bank = Self::new_for_tests(genesis_config);
6894 bank.wrap_with_bank_forks_for_tests()
6895 }
6896
6897 pub fn new_for_tests(genesis_config: &GenesisConfig) -> Self {
6898 Self::new_with_paths_for_tests(genesis_config, None, vec![], None)
6899 }
6900
6901 pub fn new_with_mockup_builtin_for_tests(
6902 genesis_config: &GenesisConfig,
6903 program_id: Pubkey,
6904 builtin: BuiltinFunctionRegisterer,
6905 ) -> (Arc<Self>, Arc<RwLock<BankForks>>) {
6906 let mut bank = Self::new_for_tests(genesis_config);
6907 bank.add_mockup_builtin(program_id, builtin);
6908 bank.wrap_with_bank_forks_for_tests()
6909 }
6910
6911 pub fn new_with_paths_for_tests(
6912 genesis_config: &GenesisConfig,
6913 test_config: Option<BankTestConfig>,
6914 paths: Vec<PathBuf>,
6915 leader: Option<SlotLeader>,
6916 ) -> Self {
6917 let test_config = test_config.unwrap_or_default();
6918 let mut bank = Self::new_from_genesis(
6919 genesis_config,
6920 Arc::new(RuntimeConfig::default()),
6921 paths,
6922 None,
6923 test_config.accounts_db_config,
6924 None,
6925 leader,
6926 Arc::default(),
6927 None,
6928 None,
6929 );
6930 bank.set_fee_structure(&FeeStructure {
6932 lamports_per_signature: genesis_config.fee_rate_governor.lamports_per_signature,
6933 ..FeeStructure::default()
6934 });
6935 bank
6936 }
6937
6938 pub fn new_for_benches(genesis_config: &GenesisConfig) -> Self {
6939 Self::new_with_paths_for_benches(genesis_config, Vec::new())
6940 }
6941
6942 pub fn new_with_paths_for_benches(genesis_config: &GenesisConfig, paths: Vec<PathBuf>) -> Self {
6945 Self::new_from_genesis(
6946 genesis_config,
6947 Arc::<RuntimeConfig>::default(),
6948 paths,
6949 None,
6950 ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS,
6951 None,
6952 Some(SlotLeader::new_unique()),
6953 Arc::default(),
6954 None,
6955 None,
6956 )
6957 }
6958
6959 pub fn new_from_parent_with_bank_forks(
6960 bank_forks: &RwLock<BankForks>,
6961 parent: Arc<Bank>,
6962 leader: SlotLeader,
6963 slot: Slot,
6964 ) -> Arc<Self> {
6965 let bank = Bank::new_from_parent(parent, leader, slot);
6966 bank_forks
6967 .write()
6968 .unwrap()
6969 .insert(bank)
6970 .clone_without_scheduler()
6971 }
6972
6973 pub fn prepare_batch_for_tests(
6975 &self,
6976 txs: Vec<Transaction>,
6977 ) -> TransactionBatch<'_, '_, RuntimeTransaction<SanitizedTransaction>> {
6978 let sanitized_txs = txs
6979 .into_iter()
6980 .map(RuntimeTransaction::from_transaction_for_tests)
6981 .collect::<Vec<_>>();
6982 TransactionBatch::new(
6983 self.try_lock_accounts(&sanitized_txs),
6984 self,
6985 OwnedOrBorrowed::Owned(sanitized_txs),
6986 )
6987 }
6988
6989 pub fn set_accounts_data_size_initial_for_tests(&mut self, amount: u64) {
6992 self.accounts_data_size_initial = amount;
6993 }
6994
6995 pub fn update_accounts_data_size_delta_off_chain_for_tests(&self, amount: i64) {
6998 self.update_accounts_data_size_delta_off_chain(amount)
6999 }
7000
7001 #[must_use]
7007 pub fn process_transactions<'a>(
7008 &self,
7009 txs: impl Iterator<Item = &'a Transaction>,
7010 ) -> Vec<Result<()>> {
7011 self.try_process_transactions(txs).unwrap()
7012 }
7013
7014 #[must_use]
7020 pub fn process_entry_transactions(&self, txs: Vec<VersionedTransaction>) -> Vec<Result<()>> {
7021 self.try_process_entry_transactions(txs).unwrap()
7022 }
7023
7024 pub fn get_sysvar_cache_for_tests(&self) -> SysvarCache {
7025 self.transaction_processor.get_sysvar_cache_for_tests()
7026 }
7027
7028 pub fn calculate_accounts_lt_hash_for_tests(&self) -> AccountsLtHash {
7029 self.rc
7030 .accounts
7031 .accounts_db
7032 .calculate_accounts_lt_hash_at_startup_from_index(&self.ancestors)
7033 }
7034
7035 pub fn get_transaction_processor(&self) -> &TransactionBatchProcessor<BankForks> {
7036 &self.transaction_processor
7037 }
7038
7039 pub fn set_fee_structure(&mut self, fee_structure: &FeeStructure) {
7040 self.fee_structure = fee_structure.clone();
7041 }
7042
7043 pub fn load_program(
7044 &self,
7045 pubkey: &Pubkey,
7046 effective_epoch: Epoch,
7047 ) -> Option<Arc<ProgramCacheEntry>> {
7048 let environments = self
7049 .transaction_processor
7050 .program_runtime_environment_for_epoch(effective_epoch);
7051 load_program_with_pubkey(
7052 self,
7053 &environments,
7054 pubkey,
7055 self.slot(),
7056 &mut ExecuteTimings::default(), )
7058 .map(|(loaded_program, _last_modification_slot)| loaded_program)
7059 }
7060
7061 pub fn withdraw(&self, pubkey: &Pubkey, lamports: u64) -> Result<()> {
7062 match self.get_account_with_fixed_root(pubkey) {
7063 Some(mut account) => {
7064 let min_balance = match get_system_account_kind(&account) {
7065 Some(SystemAccountKind::Nonce) => self
7066 .rent_collector
7067 .rent
7068 .minimum_balance(nonce::state::State::size()),
7069 _ => 0,
7070 };
7071
7072 lamports
7073 .checked_add(min_balance)
7074 .filter(|required_balance| *required_balance <= account.lamports())
7075 .ok_or(TransactionError::InsufficientFundsForFee)?;
7076 account
7077 .checked_sub_lamports(lamports)
7078 .map_err(|_| TransactionError::InsufficientFundsForFee)?;
7079 self.store_account(pubkey, &account);
7080
7081 Ok(())
7082 }
7083 None => Err(TransactionError::AccountNotFound),
7084 }
7085 }
7086
7087 pub fn set_hash_overrides(&self, hash_overrides: HashOverrides) {
7088 *self.hash_overrides.lock().unwrap() = hash_overrides;
7089 }
7090
7091 pub(crate) fn get_stake_accounts(&self, minimized_account_set: &DashSet<Pubkey>) {
7093 self.stakes_cache
7094 .stakes()
7095 .stake_delegations()
7096 .iter()
7097 .for_each(|(pubkey, _)| {
7098 minimized_account_set.insert(*pubkey);
7099 });
7100
7101 self.stakes_cache
7102 .stakes()
7103 .staked_nodes()
7104 .par_iter()
7105 .for_each(|(pubkey, _)| {
7106 minimized_account_set.insert(*pubkey);
7107 });
7108 }
7109
7110 pub fn slot_time_reduction_active(&self) -> bool {
7112 self.ns_per_slot != self.slot_params.baseline_params().ns_per_slot()
7113 }
7114}
7115
7116pub(crate) fn rewards_calculation_thread_pool() -> &'static ThreadPool {
7126 static NEW_EPOCH_THREAD_POOL: OnceLock<ThreadPool> = OnceLock::new();
7127 NEW_EPOCH_THREAD_POOL.get_or_init(|| {
7128 rayon::ThreadPoolBuilder::new()
7129 .thread_name(|i| format!("solBnkClcRwds{i:02}"))
7130 .build()
7131 .expect("new epoch boundary rayon threadpool")
7132 })
7133}
7134
7135fn calculate_data_size_delta(old_data_size: usize, new_data_size: usize) -> i64 {
7138 assert!(old_data_size <= i64::MAX as usize);
7139 assert!(new_data_size <= i64::MAX as usize);
7140 let old_data_size = old_data_size as i64;
7141 let new_data_size = new_data_size as i64;
7142
7143 new_data_size.saturating_sub(old_data_size)
7144}
7145
7146impl Drop for Bank {
7147 fn drop(&mut self) {
7148 if let Some(drop_callback) = self.drop_callback.read().unwrap().0.as_ref() {
7149 drop_callback.callback(self);
7150 } else {
7151 self.rc
7153 .accounts
7154 .accounts_db
7155 .purge_slot(self.slot(), self.bank_id(), false);
7156 }
7157 }
7158}
7159
7160pub mod test_utils {
7162 use {
7163 super::Bank,
7164 crate::installed_scheduler_pool::BankWithScheduler,
7165 solana_account::{ReadableAccount, WritableAccount, state_traits::StateMut},
7166 solana_instruction::error::LamportsError,
7167 solana_pubkey::Pubkey,
7168 solana_sha256_hasher::hashv,
7169 solana_vote_interface::state::VoteStateV4,
7170 solana_vote_program::vote_state::{BlockTimestamp, VoteStateVersions},
7171 std::sync::Arc,
7172 };
7173 pub fn goto_end_of_slot(bank: Arc<Bank>) {
7174 goto_end_of_slot_with_scheduler(&BankWithScheduler::new_without_scheduler(bank))
7175 }
7176
7177 pub fn goto_end_of_slot_with_scheduler(bank: &BankWithScheduler) {
7178 let mut tick_hash = bank.last_blockhash();
7179 loop {
7180 tick_hash = hashv(&[tick_hash.as_ref(), &[42]]);
7181 bank.register_tick(&tick_hash);
7182 if tick_hash == bank.last_blockhash() {
7183 bank.freeze();
7184 return;
7185 }
7186 }
7187 }
7188
7189 pub fn update_vote_account_timestamp(
7190 timestamp: BlockTimestamp,
7191 bank: &Bank,
7192 vote_pubkey: &Pubkey,
7193 ) {
7194 let mut vote_account = bank.get_account(vote_pubkey).unwrap_or_default();
7195 let mut vote_state = VoteStateV4::deserialize(vote_account.data(), vote_pubkey)
7196 .ok()
7197 .unwrap_or_default();
7198 vote_state.last_timestamp = timestamp;
7199 let versioned = VoteStateVersions::new_v4(vote_state);
7200 vote_account.set_state(&versioned).unwrap();
7201 bank.store_account(vote_pubkey, &vote_account);
7202 }
7203
7204 pub fn deposit(
7205 bank: &Bank,
7206 pubkey: &Pubkey,
7207 lamports: u64,
7208 ) -> std::result::Result<u64, LamportsError> {
7209 let mut account = bank
7212 .get_account_with_fixed_root_no_cache(pubkey)
7213 .unwrap_or_default();
7214 account.checked_add_lamports(lamports)?;
7215 bank.store_account(pubkey, &account);
7216 Ok(account.lamports())
7217 }
7218}