Add incinerator sysvar (#9815)

This commit is contained in:
Michael Vines 2020-04-30 22:04:08 -07:00 committed by GitHub
parent 450f1d2867
commit 8dfe0affd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 9 deletions

View File

@ -162,7 +162,7 @@ impl Accounts {
let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key)
.and_then(|(mut account, _)| {
if message.is_writable(i) && !account.executable {
let rent_due = rent_collector.update(&mut account);
let rent_due = rent_collector.update(&key, &mut account);
Some((account, rent_due))
} else {
Some((account, 0))
@ -664,7 +664,7 @@ impl Accounts {
if message.is_writable(i) {
if account.rent_epoch == 0 {
account.rent_epoch = rent_collector.epoch;
acc.2 += rent_collector.update(account);
acc.2 += rent_collector.update(&key, account);
}
accounts.push((key, &*account));
}

View File

@ -42,6 +42,7 @@ use solana_sdk::{
genesis_config::GenesisConfig,
hard_forks::HardForks,
hash::{extend_and_hash, hashv, Hash},
incinerator,
inflation::Inflation,
native_loader, nonce,
pubkey::Pubkey,
@ -795,6 +796,7 @@ impl Bank {
self.collect_fees();
self.distribute_rent();
self.update_slot_history();
self.run_incinerator();
// freeze is a one-way trip, idempotent
*hash = self.hash_internal_state();
@ -1639,6 +1641,14 @@ impl Bank {
.fetch_add(collected_rent, Ordering::Relaxed);
}
fn run_incinerator(&self) {
if let Some((account, _)) = self.get_account_modified_since_parent(&incinerator::id()) {
self.capitalization
.fetch_sub(account.lamports, Ordering::Relaxed);
self.store_account(&incinerator::id(), &Account::default());
}
}
/// Process a batch of transactions.
#[must_use]
pub fn load_execute_and_commit_transactions(
@ -1751,8 +1761,10 @@ impl Bank {
pub fn deposit(&self, pubkey: &Pubkey, lamports: u64) {
let mut account = self.get_account(pubkey).unwrap_or_default();
self.collected_rent
.fetch_add(self.rent_collector.update(&mut account), Ordering::Relaxed);
self.collected_rent.fetch_add(
self.rent_collector.update(pubkey, &mut account),
Ordering::Relaxed,
);
account.lamports += lamports;
self.store_account(pubkey, &account);
}
@ -5843,4 +5855,32 @@ mod tests {
info!("account: {:?}", account);
assert!(account.executable);
}
#[test]
fn test_incinerator() {
let (genesis_config, mint_keypair) = create_genesis_config(1_000_000_000_000);
let bank0 = Arc::new(Bank::new(&genesis_config));
// Move to the first normal slot so normal rent behaviour applies
let bank = Bank::new_from_parent(
&bank0,
&Pubkey::default(),
genesis_config.epoch_schedule.first_normal_slot,
);
let pre_capitalization = bank.capitalization();
// Burn a non-rent exempt amount
let burn_amount = bank.get_minimum_balance_for_rent_exemption(0) - 1;
assert_eq!(bank.get_balance(&incinerator::id()), 0);
bank.transfer(burn_amount, &mint_keypair, &incinerator::id())
.unwrap();
assert_eq!(bank.get_balance(&incinerator::id()), burn_amount);
bank.freeze();
assert_eq!(bank.get_balance(&incinerator::id()), 0);
// Ensure that no rent was collected, and the entire burn amount was removed from bank
// capitalization
assert_eq!(bank.capitalization(), pre_capitalization - burn_amount);
}
}

View File

@ -1,6 +1,7 @@
//! calculate and collect rent from Accounts
use solana_sdk::{
account::Account, clock::Epoch, epoch_schedule::EpochSchedule, rent::Rent, sysvar,
account::Account, clock::Epoch, epoch_schedule::EpochSchedule, incinerator, pubkey::Pubkey,
rent::Rent, sysvar,
};
#[derive(Default, Serialize, Deserialize, Clone)]
@ -35,8 +36,11 @@ impl RentCollector {
// updates this account's lamports and status and returns
// the account rent collected, if any
//
pub fn update(&self, account: &mut Account) -> u64 {
if account.executable || account.rent_epoch > self.epoch || sysvar::check_id(&account.owner)
pub fn update(&self, address: &Pubkey, account: &mut Account) -> u64 {
if account.executable
|| account.rent_epoch > self.epoch
|| sysvar::check_id(&account.owner)
|| *address == incinerator::id()
{
0
} else {

View File

@ -21,8 +21,12 @@ impl Parse for Id {
let id_vec = bs58::decode(id_literal.value())
.into_vec()
.map_err(|_| syn::Error::new_spanned(&id_literal, "failed to decode base58 id"))?;
let id_array = <[u8; 32]>::try_from(<&[u8]>::clone(&&id_vec[..]))
.map_err(|_| syn::Error::new_spanned(&id_literal, "id is not 32 bytes long"))?;
let id_array = <[u8; 32]>::try_from(<&[u8]>::clone(&&id_vec[..])).map_err(|_| {
syn::Error::new_spanned(
&id_literal,
format!("id is not 32 bytes long: len={}", id_vec.len()),
)
})?;
let bytes = id_array.iter().map(|b| LitByte::new(*b, Span::call_site()));
quote! {
::solana_sdk::pubkey::Pubkey::new_from_array(

4
sdk/src/incinerator.rs Normal file
View File

@ -0,0 +1,4 @@
//! Lamports credited to this address will be removed from the total supply (burned) at the end of
//! the current block.
crate::declare_id!("1nc1nerator11111111111111111111111111111111");

View File

@ -10,6 +10,7 @@ pub mod entrypoint_native;
pub mod epoch_schedule;
pub mod fee_calculator;
pub mod hash;
pub mod incinerator;
pub mod inflation;
pub mod instruction;
pub mod loader_instruction;