-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Maintain sysvar balances for consistent market cap. #9936
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -778,6 +778,14 @@ fn main() { | |
| .help("Include sysvars too"), | ||
| ) | ||
| .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::with_name("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 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| .get_program_accounts(None) | ||
| .into_iter() | ||
| .filter_map(|(_pubkey, account)| { | ||
| if account.lamports == u64::max_value() { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is like this handling (at #9869) CC: @CriesofCarrots:
|
||
| return None; | ||
| } | ||
|
|
||
| let is_specially_retained = | ||
| solana_sdk::native_loader::check_id(&account.owner) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jackcmay I'm not that familiar with loaders... Well, loaders can have similar problem as this pr? What happens to the balance if one of loaders is updated? (or not updated ever, first of all?)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it seems that I can't change of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once marked executable you can't change its lamports
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And, iirc the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct |
||
| || 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())); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @danpaul000 FYI: I've created the rust version of |
||
| } | ||
| Err(err) => { | ||
| eprintln!("Failed to load ledger: {:?}", err); | ||
| exit(1); | ||
| } | ||
| } | ||
| } | ||
| ("purge", Some(arg_matches)) => { | ||
| let start_slot = value_t_or_exit!(arg_matches, "start_slot", Slot); | ||
| let end_slot = value_t!(arg_matches, "end_slot", Slot); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -563,16 +563,20 @@ impl Bank { | |
| self.store_account(pubkey, &new_account); | ||
| } | ||
|
|
||
| fn inherit_sysvar_account_balance(&self, old_account: &Option<Account>) -> u64 { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not |
||
| old_account.as_ref().map(|a| a.lamports).unwrap_or(1) | ||
| } | ||
|
|
||
| fn update_clock(&self) { | ||
| self.update_sysvar_account(&sysvar::clock::id(), |_| { | ||
| self.update_sysvar_account(&sysvar::clock::id(), |account| { | ||
| sysvar::clock::Clock { | ||
| slot: self.slot, | ||
| segment: get_segment_from_slot(self.slot, self.slots_per_segment), | ||
| epoch: self.epoch_schedule.get_epoch(self.slot), | ||
| leader_schedule_epoch: self.epoch_schedule.get_leader_schedule_epoch(self.slot), | ||
| 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()) | ||
| .unwrap_or_default(); | ||
| 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()) | ||
| .unwrap_or_default(); | ||
| 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) { | ||
| self.update_sysvar_account(&sysvar::fees::id(), |_| { | ||
| sysvar::fees::create_account(1, &self.fee_calculator) | ||
| self.update_sysvar_account(&sysvar::fees::id(), |account| { | ||
| sysvar::fees::create_account( | ||
| self.inherit_sysvar_account_balance(account), | ||
| &self.fee_calculator, | ||
| ) | ||
| }); | ||
| } | ||
|
|
||
| fn update_rent(&self) { | ||
| self.update_sysvar_account(&sysvar::rent::id(), |_| { | ||
| sysvar::rent::create_account(1, &self.rent_collector.rent) | ||
| self.update_sysvar_account(&sysvar::rent::id(), |account| { | ||
| sysvar::rent::create_account( | ||
| self.inherit_sysvar_account_balance(account), | ||
| &self.rent_collector.rent, | ||
| ) | ||
| }); | ||
| } | ||
|
|
||
| fn update_epoch_schedule(&self) { | ||
| self.update_sysvar_account(&sysvar::epoch_schedule::id(), |_| { | ||
| sysvar::epoch_schedule::create_account(1, &self.epoch_schedule) | ||
| self.update_sysvar_account(&sysvar::epoch_schedule::id(), |account| { | ||
| sysvar::epoch_schedule::create_account( | ||
| self.inherit_sysvar_account_balance(account), | ||
| &self.epoch_schedule, | ||
| ) | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -651,8 +664,11 @@ impl Bank { | |
| return; | ||
| } | ||
| // if I'm the first Bank in an epoch, ensure stake_history is updated | ||
| self.update_sysvar_account(&sysvar::stake_history::id(), |_| { | ||
| sysvar::stake_history::create_account(1, self.stakes.read().unwrap().history()) | ||
| self.update_sysvar_account(&sysvar::stake_history::id(), |account| { | ||
| 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, | ||
| storage_rewards / storage_points as f64, | ||
| ); | ||
| self.update_sysvar_account(&sysvar::rewards::id(), |_| { | ||
| sysvar::rewards::create_account(1, validator_point_value, storage_point_value) | ||
| self.update_sysvar_account(&sysvar::rewards::id(), |account| { | ||
| 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); | ||
|
|
@@ -754,10 +774,13 @@ impl Bank { | |
| } | ||
|
|
||
| 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 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!( | ||
| "bank frozen: {} hash: {} accounts_delta: {} signature_count: {} last_blockhash: {}", | ||
| "bank frozen: {} hash: {} accounts_delta: {} signature_count: {} last_blockhash: {} capitalization: {}", | ||
| self.slot(), | ||
| hash, | ||
| accounts_delta_hash.hash, | ||
| self.signature_count(), | ||
| self.last_blockhash(), | ||
| self.capitalization(), | ||
| ); | ||
|
|
||
| info!( | ||
|
|
@@ -3558,6 +3582,27 @@ mod tests { | |
| 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] | ||
| fn test_bank_deposit() { | ||
| let (genesis_config, _mint_keypair) = create_genesis_config(100); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm planning to promote this to the
Displayacross the whole cli. But, that change will be invasive; let's minimize for now.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this pr absolutely needs this precision over
f64because capitalization tends to be well larger than the significant digits off64.