plumb some rent (#5610)
* plumb some rent * nits * fixups * fixups * fixups
This commit is contained in:
@ -871,7 +871,8 @@ pub mod tests {
|
|||||||
"owner": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
|
"owner": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
|
||||||
"lamports": 20,
|
"lamports": 20,
|
||||||
"data": [],
|
"data": [],
|
||||||
"executable": false
|
"executable": false,
|
||||||
|
"rent_epoch": 0
|
||||||
},
|
},
|
||||||
"id":1}
|
"id":1}
|
||||||
"#;
|
"#;
|
||||||
@ -903,7 +904,8 @@ pub mod tests {
|
|||||||
"owner": {:?},
|
"owner": {:?},
|
||||||
"lamports": 20,
|
"lamports": 20,
|
||||||
"data": [],
|
"data": [],
|
||||||
"executable": false
|
"executable": false,
|
||||||
|
"rent_epoch": 0
|
||||||
}}]],
|
}}]],
|
||||||
"id":1}}
|
"id":1}}
|
||||||
"#,
|
"#,
|
||||||
|
@ -429,7 +429,8 @@ mod tests {
|
|||||||
"owner": budget_program_id,
|
"owner": budget_program_id,
|
||||||
"lamports": 51,
|
"lamports": 51,
|
||||||
"data": expected_data,
|
"data": expected_data,
|
||||||
"executable": executable,
|
"executable": executable,
|
||||||
|
"rent_epoch": 0,
|
||||||
},
|
},
|
||||||
"subscription": 0,
|
"subscription": 0,
|
||||||
}
|
}
|
||||||
@ -574,6 +575,7 @@ mod tests {
|
|||||||
"lamports": 100,
|
"lamports": 100,
|
||||||
"data": [],
|
"data": [],
|
||||||
"executable": false,
|
"executable": false,
|
||||||
|
"rent_epoch": 0,
|
||||||
},
|
},
|
||||||
"subscription": 0,
|
"subscription": 0,
|
||||||
}
|
}
|
||||||
|
@ -348,7 +348,7 @@ mod tests {
|
|||||||
subscriptions.check_account(&alice.pubkey(), 0, &bank_forks);
|
subscriptions.check_account(&alice.pubkey(), 0, &bank_forks);
|
||||||
let string = transport_receiver.poll();
|
let string = transport_receiver.poll();
|
||||||
if let Async::Ready(Some(response)) = string.unwrap() {
|
if let Async::Ready(Some(response)) = string.unwrap() {
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","method":"accountNotification","params":{{"result":{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0]}},"subscription":0}}}}"#);
|
let expected = format!(r#"{{"jsonrpc":"2.0","method":"accountNotification","params":{{"result":{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0],"rent_epoch":0}},"subscription":0}}}}"#);
|
||||||
assert_eq!(expected, response);
|
assert_eq!(expected, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +403,7 @@ mod tests {
|
|||||||
subscriptions.check_program(&solana_budget_api::id(), 0, &bank_forks);
|
subscriptions.check_program(&solana_budget_api::id(), 0, &bank_forks);
|
||||||
let string = transport_receiver.poll();
|
let string = transport_receiver.poll();
|
||||||
if let Async::Ready(Some(response)) = string.unwrap() {
|
if let Async::Ready(Some(response)) = string.unwrap() {
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["{:?}",{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0]}}],"subscription":0}}}}"#, alice.pubkey());
|
let expected = format!(r#"{{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["{:?}",{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0],"rent_epoch":0}}],"subscription":0}}}}"#, alice.pubkey());
|
||||||
assert_eq!(expected, response);
|
assert_eq!(expected, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ use solana_sdk::genesis_block::Builder;
|
|||||||
use solana_sdk::hash::{hash, Hash};
|
use solana_sdk::hash::{hash, Hash};
|
||||||
use solana_sdk::poh_config::PohConfig;
|
use solana_sdk::poh_config::PohConfig;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
|
use solana_sdk::rent::Rent;
|
||||||
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
|
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
|
||||||
use solana_sdk::system_program;
|
use solana_sdk::system_program;
|
||||||
use solana_sdk::timing;
|
use solana_sdk::timing;
|
||||||
@ -59,6 +60,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||||||
let default_target_lamports_per_signature = &FeeCalculator::default()
|
let default_target_lamports_per_signature = &FeeCalculator::default()
|
||||||
.target_lamports_per_signature
|
.target_lamports_per_signature
|
||||||
.to_string();
|
.to_string();
|
||||||
|
let default_lamports_per_byte_year = &Rent::default().lamports_per_byte_year.to_string();
|
||||||
let default_target_signatures_per_slot = &FeeCalculator::default()
|
let default_target_signatures_per_slot = &FeeCalculator::default()
|
||||||
.target_signatures_per_slot
|
.target_signatures_per_slot
|
||||||
.to_string();
|
.to_string();
|
||||||
@ -161,6 +163,17 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||||||
verification when the cluster is operating at target-signatures-per-slot",
|
verification when the cluster is operating at target-signatures-per-slot",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("lamports_per_byte_year")
|
||||||
|
.long("lamports-per-byte-year")
|
||||||
|
.value_name("LAMPORTS")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value(default_lamports_per_byte_year)
|
||||||
|
.help(
|
||||||
|
"The cost in lamports that the cluster will charge per byte per year \
|
||||||
|
for accounts with data.",
|
||||||
|
),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("target_signatures_per_slot")
|
Arg::with_name("target_signatures_per_slot")
|
||||||
.long("target-signatures-per-slot")
|
.long("target-signatures-per-slot")
|
||||||
|
@ -760,7 +760,7 @@ mod tests {
|
|||||||
lamports: 1,
|
lamports: 1,
|
||||||
data: bincode::serialize(&LibraAccountState::create_unallocated()).unwrap(),
|
data: bincode::serialize(&LibraAccountState::create_unallocated()).unwrap(),
|
||||||
owner: id(),
|
owner: id(),
|
||||||
executable: false,
|
..Account::default()
|
||||||
};
|
};
|
||||||
Self::new(key, account)
|
Self::new(key, account)
|
||||||
}
|
}
|
||||||
@ -768,9 +768,8 @@ mod tests {
|
|||||||
pub fn create_genesis(amount: u64) -> Self {
|
pub fn create_genesis(amount: u64) -> Self {
|
||||||
let account = Account {
|
let account = Account {
|
||||||
lamports: 1,
|
lamports: 1,
|
||||||
data: vec![],
|
|
||||||
owner: id(),
|
owner: id(),
|
||||||
executable: false,
|
..Account::default()
|
||||||
};
|
};
|
||||||
let mut genesis = Self::new(Pubkey::default(), account);
|
let mut genesis = Self::new(Pubkey::default(), account);
|
||||||
genesis.account.data =
|
genesis.account.data =
|
||||||
|
@ -547,10 +547,8 @@ mod tests {
|
|||||||
let mut account = StorageAccount {
|
let mut account = StorageAccount {
|
||||||
id: Pubkey::default(),
|
id: Pubkey::default(),
|
||||||
account: &mut Account {
|
account: &mut Account {
|
||||||
lamports: 0,
|
|
||||||
data: vec![],
|
|
||||||
owner: id(),
|
owner: id(),
|
||||||
executable: false,
|
..Account::default()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let segment_index = 0;
|
let segment_index = 0;
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
use crate::accounts_db::{
|
use crate::accounts_db::{AccountInfo, AccountStorage, AccountsDB, AppendVecId, ErrorCounters};
|
||||||
AccountInfo, AccountStorage, AccountsDB, AppendVecId, ErrorCounters, InstructionAccounts,
|
|
||||||
InstructionCredits, InstructionLoaders,
|
|
||||||
};
|
|
||||||
use crate::accounts_index::{AccountsIndex, Fork};
|
use crate::accounts_index::{AccountsIndex, Fork};
|
||||||
use crate::append_vec::StoredAccount;
|
use crate::append_vec::StoredAccount;
|
||||||
use crate::blockhash_queue::BlockhashQueue;
|
use crate::blockhash_queue::BlockhashQueue;
|
||||||
use crate::message_processor::has_duplicates;
|
use crate::message_processor::has_duplicates;
|
||||||
|
use crate::rent_collector::RentCollector;
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use log::*;
|
use log::*;
|
||||||
use rayon::slice::ParallelSliceMut;
|
use rayon::slice::ParallelSliceMut;
|
||||||
@ -46,6 +44,12 @@ pub struct Accounts {
|
|||||||
credit_only_account_locks: Arc<RwLock<Option<HashMap<Pubkey, CreditOnlyLock>>>>,
|
credit_only_account_locks: Arc<RwLock<Option<HashMap<Pubkey, CreditOnlyLock>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for the load instructions
|
||||||
|
pub type TransactionAccounts = Vec<Account>;
|
||||||
|
pub type TransactionCredits = Vec<u64>;
|
||||||
|
pub type TransactionRents = Vec<u64>;
|
||||||
|
pub type TransactionLoaders = Vec<Vec<(Pubkey, Account)>>;
|
||||||
|
|
||||||
impl Accounts {
|
impl Accounts {
|
||||||
pub fn new(paths: Option<String>) -> Self {
|
pub fn new(paths: Option<String>) -> Self {
|
||||||
let accounts_db = Arc::new(AccountsDB::new(paths));
|
let accounts_db = Arc::new(AccountsDB::new(paths));
|
||||||
@ -82,7 +86,8 @@ impl Accounts {
|
|||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
fee: u64,
|
fee: u64,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> Result<(Vec<Account>, InstructionCredits)> {
|
rent_collector: &RentCollector,
|
||||||
|
) -> Result<(TransactionAccounts, TransactionCredits, TransactionRents)> {
|
||||||
// Copy all the accounts
|
// Copy all the accounts
|
||||||
let message = tx.message();
|
let message = tx.message();
|
||||||
if tx.signatures.is_empty() && fee != 0 {
|
if tx.signatures.is_empty() && fee != 0 {
|
||||||
@ -96,30 +101,35 @@ impl Accounts {
|
|||||||
|
|
||||||
// There is no way to predict what program will execute without an error
|
// There is no way to predict what program will execute without an error
|
||||||
// If a fee can pay for execution then the program will be scheduled
|
// If a fee can pay for execution then the program will be scheduled
|
||||||
let mut called_accounts: Vec<Account> = vec![];
|
let mut accounts: TransactionAccounts = vec![];
|
||||||
let mut credits: InstructionCredits = vec![];
|
let mut credits: TransactionCredits = vec![];
|
||||||
for key in message.account_keys.iter() {
|
let mut rents: TransactionRents = vec![];
|
||||||
if !message.program_ids().contains(&key) {
|
for key in message
|
||||||
called_accounts.push(
|
.account_keys
|
||||||
AccountsDB::load(storage, ancestors, accounts_index, key)
|
.iter()
|
||||||
.map(|(account, _)| account)
|
.filter(|key| !message.program_ids().contains(&key))
|
||||||
.unwrap_or_default(),
|
{
|
||||||
);
|
let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key)
|
||||||
credits.push(0);
|
.and_then(|(account, _)| rent_collector.update(account))
|
||||||
}
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
accounts.push(account);
|
||||||
|
credits.push(0);
|
||||||
|
rents.push(rent);
|
||||||
}
|
}
|
||||||
if called_accounts.is_empty() || called_accounts[0].lamports == 0 {
|
|
||||||
|
if accounts.is_empty() || accounts[0].lamports == 0 {
|
||||||
error_counters.account_not_found += 1;
|
error_counters.account_not_found += 1;
|
||||||
Err(TransactionError::AccountNotFound)
|
Err(TransactionError::AccountNotFound)
|
||||||
} else if called_accounts[0].owner != system_program::id() {
|
} else if accounts[0].owner != system_program::id() {
|
||||||
error_counters.invalid_account_for_fee += 1;
|
error_counters.invalid_account_for_fee += 1;
|
||||||
Err(TransactionError::InvalidAccountForFee)
|
Err(TransactionError::InvalidAccountForFee)
|
||||||
} else if called_accounts[0].lamports < fee {
|
} else if accounts[0].lamports < fee {
|
||||||
error_counters.insufficient_funds += 1;
|
error_counters.insufficient_funds += 1;
|
||||||
Err(TransactionError::InsufficientFundsForFee)
|
Err(TransactionError::InsufficientFundsForFee)
|
||||||
} else {
|
} else {
|
||||||
called_accounts[0].lamports -= fee;
|
accounts[0].lamports -= fee;
|
||||||
Ok((called_accounts, credits))
|
Ok((accounts, credits, rents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +184,7 @@ impl Accounts {
|
|||||||
accounts_index: &AccountsIndex<AccountInfo>,
|
accounts_index: &AccountsIndex<AccountInfo>,
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> Result<Vec<Vec<(Pubkey, Account)>>> {
|
) -> Result<TransactionLoaders> {
|
||||||
let message = tx.message();
|
let message = tx.message();
|
||||||
message
|
message
|
||||||
.instructions
|
.instructions
|
||||||
@ -203,7 +213,15 @@ impl Accounts {
|
|||||||
lock_results: Vec<Result<()>>,
|
lock_results: Vec<Result<()>>,
|
||||||
hash_queue: &BlockhashQueue,
|
hash_queue: &BlockhashQueue,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> Vec<Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>> {
|
rent_collector: &RentCollector,
|
||||||
|
) -> Vec<
|
||||||
|
Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>,
|
||||||
|
> {
|
||||||
//PERF: hold the lock to scan for the references, but not to clone the accounts
|
//PERF: hold the lock to scan for the references, but not to clone the accounts
|
||||||
//TODO: two locks usually leads to deadlocks, should this be one structure?
|
//TODO: two locks usually leads to deadlocks, should this be one structure?
|
||||||
let accounts_index = self.accounts_db.accounts_index.read().unwrap();
|
let accounts_index = self.accounts_db.accounts_index.read().unwrap();
|
||||||
@ -217,13 +235,14 @@ impl Accounts {
|
|||||||
.ok_or(TransactionError::BlockhashNotFound)?;
|
.ok_or(TransactionError::BlockhashNotFound)?;
|
||||||
|
|
||||||
let fee = fee_calculator.calculate_fee(tx.message());
|
let fee = fee_calculator.calculate_fee(tx.message());
|
||||||
let (accounts, credits) = Self::load_tx_accounts(
|
let (accounts, credits, rents) = Self::load_tx_accounts(
|
||||||
&storage,
|
&storage,
|
||||||
ancestors,
|
ancestors,
|
||||||
&accounts_index,
|
&accounts_index,
|
||||||
tx,
|
tx,
|
||||||
fee,
|
fee,
|
||||||
error_counters,
|
error_counters,
|
||||||
|
rent_collector,
|
||||||
)?;
|
)?;
|
||||||
let loaders = Self::load_loaders(
|
let loaders = Self::load_loaders(
|
||||||
&storage,
|
&storage,
|
||||||
@ -232,7 +251,7 @@ impl Accounts {
|
|||||||
tx,
|
tx,
|
||||||
error_counters,
|
error_counters,
|
||||||
)?;
|
)?;
|
||||||
Ok((accounts, loaders, credits))
|
Ok((accounts, loaders, credits, rents))
|
||||||
}
|
}
|
||||||
(_, Err(e)) => Err(e),
|
(_, Err(e)) => Err(e),
|
||||||
})
|
})
|
||||||
@ -503,7 +522,12 @@ impl Accounts {
|
|||||||
fork: Fork,
|
fork: Fork,
|
||||||
txs: &[Transaction],
|
txs: &[Transaction],
|
||||||
res: &[Result<()>],
|
res: &[Result<()>],
|
||||||
loaded: &mut [Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>],
|
loaded: &mut [Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>],
|
||||||
) {
|
) {
|
||||||
let accounts_to_store = self.collect_accounts_to_store(txs, res, loaded);
|
let accounts_to_store = self.collect_accounts_to_store(txs, res, loaded);
|
||||||
self.accounts_db.store(fork, &accounts_to_store);
|
self.accounts_db.store(fork, &accounts_to_store);
|
||||||
@ -578,7 +602,12 @@ impl Accounts {
|
|||||||
&self,
|
&self,
|
||||||
txs: &'a [Transaction],
|
txs: &'a [Transaction],
|
||||||
res: &'a [Result<()>],
|
res: &'a [Result<()>],
|
||||||
loaded: &'a mut [Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>],
|
loaded: &'a mut [Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>],
|
||||||
) -> Vec<(&'a Pubkey, &'a Account)> {
|
) -> Vec<(&'a Pubkey, &'a Account)> {
|
||||||
let mut accounts = Vec::new();
|
let mut accounts = Vec::new();
|
||||||
for (i, raccs) in loaded.iter_mut().enumerate() {
|
for (i, raccs) in loaded.iter_mut().enumerate() {
|
||||||
@ -651,7 +680,14 @@ mod tests {
|
|||||||
ka: &Vec<(Pubkey, Account)>,
|
ka: &Vec<(Pubkey, Account)>,
|
||||||
fee_calculator: &FeeCalculator,
|
fee_calculator: &FeeCalculator,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> Vec<Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>> {
|
) -> Vec<
|
||||||
|
Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>,
|
||||||
|
> {
|
||||||
let mut hash_queue = BlockhashQueue::new(100);
|
let mut hash_queue = BlockhashQueue::new(100);
|
||||||
hash_queue.register_hash(&tx.message().recent_blockhash, &fee_calculator);
|
hash_queue.register_hash(&tx.message().recent_blockhash, &fee_calculator);
|
||||||
let accounts = Accounts::new(None);
|
let accounts = Accounts::new(None);
|
||||||
@ -660,8 +696,15 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ancestors = vec![(0, 0)].into_iter().collect();
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
||||||
let res =
|
let rent_collector = RentCollector::default();
|
||||||
accounts.load_accounts(&ancestors, &[tx], vec![Ok(())], &hash_queue, error_counters);
|
let res = accounts.load_accounts(
|
||||||
|
&ancestors,
|
||||||
|
&[tx],
|
||||||
|
vec![Ok(())],
|
||||||
|
&hash_queue,
|
||||||
|
error_counters,
|
||||||
|
&rent_collector,
|
||||||
|
);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,7 +712,14 @@ mod tests {
|
|||||||
tx: Transaction,
|
tx: Transaction,
|
||||||
ka: &Vec<(Pubkey, Account)>,
|
ka: &Vec<(Pubkey, Account)>,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> Vec<Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>> {
|
) -> Vec<
|
||||||
|
Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>,
|
||||||
|
> {
|
||||||
let fee_calculator = FeeCalculator::default();
|
let fee_calculator = FeeCalculator::default();
|
||||||
load_accounts_with_fee(tx, ka, &fee_calculator, error_counters)
|
load_accounts_with_fee(tx, ka, &fee_calculator, error_counters)
|
||||||
}
|
}
|
||||||
@ -825,10 +875,12 @@ mod tests {
|
|||||||
let key0 = keypair.pubkey();
|
let key0 = keypair.pubkey();
|
||||||
let key1 = Pubkey::new(&[5u8; 32]);
|
let key1 = Pubkey::new(&[5u8; 32]);
|
||||||
|
|
||||||
let account = Account::new(1, 1, &Pubkey::default());
|
let mut account = Account::new(1, 1, &Pubkey::default());
|
||||||
|
account.rent_epoch = 1;
|
||||||
accounts.push((key0, account));
|
accounts.push((key0, account));
|
||||||
|
|
||||||
let account = Account::new(2, 1, &Pubkey::default());
|
let mut account = Account::new(2, 1, &Pubkey::default());
|
||||||
|
account.rent_epoch = 1;
|
||||||
accounts.push((key1, account));
|
accounts.push((key1, account));
|
||||||
|
|
||||||
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
|
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
|
||||||
@ -845,13 +897,18 @@ mod tests {
|
|||||||
assert_eq!(error_counters.account_not_found, 0);
|
assert_eq!(error_counters.account_not_found, 0);
|
||||||
assert_eq!(loaded_accounts.len(), 1);
|
assert_eq!(loaded_accounts.len(), 1);
|
||||||
match &loaded_accounts[0] {
|
match &loaded_accounts[0] {
|
||||||
Ok((instruction_accounts, instruction_loaders, instruction_credits)) => {
|
Ok((
|
||||||
assert_eq!(instruction_accounts.len(), 2);
|
transaction_accounts,
|
||||||
assert_eq!(instruction_accounts[0], accounts[0].1);
|
transaction_loaders,
|
||||||
assert_eq!(instruction_loaders.len(), 1);
|
transaction_credits,
|
||||||
assert_eq!(instruction_loaders[0].len(), 0);
|
_transaction_rents,
|
||||||
assert_eq!(instruction_credits.len(), 2);
|
)) => {
|
||||||
assert_eq!(instruction_credits, &vec![0, 0]);
|
assert_eq!(transaction_accounts.len(), 2);
|
||||||
|
assert_eq!(transaction_accounts[0], accounts[0].1);
|
||||||
|
assert_eq!(transaction_loaders.len(), 1);
|
||||||
|
assert_eq!(transaction_loaders[0].len(), 0);
|
||||||
|
assert_eq!(transaction_credits.len(), 2);
|
||||||
|
assert_eq!(transaction_credits, &vec![0, 0]);
|
||||||
}
|
}
|
||||||
Err(e) => Err(e).unwrap(),
|
Err(e) => Err(e).unwrap(),
|
||||||
}
|
}
|
||||||
@ -996,21 +1053,25 @@ mod tests {
|
|||||||
let key2 = Pubkey::new(&[6u8; 32]);
|
let key2 = Pubkey::new(&[6u8; 32]);
|
||||||
let key3 = Pubkey::new(&[7u8; 32]);
|
let key3 = Pubkey::new(&[7u8; 32]);
|
||||||
|
|
||||||
let account = Account::new(1, 1, &Pubkey::default());
|
let mut account = Account::new(1, 1, &Pubkey::default());
|
||||||
|
account.rent_epoch = 1;
|
||||||
accounts.push((key0, account));
|
accounts.push((key0, account));
|
||||||
|
|
||||||
let mut account = Account::new(40, 1, &Pubkey::default());
|
let mut account = Account::new(40, 1, &Pubkey::default());
|
||||||
account.executable = true;
|
account.executable = true;
|
||||||
|
account.rent_epoch = 1;
|
||||||
account.owner = native_loader::id();
|
account.owner = native_loader::id();
|
||||||
accounts.push((key1, account));
|
accounts.push((key1, account));
|
||||||
|
|
||||||
let mut account = Account::new(41, 1, &Pubkey::default());
|
let mut account = Account::new(41, 1, &Pubkey::default());
|
||||||
account.executable = true;
|
account.executable = true;
|
||||||
|
account.rent_epoch = 1;
|
||||||
account.owner = key1;
|
account.owner = key1;
|
||||||
accounts.push((key2, account));
|
accounts.push((key2, account));
|
||||||
|
|
||||||
let mut account = Account::new(42, 1, &Pubkey::default());
|
let mut account = Account::new(42, 1, &Pubkey::default());
|
||||||
account.executable = true;
|
account.executable = true;
|
||||||
|
account.rent_epoch = 1;
|
||||||
account.owner = key2;
|
account.owner = key2;
|
||||||
accounts.push((key3, account));
|
accounts.push((key3, account));
|
||||||
|
|
||||||
@ -1031,15 +1092,20 @@ mod tests {
|
|||||||
assert_eq!(error_counters.account_not_found, 0);
|
assert_eq!(error_counters.account_not_found, 0);
|
||||||
assert_eq!(loaded_accounts.len(), 1);
|
assert_eq!(loaded_accounts.len(), 1);
|
||||||
match &loaded_accounts[0] {
|
match &loaded_accounts[0] {
|
||||||
Ok((instruction_accounts, instruction_loaders, instruction_credits)) => {
|
Ok((
|
||||||
assert_eq!(instruction_accounts.len(), 1);
|
transaction_accounts,
|
||||||
assert_eq!(instruction_accounts[0], accounts[0].1);
|
transaction_loaders,
|
||||||
assert_eq!(instruction_loaders.len(), 2);
|
transaction_credits,
|
||||||
assert_eq!(instruction_loaders[0].len(), 1);
|
_transaction_rents,
|
||||||
assert_eq!(instruction_loaders[1].len(), 2);
|
)) => {
|
||||||
assert_eq!(instruction_credits.len(), 1);
|
assert_eq!(transaction_accounts.len(), 1);
|
||||||
assert_eq!(instruction_credits, &vec![0]);
|
assert_eq!(transaction_accounts[0], accounts[0].1);
|
||||||
for loaders in instruction_loaders.iter() {
|
assert_eq!(transaction_loaders.len(), 2);
|
||||||
|
assert_eq!(transaction_loaders[0].len(), 1);
|
||||||
|
assert_eq!(transaction_loaders[1].len(), 2);
|
||||||
|
assert_eq!(transaction_credits.len(), 1);
|
||||||
|
assert_eq!(transaction_credits, &vec![0]);
|
||||||
|
for loaders in transaction_loaders.iter() {
|
||||||
for (i, accounts_subset) in loaders.iter().enumerate() {
|
for (i, accounts_subset) in loaders.iter().enumerate() {
|
||||||
// +1 to skip first not loader account
|
// +1 to skip first not loader account
|
||||||
assert_eq![accounts_subset.1, accounts[i + 1].1];
|
assert_eq![accounts_subset.1, accounts[i + 1].1];
|
||||||
@ -1475,22 +1541,26 @@ mod tests {
|
|||||||
let account1 = Account::new(2, 0, &Pubkey::default());
|
let account1 = Account::new(2, 0, &Pubkey::default());
|
||||||
let account2 = Account::new(3, 0, &Pubkey::default());
|
let account2 = Account::new(3, 0, &Pubkey::default());
|
||||||
|
|
||||||
let instruction_accounts0 = vec![account0, account2.clone()];
|
let transaction_accounts0 = vec![account0, account2.clone()];
|
||||||
let instruction_loaders0 = vec![];
|
let transaction_loaders0 = vec![];
|
||||||
let instruction_credits0 = vec![0, 2];
|
let transaction_credits0 = vec![0, 2];
|
||||||
|
let transaction_rents0 = vec![0, 0];
|
||||||
let loaded0 = Ok((
|
let loaded0 = Ok((
|
||||||
instruction_accounts0,
|
transaction_accounts0,
|
||||||
instruction_loaders0,
|
transaction_loaders0,
|
||||||
instruction_credits0,
|
transaction_credits0,
|
||||||
|
transaction_rents0,
|
||||||
));
|
));
|
||||||
|
|
||||||
let instruction_accounts1 = vec![account1, account2.clone()];
|
let transaction_accounts1 = vec![account1, account2.clone()];
|
||||||
let instruction_loaders1 = vec![];
|
let transaction_loaders1 = vec![];
|
||||||
let instruction_credits1 = vec![0, 3];
|
let transaction_credits1 = vec![0, 3];
|
||||||
|
let transaction_rents1 = vec![0, 0];
|
||||||
let loaded1 = Ok((
|
let loaded1 = Ok((
|
||||||
instruction_accounts1,
|
transaction_accounts1,
|
||||||
instruction_loaders1,
|
transaction_loaders1,
|
||||||
instruction_credits1,
|
transaction_credits1,
|
||||||
|
transaction_rents1,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut loaded = vec![loaded0, loaded1];
|
let mut loaded = vec![loaded0, loaded1];
|
||||||
|
@ -30,7 +30,7 @@ use serde::de::{MapAccess, Visitor};
|
|||||||
use serde::ser::{SerializeMap, Serializer};
|
use serde::ser::{SerializeMap, Serializer};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use solana_measure::measure::Measure;
|
use solana_measure::measure::Measure;
|
||||||
use solana_sdk::account::{Account, LamportCredit};
|
use solana_sdk::account::Account;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -76,9 +76,6 @@ pub struct AccountInfo {
|
|||||||
}
|
}
|
||||||
/// An offset into the AccountsDB::storage vector
|
/// An offset into the AccountsDB::storage vector
|
||||||
pub type AppendVecId = usize;
|
pub type AppendVecId = usize;
|
||||||
pub type InstructionAccounts = Vec<Account>;
|
|
||||||
pub type InstructionCredits = Vec<LamportCredit>;
|
|
||||||
pub type InstructionLoaders = Vec<Vec<(Pubkey, Account)>>;
|
|
||||||
|
|
||||||
// Each fork has a set of storage entries.
|
// Each fork has a set of storage entries.
|
||||||
type ForkStores = HashMap<usize, Arc<AccountStorageEntry>>;
|
type ForkStores = HashMap<usize, Arc<AccountStorageEntry>>;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use bincode::{deserialize_from, serialize_into, serialized_size};
|
use bincode::{deserialize_from, serialize_into, serialized_size};
|
||||||
use memmap::MmapMut;
|
use memmap::MmapMut;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::account::Account;
|
use solana_sdk::{account::Account, pubkey::Pubkey, Epoch};
|
||||||
use solana_sdk::pubkey::Pubkey;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::{create_dir_all, remove_file, OpenOptions};
|
use std::fs::{create_dir_all, remove_file, OpenOptions};
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -38,6 +37,8 @@ pub struct AccountBalance {
|
|||||||
pub owner: Pubkey,
|
pub owner: Pubkey,
|
||||||
/// this account's data contains a loaded program (and is now read-only)
|
/// this account's data contains a loaded program (and is now read-only)
|
||||||
pub executable: bool,
|
pub executable: bool,
|
||||||
|
/// the epoch at which this account will next owe rent
|
||||||
|
pub rent_epoch: Epoch,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// References to Memory Mapped memory
|
/// References to Memory Mapped memory
|
||||||
@ -57,6 +58,7 @@ impl<'a> StoredAccount<'a> {
|
|||||||
lamports: self.balance.lamports,
|
lamports: self.balance.lamports,
|
||||||
owner: self.balance.owner,
|
owner: self.balance.owner,
|
||||||
executable: self.balance.executable,
|
executable: self.balance.executable,
|
||||||
|
rent_epoch: self.balance.rent_epoch,
|
||||||
data: self.data.to_vec(),
|
data: self.data.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,6 +283,7 @@ impl AppendVec {
|
|||||||
lamports: account.lamports,
|
lamports: account.lamports,
|
||||||
owner: account.owner,
|
owner: account.owner,
|
||||||
executable: account.executable,
|
executable: account.executable,
|
||||||
|
rent_epoch: account.rent_epoch,
|
||||||
};
|
};
|
||||||
let balance_ptr = &balance as *const AccountBalance;
|
let balance_ptr = &balance as *const AccountBalance;
|
||||||
let data_len = storage_meta.data_len as usize;
|
let data_len = storage_meta.data_len as usize;
|
||||||
|
@ -2,23 +2,26 @@
|
|||||||
//! programs. It offers a high-level API that signs transactions
|
//! programs. It offers a high-level API that signs transactions
|
||||||
//! on behalf of the caller, and a low-level API for when they have
|
//! on behalf of the caller, and a low-level API for when they have
|
||||||
//! already been signed and verified.
|
//! already been signed and verified.
|
||||||
use crate::accounts::Accounts;
|
use crate::{
|
||||||
use crate::accounts_db::{
|
accounts::{
|
||||||
AccountStorageEntry, AccountsDBSerialize, AppendVecId, ErrorCounters, InstructionAccounts,
|
Accounts, TransactionAccounts, TransactionCredits, TransactionLoaders, TransactionRents,
|
||||||
InstructionCredits, InstructionLoaders,
|
},
|
||||||
|
accounts_db::{AccountStorageEntry, AccountsDBSerialize, AppendVecId, ErrorCounters},
|
||||||
|
accounts_index::Fork,
|
||||||
|
blockhash_queue::BlockhashQueue,
|
||||||
|
epoch_schedule::EpochSchedule,
|
||||||
|
locked_accounts_results::LockedAccountsResults,
|
||||||
|
message_processor::{MessageProcessor, ProcessInstruction},
|
||||||
|
rent_collector::RentCollector,
|
||||||
|
serde_utils::{
|
||||||
|
deserialize_atomicbool, deserialize_atomicusize, serialize_atomicbool,
|
||||||
|
serialize_atomicusize,
|
||||||
|
},
|
||||||
|
stakes::Stakes,
|
||||||
|
status_cache::{SlotDelta, StatusCache},
|
||||||
|
storage_utils,
|
||||||
|
storage_utils::StorageAccounts,
|
||||||
};
|
};
|
||||||
use crate::accounts_index::Fork;
|
|
||||||
use crate::blockhash_queue::BlockhashQueue;
|
|
||||||
use crate::epoch_schedule::EpochSchedule;
|
|
||||||
use crate::locked_accounts_results::LockedAccountsResults;
|
|
||||||
use crate::message_processor::{MessageProcessor, ProcessInstruction};
|
|
||||||
use crate::serde_utils::{
|
|
||||||
deserialize_atomicbool, deserialize_atomicusize, serialize_atomicbool, serialize_atomicusize,
|
|
||||||
};
|
|
||||||
use crate::stakes::Stakes;
|
|
||||||
use crate::status_cache::{SlotDelta, StatusCache};
|
|
||||||
use crate::storage_utils;
|
|
||||||
use crate::storage_utils::StorageAccounts;
|
|
||||||
use bincode::{deserialize_from, serialize_into};
|
use bincode::{deserialize_from, serialize_into};
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use log::*;
|
use log::*;
|
||||||
@ -197,8 +200,11 @@ pub struct Bank {
|
|||||||
/// The number of slots per Storage segment
|
/// The number of slots per Storage segment
|
||||||
slots_per_segment: u64,
|
slots_per_segment: u64,
|
||||||
|
|
||||||
/// Bank fork (i.e. slot, i.e. block)
|
/// Bank slot (i.e. block)
|
||||||
slot: u64,
|
slot: Slot,
|
||||||
|
|
||||||
|
/// Bank epoch
|
||||||
|
epoch: Epoch,
|
||||||
|
|
||||||
/// Bank height in term of banks
|
/// Bank height in term of banks
|
||||||
bank_height: u64,
|
bank_height: u64,
|
||||||
@ -214,6 +220,9 @@ pub struct Bank {
|
|||||||
/// Latest transaction fees for transactions processed by this bank
|
/// Latest transaction fees for transactions processed by this bank
|
||||||
fee_calculator: FeeCalculator,
|
fee_calculator: FeeCalculator,
|
||||||
|
|
||||||
|
/// latest rent collector, knows the epoch
|
||||||
|
rent_collector: RentCollector,
|
||||||
|
|
||||||
/// initialized from genesis
|
/// initialized from genesis
|
||||||
epoch_schedule: EpochSchedule,
|
epoch_schedule: EpochSchedule,
|
||||||
|
|
||||||
@ -282,17 +291,22 @@ impl Bank {
|
|||||||
let src = StatusCacheRc {
|
let src = StatusCacheRc {
|
||||||
status_cache: parent.src.status_cache.clone(),
|
status_cache: parent.src.status_cache.clone(),
|
||||||
};
|
};
|
||||||
|
let epoch_schedule = parent.epoch_schedule;
|
||||||
|
let epoch = epoch_schedule.get_epoch(slot);
|
||||||
|
|
||||||
let mut new = Bank {
|
let mut new = Bank {
|
||||||
rc,
|
rc,
|
||||||
src,
|
src,
|
||||||
|
slot,
|
||||||
|
epoch,
|
||||||
blockhash_queue: RwLock::new(parent.blockhash_queue.read().unwrap().clone()),
|
blockhash_queue: RwLock::new(parent.blockhash_queue.read().unwrap().clone()),
|
||||||
|
|
||||||
// TODO: clean this up, soo much special-case copying...
|
// TODO: clean this up, soo much special-case copying...
|
||||||
ticks_per_slot: parent.ticks_per_slot,
|
ticks_per_slot: parent.ticks_per_slot,
|
||||||
slots_per_segment: parent.slots_per_segment,
|
slots_per_segment: parent.slots_per_segment,
|
||||||
slots_per_year: parent.slots_per_year,
|
slots_per_year: parent.slots_per_year,
|
||||||
epoch_schedule: parent.epoch_schedule,
|
epoch_schedule,
|
||||||
slot,
|
rent_collector: parent.rent_collector.clone_with_epoch(epoch),
|
||||||
max_tick_height: (slot + 1) * parent.ticks_per_slot - 1,
|
max_tick_height: (slot + 1) * parent.ticks_per_slot - 1,
|
||||||
bank_height: parent.bank_height + 1,
|
bank_height: parent.bank_height + 1,
|
||||||
fee_calculator: FeeCalculator::new_derived(
|
fee_calculator: FeeCalculator::new_derived(
|
||||||
@ -300,15 +314,15 @@ impl Bank {
|
|||||||
parent.signature_count(),
|
parent.signature_count(),
|
||||||
),
|
),
|
||||||
capitalization: AtomicUsize::new(parent.capitalization() as usize),
|
capitalization: AtomicUsize::new(parent.capitalization() as usize),
|
||||||
inflation: parent.inflation.clone(),
|
inflation: parent.inflation,
|
||||||
transaction_count: AtomicUsize::new(parent.transaction_count() as usize),
|
transaction_count: AtomicUsize::new(parent.transaction_count() as usize),
|
||||||
stakes: RwLock::new(parent.stakes.read().unwrap().clone_with_epoch(0)),
|
stakes: RwLock::new(parent.stakes.read().unwrap().clone_with_epoch(epoch)),
|
||||||
|
epoch_stakes: parent.epoch_stakes.clone(),
|
||||||
storage_accounts: RwLock::new(parent.storage_accounts.read().unwrap().clone()),
|
storage_accounts: RwLock::new(parent.storage_accounts.read().unwrap().clone()),
|
||||||
parent_hash: parent.hash(),
|
parent_hash: parent.hash(),
|
||||||
collector_id: *collector_id,
|
collector_id: *collector_id,
|
||||||
collector_fees: AtomicUsize::new(0),
|
collector_fees: AtomicUsize::new(0),
|
||||||
ancestors: HashMap::new(),
|
ancestors: HashMap::new(),
|
||||||
epoch_stakes: HashMap::new(),
|
|
||||||
hash: RwLock::new(Hash::default()),
|
hash: RwLock::new(Hash::default()),
|
||||||
is_delta: AtomicBool::new(false),
|
is_delta: AtomicBool::new(false),
|
||||||
tick_height: AtomicUsize::new(parent.tick_height.load(Ordering::Relaxed)),
|
tick_height: AtomicUsize::new(parent.tick_height.load(Ordering::Relaxed)),
|
||||||
@ -316,28 +330,21 @@ impl Bank {
|
|||||||
message_processor: MessageProcessor::default(),
|
message_processor: MessageProcessor::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
|
||||||
*new.stakes.write().unwrap() =
|
|
||||||
parent.stakes.read().unwrap().clone_with_epoch(new.epoch());
|
|
||||||
}
|
|
||||||
|
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
"bank-new_from_parent-heights",
|
"bank-new_from_parent-heights",
|
||||||
("slot_height", slot, i64),
|
("slot_height", slot, i64),
|
||||||
("bank_height", new.bank_height, i64)
|
("bank_height", new.bank_height, i64)
|
||||||
);
|
);
|
||||||
|
|
||||||
new.epoch_stakes = {
|
let stakers_epoch = epoch_schedule.get_stakers_epoch(slot);
|
||||||
let mut epoch_stakes = parent.epoch_stakes.clone();
|
// update epoch_stakes cache
|
||||||
let epoch = new.get_stakers_epoch(new.slot);
|
// if my parent didn't populate for this staker's epoch, we've
|
||||||
// update epoch_vote_states cache
|
// crossed a boundary
|
||||||
// if my parent didn't populate for this epoch, we've
|
if new.epoch_stakes.get(&stakers_epoch).is_none() {
|
||||||
// crossed a boundary
|
new.epoch_stakes
|
||||||
if epoch_stakes.get(&epoch).is_none() {
|
.insert(stakers_epoch, new.stakes.read().unwrap().clone());
|
||||||
epoch_stakes.insert(epoch, new.stakes.read().unwrap().clone());
|
}
|
||||||
}
|
|
||||||
epoch_stakes
|
|
||||||
};
|
|
||||||
new.ancestors.insert(new.slot(), 0);
|
new.ancestors.insert(new.slot(), 0);
|
||||||
new.parents().iter().enumerate().for_each(|(i, p)| {
|
new.parents().iter().enumerate().for_each(|(i, p)| {
|
||||||
new.ancestors.insert(p.slot(), i + 1);
|
new.ancestors.insert(p.slot(), i + 1);
|
||||||
@ -375,7 +382,7 @@ impl Bank {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn epoch(&self) -> u64 {
|
pub fn epoch(&self) -> u64 {
|
||||||
self.epoch_schedule.get_epoch(self.slot)
|
self.epoch
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn freeze_lock(&self) -> RwLockReadGuard<Hash> {
|
pub fn freeze_lock(&self) -> RwLockReadGuard<Hash> {
|
||||||
@ -611,7 +618,7 @@ impl Bank {
|
|||||||
genesis_block.epoch_warmup,
|
genesis_block.epoch_warmup,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.inflation = genesis_block.inflation.clone();
|
self.inflation = genesis_block.inflation;
|
||||||
|
|
||||||
// Add additional native programs specified in the genesis block
|
// Add additional native programs specified in the genesis block
|
||||||
for (name, program_id) in &genesis_block.native_instruction_processors {
|
for (name, program_id) in &genesis_block.native_instruction_processors {
|
||||||
@ -781,13 +788,21 @@ impl Bank {
|
|||||||
txs: &[Transaction],
|
txs: &[Transaction],
|
||||||
results: Vec<Result<()>>,
|
results: Vec<Result<()>>,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> Vec<Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>> {
|
) -> Vec<
|
||||||
|
Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>,
|
||||||
|
> {
|
||||||
self.rc.accounts.load_accounts(
|
self.rc.accounts.load_accounts(
|
||||||
&self.ancestors,
|
&self.ancestors,
|
||||||
txs,
|
txs,
|
||||||
results,
|
results,
|
||||||
&self.blockhash_queue.read().unwrap(),
|
&self.blockhash_queue.read().unwrap(),
|
||||||
error_counters,
|
error_counters,
|
||||||
|
&self.rent_collector,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn check_refs(
|
fn check_refs(
|
||||||
@ -932,7 +947,14 @@ impl Bank {
|
|||||||
lock_results: &LockedAccountsResults,
|
lock_results: &LockedAccountsResults,
|
||||||
max_age: usize,
|
max_age: usize,
|
||||||
) -> (
|
) -> (
|
||||||
Vec<Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>>,
|
Vec<
|
||||||
|
Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
Vec<Result<()>>,
|
Vec<Result<()>>,
|
||||||
Vec<usize>,
|
Vec<usize>,
|
||||||
usize,
|
usize,
|
||||||
@ -970,7 +992,7 @@ impl Bank {
|
|||||||
.zip(txs.iter())
|
.zip(txs.iter())
|
||||||
.map(|(accs, tx)| match accs {
|
.map(|(accs, tx)| match accs {
|
||||||
Err(e) => Err(e.clone()),
|
Err(e) => Err(e.clone()),
|
||||||
Ok((ref mut accounts, ref mut loaders, ref mut credits)) => {
|
Ok((ref mut accounts, ref mut loaders, ref mut credits, ref mut _rents)) => {
|
||||||
signature_count += tx.message().header.num_required_signatures as usize;
|
signature_count += tx.message().header.num_required_signatures as usize;
|
||||||
self.message_processor
|
self.message_processor
|
||||||
.process_message(tx.message(), loaders, accounts, credits)
|
.process_message(tx.message(), loaders, accounts, credits)
|
||||||
@ -1061,9 +1083,10 @@ impl Bank {
|
|||||||
&self,
|
&self,
|
||||||
txs: &[Transaction],
|
txs: &[Transaction],
|
||||||
loaded_accounts: &mut [Result<(
|
loaded_accounts: &mut [Result<(
|
||||||
InstructionAccounts,
|
TransactionAccounts,
|
||||||
InstructionLoaders,
|
TransactionLoaders,
|
||||||
InstructionCredits,
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
)>],
|
)>],
|
||||||
executed: &[Result<()>],
|
executed: &[Result<()>],
|
||||||
tx_count: usize,
|
tx_count: usize,
|
||||||
@ -1332,7 +1355,12 @@ impl Bank {
|
|||||||
&self,
|
&self,
|
||||||
txs: &[Transaction],
|
txs: &[Transaction],
|
||||||
res: &[Result<()>],
|
res: &[Result<()>],
|
||||||
loaded: &[Result<(InstructionAccounts, InstructionLoaders, InstructionCredits)>],
|
loaded: &[Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionCredits,
|
||||||
|
TransactionRents,
|
||||||
|
)>],
|
||||||
) {
|
) {
|
||||||
for (i, raccs) in loaded.iter().enumerate() {
|
for (i, raccs) in loaded.iter().enumerate() {
|
||||||
if res[i].is_err() || raccs.is_err() {
|
if res[i].is_err() || raccs.is_err() {
|
||||||
|
@ -12,6 +12,7 @@ pub mod loader_utils;
|
|||||||
pub mod locked_accounts_results;
|
pub mod locked_accounts_results;
|
||||||
pub mod message_processor;
|
pub mod message_processor;
|
||||||
mod native_loader;
|
mod native_loader;
|
||||||
|
pub mod rent_collector;
|
||||||
mod serde_utils;
|
mod serde_utils;
|
||||||
pub mod stakes;
|
pub mod stakes;
|
||||||
pub mod status_cache;
|
pub mod status_cache;
|
||||||
|
65
runtime/src/rent_collector.rs
Normal file
65
runtime/src/rent_collector.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//! calculate and collect rent from Accounts
|
||||||
|
use crate::epoch_schedule::EpochSchedule;
|
||||||
|
use solana_sdk::{account::Account, rent::Rent, timing::Epoch};
|
||||||
|
|
||||||
|
#[derive(Default, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct RentCollector {
|
||||||
|
pub epoch: Epoch,
|
||||||
|
pub epoch_schedule: EpochSchedule,
|
||||||
|
pub slots_per_year: f64,
|
||||||
|
pub rent: Rent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RentCollector {
|
||||||
|
pub fn new(
|
||||||
|
epoch: Epoch,
|
||||||
|
epoch_schedule: &EpochSchedule,
|
||||||
|
slots_per_year: f64,
|
||||||
|
rent: &Rent,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
epoch,
|
||||||
|
epoch_schedule: *epoch_schedule,
|
||||||
|
slots_per_year,
|
||||||
|
rent: *rent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clone_with_epoch(&self, epoch: Epoch) -> Self {
|
||||||
|
Self {
|
||||||
|
epoch,
|
||||||
|
..self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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))
|
||||||
|
} else {
|
||||||
|
let slots_elapsed: u64 = (account.rent_epoch..=self.epoch)
|
||||||
|
.map(|epoch| self.epoch_schedule.get_slots_in_epoch(epoch + 1))
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
let (rent_due, exempt) = self.rent.due(
|
||||||
|
account.lamports,
|
||||||
|
account.data.len(),
|
||||||
|
slots_elapsed as f64 / self.slots_per_year,
|
||||||
|
);
|
||||||
|
|
||||||
|
if exempt || rent_due != 0 {
|
||||||
|
if account.lamports > rent_due {
|
||||||
|
account.rent_epoch = self.epoch + 1;
|
||||||
|
account.lamports -= rent_due;
|
||||||
|
Some((account, rent_due))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// maybe collect rent later, leave account alone
|
||||||
|
Some((account, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -247,10 +247,8 @@ mod tests {
|
|||||||
|
|
||||||
let populated_key = Pubkey::new_rand();
|
let populated_key = Pubkey::new_rand();
|
||||||
let mut populated_account = Account {
|
let mut populated_account = Account {
|
||||||
lamports: 0,
|
|
||||||
data: vec![0, 1, 2, 3],
|
data: vec![0, 1, 2, 3],
|
||||||
owner: Pubkey::default(),
|
..Account::default()
|
||||||
executable: false,
|
|
||||||
};
|
};
|
||||||
let unchanged_account = populated_account.clone();
|
let unchanged_account = populated_account.clone();
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::pubkey::Pubkey;
|
use crate::pubkey::Pubkey;
|
||||||
|
use crate::Epoch;
|
||||||
use std::{cmp, fmt};
|
use std::{cmp, fmt};
|
||||||
|
|
||||||
/// An Account with data that is stored on chain
|
/// An Account with data that is stored on chain
|
||||||
@ -13,6 +14,8 @@ pub struct Account {
|
|||||||
pub owner: Pubkey,
|
pub owner: Pubkey,
|
||||||
/// this account's data contains a loaded program (and is now read-only)
|
/// this account's data contains a loaded program (and is now read-only)
|
||||||
pub executable: bool,
|
pub executable: bool,
|
||||||
|
/// the epoch at which this account will next owe rent
|
||||||
|
pub rent_epoch: Epoch,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Account {
|
impl fmt::Debug for Account {
|
||||||
@ -25,11 +28,12 @@ impl fmt::Debug for Account {
|
|||||||
};
|
};
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Account {{ lamports: {} data.len: {} owner: {} executable: {}{} }}",
|
"Account {{ lamports: {} data.len: {} owner: {} executable: {} rent_epoch: {}{} }}",
|
||||||
self.lamports,
|
self.lamports,
|
||||||
self.data.len(),
|
self.data.len(),
|
||||||
self.owner,
|
self.owner,
|
||||||
self.executable,
|
self.executable,
|
||||||
|
self.rent_epoch,
|
||||||
data_str,
|
data_str,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -42,7 +46,7 @@ impl Account {
|
|||||||
lamports,
|
lamports,
|
||||||
data: vec![0u8; space],
|
data: vec![0u8; space],
|
||||||
owner: *owner,
|
owner: *owner,
|
||||||
executable: false,
|
..Account::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +60,7 @@ impl Account {
|
|||||||
lamports,
|
lamports,
|
||||||
data,
|
data,
|
||||||
owner: *owner,
|
owner: *owner,
|
||||||
executable: false,
|
..Account::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ pub struct FeeCalculator {
|
|||||||
pub const DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE: u64 = 42;
|
pub const DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE: u64 = 42;
|
||||||
pub const DEFAULT_TARGET_SIGNATURES_PER_SLOT: usize =
|
pub const DEFAULT_TARGET_SIGNATURES_PER_SLOT: usize =
|
||||||
710_000 * DEFAULT_TICKS_PER_SLOT as usize / DEFAULT_TICKS_PER_SECOND as usize;
|
710_000 * DEFAULT_TICKS_PER_SLOT as usize / DEFAULT_TICKS_PER_SECOND as usize;
|
||||||
pub const DEFAULT_BURN_PERCENT: u8 = 127;
|
pub const DEFAULT_BURN_PERCENT: u8 = ((50usize * std::u8::MAX as usize) / 100usize) as u8;
|
||||||
|
|
||||||
impl Default for FeeCalculator {
|
impl Default for FeeCalculator {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! configuration for network inflation
|
//! configuration for network inflation
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
|
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug, Copy)]
|
||||||
pub struct Inflation {
|
pub struct Inflation {
|
||||||
/// Initial inflation percentage, from time=0
|
/// Initial inflation percentage, from time=0
|
||||||
pub initial: f64,
|
pub initial: f64,
|
||||||
|
@ -28,3 +28,6 @@ pub mod transport;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
pub type Epoch = u64;
|
||||||
|
pub type Slot = u64;
|
||||||
|
@ -14,5 +14,6 @@ pub fn create_loadable_account(name: &str) -> Account {
|
|||||||
owner: id(),
|
owner: id(),
|
||||||
data: name.as_bytes().to_vec(),
|
data: name.as_bytes().to_vec(),
|
||||||
executable: true,
|
executable: true,
|
||||||
|
rent_epoch: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
//! configuration for network rent
|
//! configuration for network rent
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
|
#[derive(Serialize, Deserialize, PartialEq, Clone, Copy, Debug)]
|
||||||
pub struct Rent {
|
pub struct Rent {
|
||||||
/// Rental rate
|
/// Rental rate
|
||||||
pub lamports_per_byte_year: u64,
|
pub lamports_per_byte_year: u64,
|
||||||
|
|
||||||
/// exemption threshold, in years
|
/// exemption threshold, in years
|
||||||
pub exemption_threshold: f64,
|
pub exemption_threshold: f64,
|
||||||
|
|
||||||
|
// What portion of collected rent are to be destroyed, percentage-wise
|
||||||
|
pub burn_percent: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// default rental rate in lamports/byte-year, based on:
|
/// default rental rate in lamports/byte-year, based on:
|
||||||
@ -14,16 +17,20 @@ pub struct Rent {
|
|||||||
/// $1 per Sol
|
/// $1 per Sol
|
||||||
/// $0.01 per megabyte day
|
/// $0.01 per megabyte day
|
||||||
/// $3.65 per megabyte year
|
/// $3.65 per megabyte year
|
||||||
pub const DEFAULT_LAMPORTS_PER_BYTE_YEAR: u64 = 17_179_869_184 / 100 * 365 / (1024 * 1024);
|
pub const DEFAULT_LAMPORTS_PER_BYTE_YEAR: u64 = 0; //17_179_869_184 / 100 * 365 / (1024 * 1024);
|
||||||
|
|
||||||
/// default amount of time (in years) the balance has to include rent for
|
/// default amount of time (in years) the balance has to include rent for
|
||||||
pub const DEFAULT_EXEMPTION_THRESHOLD: f64 = 2.0;
|
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;
|
||||||
|
|
||||||
impl Default for Rent {
|
impl Default for Rent {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
lamports_per_byte_year: DEFAULT_LAMPORTS_PER_BYTE_YEAR,
|
lamports_per_byte_year: DEFAULT_LAMPORTS_PER_BYTE_YEAR,
|
||||||
exemption_threshold: DEFAULT_EXEMPTION_THRESHOLD,
|
exemption_threshold: DEFAULT_EXEMPTION_THRESHOLD,
|
||||||
|
burn_percent: DEFAULT_BURN_PERCENT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,12 +48,14 @@ impl Rent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// rent due on account's data_len with balance
|
/// rent due on account's data_len with balance
|
||||||
pub fn due(&self, balance: u64, data_len: usize, years_elapsed: f64) -> u64 {
|
pub fn due(&self, balance: u64, data_len: usize, years_elapsed: f64) -> (u64, bool) {
|
||||||
if self.is_exempt(balance, data_len) {
|
if self.is_exempt(balance, data_len) {
|
||||||
0
|
(0, true)
|
||||||
} else {
|
} else {
|
||||||
let bytes = data_len as u64;
|
(
|
||||||
((self.lamports_per_byte_year * bytes) as f64 * years_elapsed) as u64
|
((self.lamports_per_byte_year * data_len as u64) as f64 * years_elapsed) as u64,
|
||||||
|
false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,14 +68,63 @@ mod tests {
|
|||||||
fn test_due() {
|
fn test_due() {
|
||||||
let rent = Rent::default();
|
let rent = Rent::default();
|
||||||
|
|
||||||
assert_eq!(rent.due(0, 1, 1.0), DEFAULT_LAMPORTS_PER_BYTE_YEAR);
|
assert_eq!(
|
||||||
|
rent.due(0, 1, 1.0),
|
||||||
|
(
|
||||||
|
DEFAULT_LAMPORTS_PER_BYTE_YEAR,
|
||||||
|
DEFAULT_LAMPORTS_PER_BYTE_YEAR == 0
|
||||||
|
)
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
rent.due(
|
rent.due(
|
||||||
DEFAULT_LAMPORTS_PER_BYTE_YEAR * DEFAULT_EXEMPTION_THRESHOLD as u64,
|
DEFAULT_LAMPORTS_PER_BYTE_YEAR * DEFAULT_EXEMPTION_THRESHOLD as u64,
|
||||||
1,
|
1,
|
||||||
1.0
|
1.0
|
||||||
),
|
),
|
||||||
0
|
(0, true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uncomment me and make my eprintlns macros
|
||||||
|
// #[test]
|
||||||
|
// fn test_rent_model() {
|
||||||
|
// use crate::timing::*;
|
||||||
|
//
|
||||||
|
// const SECONDS_PER_YEAR: f64 = (365.25 * 24.0 * 60.0 * 60.0);
|
||||||
|
// const SLOTS_PER_YEAR: f64 =
|
||||||
|
// SECONDS_PER_YEAR / (DEFAULT_TICKS_PER_SLOT as f64 / DEFAULT_TICKS_PER_SECOND as f64);
|
||||||
|
//
|
||||||
|
// let rent = Rent::default();
|
||||||
|
//
|
||||||
|
// eprintln();
|
||||||
|
// // lamports charged per byte per slot at $1/MByear, rent per slot is zero
|
||||||
|
// eprintln(
|
||||||
|
// "{} lamports per byte-slot, rent.due(): {}",
|
||||||
|
// (1.0 / SLOTS_PER_YEAR) * DEFAULT_LAMPORTS_PER_BYTE_YEAR as f64,
|
||||||
|
// rent.due(0, 1, 1.0 / SLOTS_PER_YEAR).0,
|
||||||
|
// );
|
||||||
|
// // lamports charged per byte per _epoch_ starts to have some significant digits
|
||||||
|
// eprintln(
|
||||||
|
// "{} lamports per byte-epoch, rent.due(): {}",
|
||||||
|
// (1.0 / SLOTS_PER_YEAR)
|
||||||
|
// * (DEFAULT_LAMPORTS_PER_BYTE_YEAR * DEFAULT_SLOTS_PER_EPOCH) as f64,
|
||||||
|
// rent.due(
|
||||||
|
// 0,
|
||||||
|
// 1,
|
||||||
|
// (1.0 / SLOTS_PER_YEAR) * DEFAULT_SLOTS_PER_EPOCH as f64
|
||||||
|
// )
|
||||||
|
// .0,
|
||||||
|
// );
|
||||||
|
// // have a look at what a large-ish sysvar would cost, were it a real account...
|
||||||
|
// eprintln(
|
||||||
|
// "stake_history: {}kB == {} lamports per epoch",
|
||||||
|
// crate::sysvar::stake_history::StakeHistory::size_of() / 1024,
|
||||||
|
// rent.due(
|
||||||
|
// 0,
|
||||||
|
// crate::sysvar::stake_history::StakeHistory::size_of(),
|
||||||
|
// (1.0 / SLOTS_PER_YEAR) * DEFAULT_SLOTS_PER_EPOCH as f64
|
||||||
|
// )
|
||||||
|
// .0,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user