From 7b05b3dbb35c81be85520b422709efd699b65c50 Mon Sep 17 00:00:00 2001 From: Parth Date: Thu, 14 Nov 2019 10:56:49 +0530 Subject: [PATCH] rent collector improvments (#6888) * avoid account copying + pre-empt rent * adding support for base rent --- core/src/validator.rs | 2 +- core/tests/client.rs | 5 ++-- runtime/src/accounts.rs | 5 +++- runtime/src/rent_collector.rs | 14 +++++----- sdk/src/rent.rs | 49 ++++++++++++++++++++++++++++------- 5 files changed, 56 insertions(+), 19 deletions(-) diff --git a/core/src/validator.rs b/core/src/validator.rs index d2dacada26..3330498ccb 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -508,7 +508,7 @@ pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) { mut genesis_config, mint_keypair, voting_keypair, - } = create_genesis_config_with_leader(10_000, &contact_info.id, 42); + } = create_genesis_config_with_leader(1_000_000, &contact_info.id, 42); genesis_config .native_instruction_processors .push(solana_budget_program!()); diff --git a/core/tests/client.rs b/core/tests/client.rs index 05deec3686..d85a972da4 100644 --- a/core/tests/client.rs +++ b/core/tests/client.rs @@ -23,7 +23,8 @@ fn test_rpc_client() { ); assert_eq!(client.get_balance(&bob_pubkey).unwrap(), 0); - assert_eq!(client.get_balance(&alice.pubkey()).unwrap(), 10000); + + assert_eq!(client.get_balance(&alice.pubkey()).unwrap(), 1_000_000); let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); @@ -49,7 +50,7 @@ fn test_rpc_client() { assert!(confirmed_tx); assert_eq!(client.get_balance(&bob_pubkey).unwrap(), 20); - assert_eq!(client.get_balance(&alice.pubkey()).unwrap(), 9980); + assert_eq!(client.get_balance(&alice.pubkey()).unwrap(), 999980); server.close().unwrap(); remove_dir_all(ledger_path).unwrap(); diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 401722e6af..205434e7de 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -114,7 +114,10 @@ impl Accounts { .filter(|key| !message.program_ids().contains(key)) { let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key) - .and_then(|(account, _)| rent_collector.update(account)) + .and_then(|(mut account, _)| { + let rent_due = rent_collector.update(&mut account); + Some((account, rent_due)) + }) .unwrap_or_default(); accounts.push(account); diff --git a/runtime/src/rent_collector.rs b/runtime/src/rent_collector.rs index 373b6fd5ca..86ccd1ba11 100644 --- a/runtime/src/rent_collector.rs +++ b/runtime/src/rent_collector.rs @@ -33,9 +33,9 @@ impl RentCollector { // updates this account's lamports and status and returns // the account rent collected, if any // - pub fn update(&self, mut account: Account) -> Option<(Account, u64)> { - if account.data.is_empty() || account.rent_epoch > self.epoch { - Some((account, 0)) + pub fn update(&self, account: &mut Account) -> u64 { + if account.rent_epoch > self.epoch { + 0 } else { let slots_elapsed: u64 = (account.rent_epoch..=self.epoch) .map(|epoch| self.epoch_schedule.get_slots_in_epoch(epoch + 1)) @@ -51,13 +51,15 @@ impl RentCollector { if account.lamports > rent_due { account.rent_epoch = self.epoch + 1; account.lamports -= rent_due; - Some((account, rent_due)) + rent_due } else { - None + let rent_charged = account.lamports; + *account = Account::default(); + rent_charged } } else { // maybe collect rent later, leave account alone - Some((account, 0)) + 0 } } } diff --git a/sdk/src/rent.rs b/sdk/src/rent.rs index 2c977da073..bfa3a101fa 100644 --- a/sdk/src/rent.rs +++ b/sdk/src/rent.rs @@ -26,6 +26,9 @@ pub const DEFAULT_EXEMPTION_THRESHOLD: f64 = 2.0; /// default amount of rent to burn, as a fraction of std::u8::MAX pub const DEFAULT_BURN_PERCENT: u8 = ((50usize * std::u8::MAX as usize) / 100usize) as u8; +/// default account storage over head for calculation of base rent +pub const ACCOUNT_STORAGE_OVERHEAD: u64 = 128; + impl Default for Rent { fn default() -> Self { Self { @@ -40,7 +43,8 @@ impl Rent { /// minimum balance due for a given size Account::data.len() pub fn minimum_balance(&self, data_len: usize) -> u64 { let bytes = data_len as u64; - bytes * (self.exemption_threshold * self.lamports_per_byte_year as f64) as u64 + (((ACCOUNT_STORAGE_OVERHEAD + bytes) * self.lamports_per_byte_year) as f64 + * self.exemption_threshold) as u64 } /// whether a given balance and data_len would be exempt @@ -54,7 +58,9 @@ impl Rent { (0, true) } else { ( - ((self.lamports_per_byte_year * data_len as u64) as f64 * years_elapsed) as u64, + ((self.lamports_per_byte_year * (data_len as u64 + ACCOUNT_STORAGE_OVERHEAD)) + as f64 + * years_elapsed) as u64, false, ) } @@ -74,20 +80,45 @@ mod tests { #[test] fn test_due() { - let rent = Rent::default(); + let default_rent = Rent::default(); assert_eq!( - rent.due(0, 1, 1.0), + default_rent.due(0, 2, 1.2), ( - DEFAULT_LAMPORTS_PER_BYTE_YEAR, + (((2 + ACCOUNT_STORAGE_OVERHEAD) * DEFAULT_LAMPORTS_PER_BYTE_YEAR) as f64 * 1.2) + as u64, DEFAULT_LAMPORTS_PER_BYTE_YEAR == 0 ) ); assert_eq!( - rent.due( - DEFAULT_LAMPORTS_PER_BYTE_YEAR * DEFAULT_EXEMPTION_THRESHOLD as u64, - 1, - 1.0 + default_rent.due( + (((2 + ACCOUNT_STORAGE_OVERHEAD) * DEFAULT_LAMPORTS_PER_BYTE_YEAR) as f64 + * DEFAULT_EXEMPTION_THRESHOLD) as u64, + 2, + 1.2 + ), + (0, true) + ); + + let mut custom_rent = Rent::default(); + custom_rent.lamports_per_byte_year = 5; + custom_rent.exemption_threshold = 2.5; + + assert_eq!( + custom_rent.due(0, 2, 1.2), + ( + (((2 + ACCOUNT_STORAGE_OVERHEAD) * custom_rent.lamports_per_byte_year) as f64 * 1.2) + as u64, + false + ) + ); + + assert_eq!( + custom_rent.due( + (((2 + ACCOUNT_STORAGE_OVERHEAD) * custom_rent.lamports_per_byte_year) as f64 + * custom_rent.exemption_threshold) as u64, + 2, + 1.2 ), (0, true) );