Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions ledger-tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Expand Down Expand Up @@ -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",
Copy link
Copy Markdown
Contributor Author

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 Display across the whole cli. But, that change will be invasive; let's minimize for now.

Copy link
Copy Markdown
Contributor Author

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 f64 because capitalization tends to be well larger than the significant digits of f64.

self.0 / LAMPORTS_PER_SOL,
self.0 % LAMPORTS_PER_SOL
)
}
}

let computed_capitalization: u64 = bank
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to use u64 over u128 unlike this (pr #9582) because account.lamports are well trusted data field in this context (We're past the snapshot verification) and the max capitazalition must always be within u64. Also, being u64 caught this.

.get_program_accounts(None)
.into_iter()
.filter_map(|(_pubkey, account)| {
if account.lamports == u64::max_value() {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is like this handling (at #9869) CC: @CriesofCarrots:

  • Filter out Storage program RewardsPools that get initialized with u64::MAX lamports

return None;
}

let is_specially_retained =
solana_sdk::native_loader::check_id(&account.owner)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it seems that I can't change of account.lamports first of all:

$ solana --url http://localhost:8899 pay -v Stake11111111111111111111111111111111111111 0.82643
RPC URL: http://localhost:8899
Default Signer Path: /home/ryoqun/.config/solana/id.json
Error: TransactionError::InstructionError(0, ExecutableLamportChange)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once marked executable you can't change its lamports

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, iirc the executable bit can't be off after that, too? :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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()));
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danpaul000 FYI: I've created the rust version of capitalization bash script, which you created in that past iirc. :)

$ RUST_LOG=solana=error solana-ledger-tool --ledger config/ledger/ capitalization
Capitalization: 999999999.998820000 SOL

}
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);
Expand Down
79 changes: 62 additions & 17 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,16 +563,20 @@ impl Bank {
self.store_account(pubkey, &new_account);
}

fn inherit_sysvar_account_balance(&self, old_account: &Option<Account>) -> u64 {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not Self::? hint: for gating logic of backport prs: self.epoch().

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))
});
}

Expand All @@ -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))
});
}

Expand All @@ -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))
});
}

Expand Down Expand Up @@ -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,
)
});
}

Expand All @@ -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(),
)
});
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
)
});
}

Expand Down Expand Up @@ -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!(
Expand Down Expand Up @@ -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);
Expand Down