Maintain sysvar balances for consistent market cap. (#9936)
* Maintain sysvar balances for consistent market cap. * Unindent
This commit is contained in:
parent
f98bfda6f9
commit
00e45ec935
|
@ -778,6 +778,14 @@ fn main() {
|
||||||
.help("Include sysvars too"),
|
.help("Include sysvars too"),
|
||||||
)
|
)
|
||||||
.arg(&max_genesis_archive_unpacked_size_arg)
|
.arg(&max_genesis_archive_unpacked_size_arg)
|
||||||
|
).subcommand(
|
||||||
|
SubCommand::with_name("capitalization")
|
||||||
|
.about("Print capitalization (aka, total suppy)")
|
||||||
|
.arg(&no_snapshot_arg)
|
||||||
|
.arg(&account_paths_arg)
|
||||||
|
.arg(&halt_at_slot_arg)
|
||||||
|
.arg(&hard_forks_arg)
|
||||||
|
.arg(&max_genesis_archive_unpacked_size_arg)
|
||||||
).subcommand(
|
).subcommand(
|
||||||
SubCommand::with_name("prune")
|
SubCommand::with_name("prune")
|
||||||
.about("Prune the ledger from a yaml file containing a list of slots to prune.")
|
.about("Prune the ledger from a yaml file containing a list of slots to prune.")
|
||||||
|
@ -1112,6 +1120,76 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
("capitalization", Some(arg_matches)) => {
|
||||||
|
let dev_halt_at_slot = value_t!(arg_matches, "halt_at_slot", Slot).ok();
|
||||||
|
let process_options = ProcessOptions {
|
||||||
|
dev_halt_at_slot,
|
||||||
|
new_hard_forks: hardforks_of(arg_matches, "hard_forks"),
|
||||||
|
poh_verify: false,
|
||||||
|
..ProcessOptions::default()
|
||||||
|
};
|
||||||
|
let genesis_config = open_genesis_config_by(&ledger_path, arg_matches);
|
||||||
|
match load_bank_forks(arg_matches, &ledger_path, &genesis_config, process_options) {
|
||||||
|
Ok((bank_forks, _leader_schedule_cache, _snapshot_hash)) => {
|
||||||
|
let slot = bank_forks.working_bank().slot();
|
||||||
|
let bank = bank_forks.get(slot).unwrap_or_else(|| {
|
||||||
|
eprintln!("Error: Slot {} is not available", slot);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
use solana_sdk::native_token::LAMPORTS_PER_SOL;
|
||||||
|
use std::fmt::{Display, Formatter, Result};
|
||||||
|
pub struct Sol(u64);
|
||||||
|
|
||||||
|
impl Display for Sol {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}.{:09} SOL",
|
||||||
|
self.0 / LAMPORTS_PER_SOL,
|
||||||
|
self.0 % LAMPORTS_PER_SOL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let computed_capitalization: u64 = bank
|
||||||
|
.get_program_accounts(None)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(_pubkey, account)| {
|
||||||
|
if account.lamports == u64::max_value() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_specially_retained =
|
||||||
|
solana_sdk::native_loader::check_id(&account.owner)
|
||||||
|
|| solana_sdk::sysvar::check_id(&account.owner);
|
||||||
|
|
||||||
|
if is_specially_retained {
|
||||||
|
// specially retained accounts are ensured to exist by
|
||||||
|
// alwaysing having a balance of 1 lamports, which is
|
||||||
|
// outside the capitalization calculation.
|
||||||
|
Some(account.lamports - 1)
|
||||||
|
} else {
|
||||||
|
Some(account.lamports)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
if bank.capitalization() != computed_capitalization {
|
||||||
|
panic!(
|
||||||
|
"Capitalization mismatch!?: {} != {}",
|
||||||
|
bank.capitalization(),
|
||||||
|
computed_capitalization
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("Capitalization: {}", Sol(bank.capitalization()));
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to load ledger: {:?}", err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
("purge", Some(arg_matches)) => {
|
("purge", Some(arg_matches)) => {
|
||||||
let start_slot = value_t_or_exit!(arg_matches, "start_slot", Slot);
|
let start_slot = value_t_or_exit!(arg_matches, "start_slot", Slot);
|
||||||
let end_slot = value_t!(arg_matches, "end_slot", Slot);
|
let end_slot = value_t!(arg_matches, "end_slot", Slot);
|
||||||
|
|
|
@ -563,8 +563,12 @@ impl Bank {
|
||||||
self.store_account(pubkey, &new_account);
|
self.store_account(pubkey, &new_account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inherit_sysvar_account_balance(&self, old_account: &Option<Account>) -> u64 {
|
||||||
|
old_account.as_ref().map(|a| a.lamports).unwrap_or(1)
|
||||||
|
}
|
||||||
|
|
||||||
fn update_clock(&self) {
|
fn update_clock(&self) {
|
||||||
self.update_sysvar_account(&sysvar::clock::id(), |_| {
|
self.update_sysvar_account(&sysvar::clock::id(), |account| {
|
||||||
sysvar::clock::Clock {
|
sysvar::clock::Clock {
|
||||||
slot: self.slot,
|
slot: self.slot,
|
||||||
segment: get_segment_from_slot(self.slot, self.slots_per_segment),
|
segment: get_segment_from_slot(self.slot, self.slots_per_segment),
|
||||||
|
@ -572,7 +576,7 @@ impl Bank {
|
||||||
leader_schedule_epoch: self.epoch_schedule.get_leader_schedule_epoch(self.slot),
|
leader_schedule_epoch: self.epoch_schedule.get_leader_schedule_epoch(self.slot),
|
||||||
unix_timestamp: self.unix_timestamp(),
|
unix_timestamp: self.unix_timestamp(),
|
||||||
}
|
}
|
||||||
.create_account(1)
|
.create_account(self.inherit_sysvar_account_balance(account))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +587,7 @@ impl Bank {
|
||||||
.map(|account| SlotHistory::from_account(&account).unwrap())
|
.map(|account| SlotHistory::from_account(&account).unwrap())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
slot_history.add(self.slot());
|
slot_history.add(self.slot());
|
||||||
slot_history.create_account(1)
|
slot_history.create_account(self.inherit_sysvar_account_balance(account))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,7 +598,7 @@ impl Bank {
|
||||||
.map(|account| SlotHashes::from_account(&account).unwrap())
|
.map(|account| SlotHashes::from_account(&account).unwrap())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
slot_hashes.add(self.parent_slot, self.parent_hash);
|
slot_hashes.add(self.parent_slot, self.parent_hash);
|
||||||
slot_hashes.create_account(1)
|
slot_hashes.create_account(self.inherit_sysvar_account_balance(account))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,20 +633,29 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_fees(&self) {
|
fn update_fees(&self) {
|
||||||
self.update_sysvar_account(&sysvar::fees::id(), |_| {
|
self.update_sysvar_account(&sysvar::fees::id(), |account| {
|
||||||
sysvar::fees::create_account(1, &self.fee_calculator)
|
sysvar::fees::create_account(
|
||||||
|
self.inherit_sysvar_account_balance(account),
|
||||||
|
&self.fee_calculator,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_rent(&self) {
|
fn update_rent(&self) {
|
||||||
self.update_sysvar_account(&sysvar::rent::id(), |_| {
|
self.update_sysvar_account(&sysvar::rent::id(), |account| {
|
||||||
sysvar::rent::create_account(1, &self.rent_collector.rent)
|
sysvar::rent::create_account(
|
||||||
|
self.inherit_sysvar_account_balance(account),
|
||||||
|
&self.rent_collector.rent,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_epoch_schedule(&self) {
|
fn update_epoch_schedule(&self) {
|
||||||
self.update_sysvar_account(&sysvar::epoch_schedule::id(), |_| {
|
self.update_sysvar_account(&sysvar::epoch_schedule::id(), |account| {
|
||||||
sysvar::epoch_schedule::create_account(1, &self.epoch_schedule)
|
sysvar::epoch_schedule::create_account(
|
||||||
|
self.inherit_sysvar_account_balance(account),
|
||||||
|
&self.epoch_schedule,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,8 +664,11 @@ impl Bank {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if I'm the first Bank in an epoch, ensure stake_history is updated
|
// if I'm the first Bank in an epoch, ensure stake_history is updated
|
||||||
self.update_sysvar_account(&sysvar::stake_history::id(), |_| {
|
self.update_sysvar_account(&sysvar::stake_history::id(), |account| {
|
||||||
sysvar::stake_history::create_account(1, self.stakes.read().unwrap().history())
|
sysvar::stake_history::create_account(
|
||||||
|
self.inherit_sysvar_account_balance(account),
|
||||||
|
self.stakes.read().unwrap().history(),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,8 +703,12 @@ impl Bank {
|
||||||
validator_rewards / validator_points as f64,
|
validator_rewards / validator_points as f64,
|
||||||
storage_rewards / storage_points as f64,
|
storage_rewards / storage_points as f64,
|
||||||
);
|
);
|
||||||
self.update_sysvar_account(&sysvar::rewards::id(), |_| {
|
self.update_sysvar_account(&sysvar::rewards::id(), |account| {
|
||||||
sysvar::rewards::create_account(1, validator_point_value, storage_point_value)
|
sysvar::rewards::create_account(
|
||||||
|
self.inherit_sysvar_account_balance(account),
|
||||||
|
validator_point_value,
|
||||||
|
storage_point_value,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let validator_rewards = self.pay_validator_rewards(validator_point_value);
|
let validator_rewards = self.pay_validator_rewards(validator_point_value);
|
||||||
|
@ -754,10 +774,13 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_recent_blockhashes(&self) {
|
pub fn update_recent_blockhashes(&self) {
|
||||||
self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |_| {
|
self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |account| {
|
||||||
let blockhash_queue = self.blockhash_queue.read().unwrap();
|
let blockhash_queue = self.blockhash_queue.read().unwrap();
|
||||||
let recent_blockhash_iter = blockhash_queue.get_recent_blockhashes();
|
let recent_blockhash_iter = blockhash_queue.get_recent_blockhashes();
|
||||||
sysvar::recent_blockhashes::create_account_with_data(1, recent_blockhash_iter)
|
sysvar::recent_blockhashes::create_account_with_data(
|
||||||
|
self.inherit_sysvar_account_balance(account),
|
||||||
|
recent_blockhash_iter,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1945,12 +1968,13 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"bank frozen: {} hash: {} accounts_delta: {} signature_count: {} last_blockhash: {}",
|
"bank frozen: {} hash: {} accounts_delta: {} signature_count: {} last_blockhash: {} capitalization: {}",
|
||||||
self.slot(),
|
self.slot(),
|
||||||
hash,
|
hash,
|
||||||
accounts_delta_hash.hash,
|
accounts_delta_hash.hash,
|
||||||
self.signature_count(),
|
self.signature_count(),
|
||||||
self.last_blockhash(),
|
self.last_blockhash(),
|
||||||
|
self.capitalization(),
|
||||||
);
|
);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
|
@ -3558,6 +3582,27 @@ mod tests {
|
||||||
assert_eq!(bank.get_balance(&pubkey), 500);
|
assert_eq!(bank.get_balance(&pubkey), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transfer_to_sysvar() {
|
||||||
|
solana_logger::setup();
|
||||||
|
let (genesis_config, mint_keypair) = create_genesis_config(10_000);
|
||||||
|
let bank = Arc::new(Bank::new(&genesis_config));
|
||||||
|
|
||||||
|
let normal_pubkey = Pubkey::new_rand();
|
||||||
|
let sysvar_pubkey = sysvar::clock::id();
|
||||||
|
assert_eq!(bank.get_balance(&normal_pubkey), 0);
|
||||||
|
assert_eq!(bank.get_balance(&sysvar_pubkey), 1);
|
||||||
|
|
||||||
|
bank.transfer(500, &mint_keypair, &normal_pubkey).unwrap();
|
||||||
|
bank.transfer(500, &mint_keypair, &sysvar_pubkey).unwrap();
|
||||||
|
assert_eq!(bank.get_balance(&normal_pubkey), 500);
|
||||||
|
assert_eq!(bank.get_balance(&sysvar_pubkey), 501);
|
||||||
|
|
||||||
|
let bank = Arc::new(new_from_parent(&bank));
|
||||||
|
assert_eq!(bank.get_balance(&normal_pubkey), 500);
|
||||||
|
assert_eq!(bank.get_balance(&sysvar_pubkey), 501);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bank_deposit() {
|
fn test_bank_deposit() {
|
||||||
let (genesis_config, _mint_keypair) = create_genesis_config(100);
|
let (genesis_config, _mint_keypair) = create_genesis_config(100);
|
||||||
|
|
Loading…
Reference in New Issue