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
84 changes: 84 additions & 0 deletions ledger-tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,13 @@ fn main() {
.takes_value(false)
.help("Include sysvars too"),
)
).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)
).subcommand(
SubCommand::with_name("prune")
.about("Prune the ledger at the block height")
Expand Down Expand Up @@ -1047,6 +1054,83 @@ 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(&ledger_path);
match load_bank_forks(arg_matches, &ledger_path, &genesis_config, process_options) {
Ok((bank_forks, bank_forks_info, _leader_schedule_cache, _snapshot_hash)) => {
let slot = dev_halt_at_slot.unwrap_or_else(|| {
if bank_forks_info.len() > 1 {
eprintln!("Error: multiple forks present");
exit(1);
}
bank_forks_info[0].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)) => {
let start_slot = value_t_or_exit!(arg_matches, "start_slot", Slot);
let end_slot = value_t!(arg_matches, "end_slot", Slot);
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/accounts_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ impl AccountsDB {

pub fn include_owner_in_hash(slot: Slot) -> bool {
// Account hashing updated to include owner activates at this slot on the mainnet-beta
slot >= 11_000_000
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.

My bad... follow-up to #9920, yeah piggybacking on this pr..

11_000_000 is too close to tds tigger timing (*). I think this violates the purpose of OperatingMode::Preview... ;)

let's again move later to some round number of weekday. Or I'm caring too much?

$ cal
      May 2020        
Su Mo Tu We Th Fr Sa  
                1  2  
 3  4  5  6  7  8  9  
10 11 12 13 14 15 16  
17 18 19 20 21 22 23  
24 25 26 27 28 29 30  
31                    

$ pry
[5] pry(main)> Time.now + ((11_000_000 - 9834692) / 2.5) # mainnet beta
=> 2020-05-14 05:40:42 +0900
[7] pry(main)> Time.now + ((14_000_000 - 12953124) / 2.5) # tds
=> 2020-05-13 16:31:21 +0900
[6] pry(main)> Time.now + ((12_000_000 - 9834692) / 2.5) # another weekend around the world...
=> 2020-05-18 20:47:29 +0900
[8] pry(main)> Time.now + ((12_500_000 - 9834692) / 2.5) # projected trigger time
=> 2020-05-21 04:21:46 +0900

slot >= 12_500_000
}

pub fn hash_account_data(
Expand Down
104 changes: 87 additions & 17 deletions runtime/src/bank/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub const MAX_SNAPSHOT_DATA_FILE_SIZE: u64 = 32 * 1024 * 1024 * 1024; // 32 GiB

pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;

const SYSVAR_BALANCE_ACTIVATION_EPOCH: Epoch = 25;
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.

Let's land this first than account.owner hashing considering significace:

$ pry
[2] pry(main)> Time.now + ((432000 - 336972) / 2.5) + 4 * 3600 * 24
=> 2020-05-13 07:32:39 +0900
$ solana  --url http://api.mainnet-beta.solana.com epoch-info

Slot: 9840972
Epoch: 22
Epoch Slot Range: [9504000..9936000)
Epoch Completed Percent: 78.003%
Epoch Completed Slots: 336972/432000 (95028 remaining)
Epoch Completed Time: 1day 13h 26m 28s/2days (10h 33m 31s remaining)

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.

Just now, mainnet-beta went into new sysvar behavior:

$ solana --url http://api.mainnet-beta.solana.com epoch-info

Slot: 10800429
Epoch: 25
Epoch slot range: [10800000..11232000)
Epoch completed percent: 0.099%
Epoch completed slots: 429/432000 (431571 remaining)
Epoch completed time: 2m 51s/2days (1day 23h 57m 8s remaining)

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.

Confirmed we now fixed the capitalization security hole.

$ solana-ledger-tool --version
solana-ledger-tool 1.0.23 [channel=on-ryoqun-fork commit=e26840cb09465352067aa037b2eee7591091529b]

$ solana-ledger-tool --ledger 7Np4/ capitalization
[2020-05-13T14:58:52.451659928Z INFO  solana_ledger::blockstore] Maximum open file descriptors: 65000
[2020-05-13T14:58:52.451757437Z INFO  solana_ledger::blockstore] Opening database at "/home/ryoqun/work/solana/solana/7Np4/rocksdb"
[2020-05-13T14:58:52.496282617Z INFO  solana_ledger::blockstore] "/home/ryoqun/work/solana/solana/7Np4/rocksdb" open took 44ms
[2020-05-13T14:58:52.496396355Z INFO  solana_ledger::bank_forks_utils] Initializing snapshot path: "/home/ryoqun/work/solana/solana/7Np4/snapshot"
[2020-05-13T14:58:52.510939661Z INFO  solana_ledger::bank_forks_utils] Loading snapshot package: "/home/ryoqun/work/solana/solana/7Np4/snapshot-10800485-D7hNsgoVP78JhCcYaLnNxmcjdmFGsVV972LPHws2F8sW.tar.bz2"
[2020-05-13T15:00:44.248861917Z INFO  solana_ledger::snapshot_utils] snapshot untar took 111.7s
[2020-05-13T15:00:44.249240456Z INFO  solana_ledger::snapshot_utils] snapshot version: 1.1.0
[2020-05-13T15:00:44.249389877Z INFO  solana_ledger::snapshot_utils] Loading bank from "/home/ryoqun/work/solana/solana/7Np4/snapshot/.tmp7V6HdT/snapshots/10800485/10800485"
[2020-05-13T15:00:44.349281802Z INFO  solana_ledger::snapshot_utils] Rebuilding accounts...
[2020-05-13T15:03:59.756305474Z INFO  solana_ledger::snapshot_utils] Rebuilding status cache...
[2020-05-13T15:04:00.177954788Z INFO  solana_ledger::snapshot_utils] Loaded bank for slot: 10800485
[2020-05-13T15:04:00.179688287Z INFO  solana_runtime::accounts_db] total_stores: 2500, newest_slot: 10800485, oldest_slot: 0, max_slot: 0 (num=5), min_slot: 4352296 (num=1)
[2020-05-13T15:04:00.179824349Z INFO  solana_metrics::metrics] metrics disabled: SOLANA_METRICS_CONFIG: environment variable not found
[2020-05-13T15:04:00.180175764Z INFO  solana_metrics::metrics] datapoint: accounts_db-stores total_count=2500i
[2020-05-13T15:04:01.017741218Z INFO  solana_runtime::accounts_db] scan took 309us merge took 55us accumulate took 157us
[2020-05-13T15:04:01.017911287Z INFO  solana_runtime::bank] bank frozen: 10800485 hash: HHQZF2VqbKfhWrWqySVPHZfkqQAB1sHA7LHG35Fv9duN accounts_delta: DrbroEkyrFtMTwyp1xEWfXnpAdYurwXMiSqBvz2gZab signature_count: 2 last_blockhash: DdmF1iG8ERFS4YGKUowDxmemqSFAd8VUS8uTYEoguLw8 capitalization: 499996966416753973
[2020-05-13T15:04:01.018237665Z INFO  solana_runtime::bank] accounts hash slot: 10800485 stats: BankHashStats { num_removed_accounts: 10, num_added_accounts: 0, num_lamports_stored: 1340866471525, total_data_len: 165103, num_executable_accounts: 0 }
[2020-05-13T15:04:01.018317962Z INFO  solana_ledger::snapshot_utils] bank rebuild from snapshot took 196.8s
[2020-05-13T15:04:01.027419913Z INFO  solana_ledger::blockstore_processor] processing ledger from root slot 10800485...
[2020-05-13T15:04:02.474804690Z INFO  solana_ledger::blockstore_processor] ledger processed in 1445ms. 90 MB allocated. 1 fork at 10800485, with 1 frozen bank
Capitalization: 499996966.416753973 SOL


type BankStatusCache = StatusCache<Result<()>>;
pub type BankSlotDelta = SlotDelta<Result<()>>;
type TransactionAccountRefCells = Vec<Rc<RefCell<Account>>>;
Expand Down Expand Up @@ -556,16 +558,25 @@ impl Bank {
self.store_account(pubkey, &new_account);
}

fn inherit_sysvar_account_balance(&self, old_account: &Option<Account>) -> u64 {
// Corrent sysvar account balance maintenance activates at this epoch on the mainnet-beta
if self.epoch() >= SYSVAR_BALANCE_ACTIVATION_EPOCH {
old_account.as_ref().map(|a| a.lamports).unwrap_or(1)
} else {
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 @@ -576,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 @@ -587,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 @@ -622,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 @@ -644,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 @@ -680,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 @@ -747,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 @@ -1896,12 +1926,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 @@ -3484,6 +3515,45 @@ 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_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), 1);

let bank = Arc::new(Bank::new_from_parent(
&bank,
&Pubkey::default(),
genesis_config
.epoch_schedule
.get_first_slot_in_epoch(SYSVAR_BALANCE_ACTIVATION_EPOCH),
));

let normal_pubkey = Pubkey::new_rand();
bank.transfer(6000, &mint_keypair, &normal_pubkey).unwrap();
bank.transfer(6000, &mint_keypair, &sysvar_pubkey).unwrap();
assert_eq!(bank.get_balance(&normal_pubkey), 3561);
assert_eq!(bank.get_balance(&sysvar_pubkey), 6001);

let bank = Arc::new(new_from_parent(&bank));
assert_eq!(bank.get_balance(&normal_pubkey), 3561);
assert_eq!(bank.get_balance(&sysvar_pubkey), 6001);
}

#[test]
fn test_bank_deposit() {
let (genesis_config, _mint_keypair) = create_genesis_config(100);
Expand Down