Skip to content

Commit

Permalink
v1.0: incinerator backport (solana-labs#9837)
Browse files Browse the repository at this point in the history
  • Loading branch information
mvines authored May 1, 2020
1 parent 2deebe4 commit 91f0faa
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 8 deletions.
4 changes: 2 additions & 2 deletions runtime/src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,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))
Expand Down Expand Up @@ -671,7 +671,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));
}
Expand Down
74 changes: 72 additions & 2 deletions runtime/src/bank/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use solana_sdk::{
genesis_config::GenesisConfig,
hard_forks::HardForks,
hash::{extend_and_hash, hashv, Hash},
incinerator,
inflation::Inflation,
native_loader, nonce,
pubkey::Pubkey,
Expand Down Expand Up @@ -792,6 +793,9 @@ impl Bank {
self.collect_fees();
self.distribute_rent();
self.update_slot_history();
if self.epoch >= incinerator::ACTIVATION_EPOCH {
self.run_incinerator();
}

// freeze is a one-way trip, idempotent
*hash = self.hash_internal_state();
Expand Down Expand Up @@ -1629,6 +1633,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(
Expand Down Expand Up @@ -1741,8 +1753,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);
}
Expand Down Expand Up @@ -5772,4 +5786,60 @@ mod tests {
info!("account: {:?}", account);
assert!(account.executable);
}

#[test]
fn test_incinerator_inactive() {
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();

let burn_amount = bank.get_minimum_balance_for_rent_exemption(0);

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

// No effect!
assert_eq!(bank.get_balance(&incinerator::id()), burn_amount);
assert_eq!(bank.capitalization(), pre_capitalization);
}

#[test]
fn test_incinerator_active() {
let (genesis_config, mint_keypair) = create_genesis_config(1_000_000_000_000);
let bank0 = Arc::new(Bank::new(&genesis_config));

// Move to the incinerator activation epoch
let bank = Bank::new_from_parent(
&bank0,
&Pubkey::default(),
genesis_config
.epoch_schedule
.get_first_slot_in_epoch(incinerator::ACTIVATION_EPOCH),
);
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);
}
}
9 changes: 7 additions & 2 deletions runtime/src/rent_collector.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -35,7 +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 {
pub fn update(&self, address: &Pubkey, account: &mut Account) -> u64 {
if *address == incinerator::id() && self.epoch >= incinerator::ACTIVATION_EPOCH {
return 0;
}

if account.executable || account.rent_epoch > self.epoch || sysvar::check_id(&account.owner)
{
0
Expand Down
8 changes: 6 additions & 2 deletions sdk/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
6 changes: 6 additions & 0 deletions sdk/src/incinerator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! Lamports credited to this address will be removed from the total supply (burned) at the end of
//! the current block.
crate::declare_id!("1nc1nerator11111111111111111111111111111111");

pub const ACTIVATION_EPOCH: u64 = 30; // Incinerator activates on mainnet-beta at this epoch
1 change: 1 addition & 0 deletions sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 91f0faa

Please sign in to comment.