Add incinerator sysvar (#9815)
This commit is contained in:
parent
450f1d2867
commit
8dfe0affd4
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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");
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue