Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit d4ddb62

Browse files
authored
Convert Banks (#9033)
* Store and compute needed state in EpochStakes struct Co-authored-by: Carl <[email protected]>
1 parent 7a8233d commit d4ddb62

File tree

5 files changed

+506
-6
lines changed

5 files changed

+506
-6
lines changed

ledger/src/snapshot_utils.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use solana_measure::measure::Measure;
88
use solana_runtime::{
99
accounts_db::{SnapshotStorage, SnapshotStorages},
1010
bank::{
11-
self, deserialize_from_snapshot, Bank, BankRcSerialize, BankSlotDelta,
11+
self, bank_1_0::Bank1_0, deserialize_from_snapshot, Bank, BankRcSerialize, BankSlotDelta,
1212
MAX_SNAPSHOT_DATA_FILE_SIZE,
1313
},
1414
};
@@ -30,7 +30,8 @@ pub const TAR_SNAPSHOTS_DIR: &str = "snapshots";
3030
pub const TAR_ACCOUNTS_DIR: &str = "accounts";
3131
pub const TAR_VERSION_FILE: &str = "version";
3232

33-
pub const SNAPSHOT_VERSION: &str = "1.0.0";
33+
pub const SNAPSHOT_VERSION_1_0: &str = "1.0.0";
34+
pub const SNAPSHOT_VERSION: &str = "1.1.0";
3435

3536
#[derive(PartialEq, Ord, Eq, Debug)]
3637
pub struct SlotSnapshotPaths {
@@ -593,6 +594,10 @@ where
593594
MAX_SNAPSHOT_DATA_FILE_SIZE,
594595
|stream| {
595596
let mut bank: Bank = match snapshot_version {
597+
SNAPSHOT_VERSION_1_0 => {
598+
let bank_1_0: Bank1_0 = deserialize_from_snapshot(stream.by_ref())?;
599+
bank_1_0.convert_to_current()
600+
}
596601
SNAPSHOT_VERSION => deserialize_from_snapshot(stream.by_ref())?,
597602
_ => {
598603
return Err(get_io_error(&format!(
@@ -602,6 +607,7 @@ where
602607
}
603608
};
604609
info!("Rebuilding accounts...");
610+
605611
let rc = bank::BankRc::from_stream(
606612
account_paths,
607613
bank.slot(),

runtime/src/bank/bank_1_0.rs

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
//! The `bank` module tracks client accounts and the progress of on-chain
2+
//! programs. It offers a high-level API that signs transactions
3+
//! on behalf of the caller, and a low-level API for when they have
4+
//! already been signed and verified.
5+
use crate::{
6+
bank::{Bank, BankRc, EnteredEpochCallback, StatusCacheRc},
7+
blockhash_queue::BlockhashQueue,
8+
epoch_stakes::EpochStakes,
9+
message_processor::MessageProcessor,
10+
rent_collector::RentCollector,
11+
serde_utils::{
12+
deserialize_atomicbool, deserialize_atomicu64, serialize_atomicbool, serialize_atomicu64,
13+
},
14+
stakes::Stakes,
15+
storage_utils::StorageAccounts,
16+
};
17+
use serde::{Deserialize, Serialize};
18+
use solana_sdk::{
19+
clock::{Epoch, Slot, UnixTimestamp},
20+
epoch_schedule::EpochSchedule,
21+
fee_calculator::{FeeCalculator, FeeRateGovernor},
22+
hard_forks::HardForks,
23+
hash::Hash,
24+
inflation::Inflation,
25+
pubkey::Pubkey,
26+
};
27+
use std::{
28+
collections::HashMap,
29+
sync::atomic::{AtomicBool, AtomicU64},
30+
sync::{Arc, RwLock},
31+
};
32+
33+
/// Manager for the state of all accounts and programs after processing its entries.
34+
#[derive(Deserialize, Serialize)]
35+
pub struct Bank1_0 {
36+
/// References to accounts, parent and signature status
37+
#[serde(skip)]
38+
pub rc: BankRc,
39+
40+
#[serde(skip)]
41+
pub src: StatusCacheRc,
42+
43+
/// FIFO queue of `recent_blockhash` items
44+
pub blockhash_queue: RwLock<BlockhashQueue>,
45+
46+
/// The set of parents including this bank
47+
pub ancestors: HashMap<Slot, usize>,
48+
49+
/// Hash of this Bank's state. Only meaningful after freezing.
50+
pub hash: RwLock<Hash>,
51+
52+
/// Hash of this Bank's parent's state
53+
pub parent_hash: Hash,
54+
55+
/// parent's slot
56+
pub parent_slot: Slot,
57+
58+
/// slots to hard fork at
59+
pub hard_forks: Arc<RwLock<HardForks>>,
60+
61+
/// The number of transactions processed without error
62+
#[serde(serialize_with = "serialize_atomicu64")]
63+
#[serde(deserialize_with = "deserialize_atomicu64")]
64+
pub transaction_count: AtomicU64,
65+
66+
/// Bank tick height
67+
#[serde(serialize_with = "serialize_atomicu64")]
68+
#[serde(deserialize_with = "deserialize_atomicu64")]
69+
pub tick_height: AtomicU64,
70+
71+
/// The number of signatures from valid transactions in this slot
72+
#[serde(serialize_with = "serialize_atomicu64")]
73+
#[serde(deserialize_with = "deserialize_atomicu64")]
74+
pub signature_count: AtomicU64,
75+
76+
/// Total capitalization, used to calculate inflation
77+
#[serde(serialize_with = "serialize_atomicu64")]
78+
#[serde(deserialize_with = "deserialize_atomicu64")]
79+
pub capitalization: AtomicU64,
80+
81+
// Bank max_tick_height
82+
pub max_tick_height: u64,
83+
84+
/// The number of hashes in each tick. None value means hashing is disabled.
85+
pub hashes_per_tick: Option<u64>,
86+
87+
/// The number of ticks in each slot.
88+
pub ticks_per_slot: u64,
89+
90+
/// length of a slot in ns
91+
pub ns_per_slot: u128,
92+
93+
/// genesis time, used for computed clock
94+
pub genesis_creation_time: UnixTimestamp,
95+
96+
/// The number of slots per year, used for inflation
97+
pub slots_per_year: f64,
98+
99+
/// The number of slots per Storage segment
100+
pub slots_per_segment: u64,
101+
102+
/// Bank slot (i.e. block)
103+
pub slot: Slot,
104+
105+
/// Bank epoch
106+
pub epoch: Epoch,
107+
108+
/// Bank block_height
109+
pub block_height: u64,
110+
111+
/// The pubkey to send transactions fees to.
112+
pub collector_id: Pubkey,
113+
114+
/// Fees that have been collected
115+
#[serde(serialize_with = "serialize_atomicu64")]
116+
#[serde(deserialize_with = "deserialize_atomicu64")]
117+
pub collector_fees: AtomicU64,
118+
119+
/// Latest transaction fees for transactions processed by this bank
120+
pub fee_calculator: FeeCalculator,
121+
122+
/// Track cluster signature throughput and adjust fee rate
123+
pub fee_rate_governor: FeeRateGovernor,
124+
125+
/// Rent that have been collected
126+
#[serde(serialize_with = "serialize_atomicu64")]
127+
#[serde(deserialize_with = "deserialize_atomicu64")]
128+
pub collected_rent: AtomicU64,
129+
130+
/// latest rent collector, knows the epoch
131+
pub rent_collector: RentCollector,
132+
133+
/// initialized from genesis
134+
pub epoch_schedule: EpochSchedule,
135+
136+
/// inflation specs
137+
pub inflation: Arc<RwLock<Inflation>>,
138+
139+
/// cache of vote_account and stake_account state for this fork
140+
pub stakes: RwLock<Stakes>,
141+
142+
/// cache of validator and archiver storage accounts for this fork
143+
pub storage_accounts: RwLock<StorageAccounts>,
144+
145+
/// staked nodes on epoch boundaries, saved off when a bank.slot() is at
146+
/// a leader schedule calculation boundary
147+
pub epoch_stakes: HashMap<Epoch, Stakes>,
148+
149+
/// A boolean reflecting whether any entries were recorded into the PoH
150+
/// stream for the slot == self.slot
151+
#[serde(serialize_with = "serialize_atomicbool")]
152+
#[serde(deserialize_with = "deserialize_atomicbool")]
153+
pub is_delta: AtomicBool,
154+
155+
/// The Message processor
156+
pub message_processor: MessageProcessor,
157+
158+
/// Callback to be notified when a bank enters a new Epoch
159+
/// (used to adjust cluster features over time)
160+
#[serde(skip)]
161+
pub entered_epoch_callback: Arc<RwLock<Option<EnteredEpochCallback>>>,
162+
163+
/// Last time when the cluster info vote listener has synced with this bank
164+
#[serde(skip)]
165+
pub last_vote_sync: AtomicU64,
166+
167+
/// Rewards that were paid out immediately after this bank was created
168+
#[serde(skip)]
169+
pub rewards: Option<Vec<(Pubkey, i64)>>,
170+
}
171+
172+
impl Bank1_0 {
173+
pub fn convert_to_current(self) -> Bank {
174+
let old_epoch_stakes = self.epoch_stakes;
175+
let epoch_stakes = old_epoch_stakes
176+
.iter()
177+
.map(|(epoch, stakes)| (*epoch, EpochStakes::new(&stakes, *epoch)))
178+
.collect();
179+
Bank {
180+
rc: self.rc,
181+
src: self.src,
182+
blockhash_queue: self.blockhash_queue,
183+
ancestors: self.ancestors,
184+
hash: self.hash,
185+
parent_hash: self.parent_hash,
186+
parent_slot: self.parent_slot,
187+
hard_forks: self.hard_forks,
188+
transaction_count: self.transaction_count,
189+
tick_height: self.tick_height,
190+
signature_count: self.signature_count,
191+
capitalization: self.capitalization,
192+
max_tick_height: self.max_tick_height,
193+
hashes_per_tick: self.hashes_per_tick,
194+
ticks_per_slot: self.ticks_per_slot,
195+
ns_per_slot: self.ns_per_slot,
196+
genesis_creation_time: self.genesis_creation_time,
197+
slots_per_year: self.slots_per_year,
198+
slots_per_segment: self.slots_per_segment,
199+
slot: self.slot,
200+
epoch: self.epoch,
201+
block_height: self.block_height,
202+
collector_id: self.collector_id,
203+
collector_fees: self.collector_fees,
204+
fee_calculator: self.fee_calculator,
205+
fee_rate_governor: self.fee_rate_governor,
206+
collected_rent: self.collected_rent,
207+
rent_collector: self.rent_collector,
208+
epoch_schedule: self.epoch_schedule,
209+
inflation: self.inflation,
210+
stakes: self.stakes,
211+
storage_accounts: self.storage_accounts,
212+
epoch_stakes,
213+
is_delta: self.is_delta,
214+
message_processor: self.message_processor,
215+
entered_epoch_callback: self.entered_epoch_callback,
216+
last_vote_sync: self.last_vote_sync,
217+
rewards: self.rewards,
218+
}
219+
}
220+
}

runtime/src/bank.rs renamed to runtime/src/bank/mod.rs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
accounts::{Accounts, TransactionAccounts, TransactionLoadResult, TransactionLoaders},
77
accounts_db::{AccountsDBSerialize, ErrorCounters, SnapshotStorage, SnapshotStorages},
88
blockhash_queue::BlockhashQueue,
9+
epoch_stakes::{EpochStakes, NodeVoteAccounts},
910
message_processor::{MessageProcessor, ProcessInstruction},
1011
nonce_utils,
1112
rent_collector::RentCollector,
@@ -60,6 +61,8 @@ use std::{
6061
sync::{Arc, RwLock, RwLockReadGuard},
6162
};
6263

64+
pub mod bank_1_0;
65+
6366
pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
6467
pub const MAX_SNAPSHOT_DATA_FILE_SIZE: u64 = 32 * 1024 * 1024 * 1024; // 32 GiB
6568

@@ -323,7 +326,7 @@ pub struct Bank {
323326

324327
/// staked nodes on epoch boundaries, saved off when a bank.slot() is at
325328
/// a leader schedule calculation boundary
326-
epoch_stakes: HashMap<Epoch, Stakes>,
329+
epoch_stakes: HashMap<Epoch, EpochStakes>,
327330

328331
/// A boolean reflecting whether any entries were recorded into the PoH
329332
/// stream for the slot == self.slot
@@ -380,7 +383,8 @@ impl Bank {
380383
{
381384
let stakes = bank.stakes.read().unwrap();
382385
for epoch in 0..=bank.get_leader_schedule_epoch(bank.slot) {
383-
bank.epoch_stakes.insert(epoch, stakes.clone());
386+
bank.epoch_stakes
387+
.insert(epoch, EpochStakes::new(&stakes, epoch));
384388
}
385389
bank.update_stake_history(None);
386390
}
@@ -592,8 +596,24 @@ impl Bank {
592596
epoch >= leader_schedule_epoch.saturating_sub(MAX_LEADER_SCHEDULE_STAKES)
593597
});
594598

599+
let vote_stakes: HashMap<_, _> = self
600+
.stakes
601+
.read()
602+
.unwrap()
603+
.vote_accounts()
604+
.iter()
605+
.map(|(epoch, (stake, _))| (*epoch, *stake))
606+
.collect();
607+
let new_epoch_stakes =
608+
EpochStakes::new(&self.stakes.read().unwrap(), leader_schedule_epoch);
609+
info!(
610+
"new epoch stakes, epoch: {}, stakes: {:#?}, total_stake: {}",
611+
leader_schedule_epoch,
612+
vote_stakes,
613+
new_epoch_stakes.total_stake(),
614+
);
595615
self.epoch_stakes
596-
.insert(leader_schedule_epoch, self.stakes.read().unwrap().clone());
616+
.insert(leader_schedule_epoch, new_epoch_stakes);
597617
}
598618
}
599619

@@ -2056,10 +2076,55 @@ impl Bank {
20562076
self.stakes.read().unwrap().vote_accounts().clone()
20572077
}
20582078

2079+
/// Get the EpochStakes for a given epoch
2080+
pub fn epoch_stakes(&self, epoch: Epoch) -> Option<&EpochStakes> {
2081+
self.epoch_stakes.get(&epoch)
2082+
}
2083+
20592084
/// vote accounts for the specific epoch along with the stake
20602085
/// attributed to each account
20612086
pub fn epoch_vote_accounts(&self, epoch: Epoch) -> Option<&HashMap<Pubkey, (u64, Account)>> {
2062-
self.epoch_stakes.get(&epoch).map(Stakes::vote_accounts)
2087+
self.epoch_stakes
2088+
.get(&epoch)
2089+
.map(|epoch_stakes| Stakes::vote_accounts(epoch_stakes.stakes()))
2090+
}
2091+
2092+
/// Get the fixed authorized voter for the given vote account for the
2093+
/// current epoch
2094+
pub fn epoch_authorized_voter(&self, vote_account: &Pubkey) -> Option<&Pubkey> {
2095+
self.epoch_stakes
2096+
.get(&self.epoch)
2097+
.expect("Epoch stakes for bank's own epoch must exist")
2098+
.epoch_authorized_voters()
2099+
.get(vote_account)
2100+
}
2101+
2102+
/// Get the fixed set of vote accounts for the given node id for the
2103+
/// current epoch
2104+
pub fn epoch_vote_accounts_for_node_id(&self, node_id: &Pubkey) -> Option<&NodeVoteAccounts> {
2105+
self.epoch_stakes
2106+
.get(&self.epoch)
2107+
.expect("Epoch stakes for bank's own epoch must exist")
2108+
.node_id_to_vote_accounts()
2109+
.get(node_id)
2110+
}
2111+
2112+
/// Get the fixed total stake of all vote accounts for current epoch
2113+
pub fn total_epoch_stake(&self) -> u64 {
2114+
self.epoch_stakes
2115+
.get(&self.epoch)
2116+
.expect("Epoch stakes for bank's own epoch must exist")
2117+
.total_stake()
2118+
}
2119+
2120+
/// Get the fixed stake of the given vote account for the current epoch
2121+
pub fn epoch_vote_account_stake(&self, voting_pubkey: &Pubkey) -> u64 {
2122+
*self
2123+
.epoch_vote_accounts(self.epoch())
2124+
.expect("Bank epoch vote accounts must contain entry for the bank's own epoch")
2125+
.get(voting_pubkey)
2126+
.map(|(stake, _)| stake)
2127+
.unwrap_or(&0)
20632128
}
20642129

20652130
/// given a slot, return the epoch and offset into the epoch this slot falls

0 commit comments

Comments
 (0)