Award tx fees to validators in new leader schedule

Also, generalize the leader_schedule functions a bit to allow for
prev_slot_leader and next_slot_leader, should they be needed.
This commit is contained in:
Greg Fitzgerald 2019-02-24 21:17:47 -07:00 committed by Grimes
parent 0947ec59c9
commit ec48c58df1
5 changed files with 65 additions and 59 deletions

View File

@ -28,6 +28,7 @@ use solana_sdk::timing::{duration_as_us, MAX_ENTRY_IDS, NUM_TICKS_PER_SECOND};
use solana_sdk::token_program;
use solana_sdk::transaction::Transaction;
use solana_sdk::vote_program::{self, VoteState};
use std::collections::HashSet;
use std::result;
use std::sync::{Arc, RwLock};
use std::time::Instant;
@ -103,9 +104,6 @@ pub struct Bank {
// A number of slots before slot_index 0. Used to generate the current
// epoch's leader schedule.
leader_schedule_slot_offset: u64,
/// Slot leader
leader: Pubkey,
}
impl Bank {
@ -117,7 +115,7 @@ impl Bank {
}
/// Create a new bank that points to an immutable checkpoint of another bank.
pub fn new_from_parent(parent: &Arc<Bank>, leader: &Pubkey) -> Self {
pub fn new_from_parent(parent: &Arc<Bank>) -> Self {
let mut bank = Self::default();
bank.last_id_queue = RwLock::new(parent.last_id_queue.read().unwrap().clone());
bank.ticks_per_slot = parent.ticks_per_slot;
@ -128,7 +126,6 @@ impl Bank {
if *parent.hash.read().unwrap() == Hash::default() {
*parent.hash.write().unwrap() = parent.hash_internal_state();
}
bank.leader = *leader;
bank
}
@ -475,7 +472,7 @@ impl Bank {
_ => res.clone(),
})
.collect();
self.deposit(&self.leader, fees);
self.deposit(&self.slot_leader(), fees);
results
}
@ -636,21 +633,34 @@ impl Bank {
where
F: Fn(&VoteState) -> bool,
{
self.accounts
.accounts_db
.read()
.unwrap()
.accounts
.values()
.filter_map(|account| {
if vote_program::check_id(&account.owner) {
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
if cond(&vote_state) {
return Some(vote_state);
let parents = self.parents();
let mut accounts = vec![&self.accounts];
accounts.extend(parents.iter().map(|b| &b.accounts));
let mut exists = HashSet::new();
accounts
.iter()
.flat_map(|account| {
let accounts_db = account.accounts_db.read().unwrap();
let vote_states: Vec<_> = accounts_db
.accounts
.iter()
.filter_map(|(key, account)| {
if exists.contains(key) {
None
} else {
exists.insert(key.clone());
if vote_program::check_id(&account.owner) {
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
if cond(&vote_state) {
return Some(vote_state);
}
}
}
None
}
}
}
None
})
.collect();
vote_states
})
.collect()
}
@ -676,8 +686,8 @@ impl Bank {
/// Return the checkpointed bank that should be used to generate a leader schedule.
/// Return None if a sufficiently old bank checkpoint doesn't exist.
fn leader_schedule_bank(&self) -> Option<Arc<Bank>> {
let epoch_slot_height = self.slot_height() - self.slot_index();
fn leader_schedule_bank(&self, epoch_height: u64) -> Option<Arc<Bank>> {
let epoch_slot_height = epoch_height * self.slots_per_epoch();
let expected = epoch_slot_height.saturating_sub(self.leader_schedule_slot_offset);
self.parents()
.into_iter()
@ -685,8 +695,8 @@ impl Bank {
}
/// Return the leader schedule for the current epoch.
fn leader_schedule(&self) -> LeaderSchedule {
match self.leader_schedule_bank() {
fn leader_schedule(&self, epoch_height: u64) -> LeaderSchedule {
match self.leader_schedule_bank(epoch_height) {
None => LeaderSchedule::new_with_bank(self),
Some(bank) => LeaderSchedule::new_with_bank(&bank),
}
@ -694,7 +704,8 @@ impl Bank {
/// Return the leader for the current slot.
pub fn slot_leader(&self) -> Pubkey {
self.leader_schedule()[self.slot_index() as usize]
let leader_schedule = self.leader_schedule(self.epoch_height());
leader_schedule[self.slot_index() as usize]
}
/// Return the number of ticks since genesis.
@ -998,9 +1009,9 @@ mod tests {
#[test]
fn test_bank_tx_fee() {
let (genesis_block, mint_keypair) = GenesisBlock::new(100);
let mut bank = Bank::new(&genesis_block);
bank.leader = Pubkey::default();
let leader = Keypair::new().pubkey();
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, leader, 2);
let bank = Bank::new(&genesis_block);
let key1 = Keypair::new();
let key2 = Keypair::new();
@ -1012,25 +1023,25 @@ mod tests {
genesis_block.last_id(),
3,
);
let initial_balance = bank.get_balance(&bank.leader);
let initial_balance = bank.get_balance(&leader);
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert_eq!(bank.get_balance(&bank.leader), initial_balance + 3);
assert_eq!(bank.get_balance(&leader), initial_balance + 3);
assert_eq!(bank.get_balance(&key1.pubkey()), 2);
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 2 - 3);
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 4 - 3);
let tx = SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 1);
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert_eq!(bank.get_balance(&bank.leader), initial_balance + 4);
assert_eq!(bank.get_balance(&leader), initial_balance + 4);
assert_eq!(bank.get_balance(&key1.pubkey()), 0);
assert_eq!(bank.get_balance(&key2.pubkey()), 1);
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 2 - 3);
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 4 - 3);
}
#[test]
fn test_filter_program_errors_and_collect_fee() {
let (genesis_block, mint_keypair) = GenesisBlock::new(100);
let mut bank = Bank::new(&genesis_block);
bank.leader = Pubkey::default();
let leader = Keypair::new().pubkey();
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, leader, 2);
let bank = Bank::new(&genesis_block);
let key = Keypair::new();
let tx1 =
@ -1046,9 +1057,9 @@ mod tests {
)),
];
let initial_balance = bank.get_balance(&bank.leader);
let initial_balance = bank.get_balance(&leader);
let results = bank.filter_program_errors_and_collect_fee(&vec![tx1, tx2], &results);
assert_eq!(bank.get_balance(&bank.leader), initial_balance + 3 + 1);
assert_eq!(bank.get_balance(&leader), initial_balance + 3 + 1);
assert_eq!(results[0], Ok(()));
assert_eq!(results[1], Ok(()));
}
@ -1127,17 +1138,19 @@ mod tests {
fn test_leader_schedule_bank() {
let (genesis_block, _) = GenesisBlock::new(5);
let bank = Bank::new(&genesis_block);
assert!(bank.leader_schedule_bank().is_none());
assert!(bank.leader_schedule_bank(bank.epoch_height()).is_none());
let bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default());
let bank = Bank::new_from_parent(&Arc::new(bank));
let ticks_per_offset = bank.leader_schedule_slot_offset * bank.ticks_per_slot();
register_ticks(&bank, ticks_per_offset);
assert_eq!(bank.slot_height(), bank.leader_schedule_slot_offset);
let slot_height = bank.slots_per_epoch() - bank.leader_schedule_slot_offset;
let bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default());
let bank = Bank::new_from_parent(&Arc::new(bank));
assert_eq!(
bank.leader_schedule_bank().unwrap().slot_height(),
bank.leader_schedule_bank(bank.epoch_height())
.unwrap()
.slot_height(),
slot_height
);
}
@ -1259,7 +1272,7 @@ mod tests {
let (genesis_block, _) = GenesisBlock::new(1);
let parent = Arc::new(Bank::new(&genesis_block));
let bank = Bank::new_from_parent(&parent, &Pubkey::default());
let bank = Bank::new_from_parent(&parent);
assert!(Arc::ptr_eq(&bank.parents()[0], &parent));
}
@ -1278,7 +1291,7 @@ mod tests {
0,
);
assert_eq!(parent.process_transaction(&tx), Ok(()));
let bank = Bank::new_from_parent(&parent, &Pubkey::default());
let bank = Bank::new_from_parent(&parent);
assert_eq!(
bank.process_transaction(&tx),
Err(BankError::DuplicateSignature)
@ -1301,7 +1314,7 @@ mod tests {
0,
);
assert_eq!(parent.process_transaction(&tx), Ok(()));
let bank = Bank::new_from_parent(&parent, &Pubkey::default());
let bank = Bank::new_from_parent(&parent);
let tx = SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 0);
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert_eq!(parent.get_signature_status(&tx.signatures[0]), None);
@ -1326,7 +1339,7 @@ mod tests {
assert_eq!(bank0.hash_internal_state(), bank1.hash_internal_state());
// Checkpointing should not change its state
let bank2 = Bank::new_from_parent(&Arc::new(bank1), &Pubkey::default());
let bank2 = Bank::new_from_parent(&Arc::new(bank1));
assert_eq!(bank0.hash_internal_state(), bank2.hash_internal_state());
}
@ -1353,7 +1366,7 @@ mod tests {
0,
);
assert_eq!(parent.process_transaction(&tx_move_mint_to_1), Ok(()));
let mut bank = Bank::new_from_parent(&parent, &Pubkey::default());
let mut bank = Bank::new_from_parent(&parent);
let tx_move_1_to_2 =
SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 0);
assert_eq!(bank.process_transaction(&tx_move_1_to_2), Ok(()));

View File

@ -38,7 +38,6 @@ impl BankForks {
mod tests {
use super::*;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
#[test]
fn test_bank_forks_root() {
@ -52,7 +51,7 @@ mod tests {
fn test_bank_forks_parent() {
let bank = Bank::default();
let mut bank_forks = BankForks::new(0, bank);
let child_bank = Bank::new_from_parent(&bank_forks.working_bank(), &Pubkey::default());
let child_bank = Bank::new_from_parent(&bank_forks.working_bank());
child_bank.register_tick(&Hash::default());
let child_bank_id = 1;
bank_forks.insert(child_bank_id, child_bank);

View File

@ -221,12 +221,7 @@ pub fn process_blocktree(
_ => {
// This is a fork point, create a new child bank for each fork
pending_slots.extend(meta.next_slots.iter().map(|next_slot| {
let leader = leader_scheduler
.read()
.unwrap()
.get_leader_for_slot(*next_slot)
.unwrap();
let child_bank = Bank::new_from_parent(&bank, &leader);
let child_bank = Bank::new_from_parent(&bank);
trace!("Add child bank for slot={}", next_slot);
let child_bank_id = *next_slot;
bank_forks.insert(child_bank_id, child_bank);

View File

@ -211,7 +211,7 @@ impl ReplayStage {
// state
to_leader_sender
.send(TvuRotationInfo {
bank: Bank::new_from_parent(&bank, &leader_id),
bank: Bank::new_from_parent(&bank),
last_entry_id: *last_entry_id.read().unwrap(),
slot,
leader_id,
@ -331,7 +331,7 @@ impl ReplayStage {
if my_id == leader_id || my_id == last_leader_id {
to_leader_sender
.send(TvuRotationInfo {
bank: Bank::new_from_parent(&bank, &leader_id),
bank: Bank::new_from_parent(&bank),
last_entry_id: *last_entry_id.read().unwrap(),
slot: next_slot,
leader_id,

View File

@ -168,7 +168,6 @@ mod tests {
use solana_sdk::budget_program;
use solana_sdk::budget_transaction::BudgetTransaction;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::transaction::Transaction;
@ -185,7 +184,7 @@ mod tests {
subscriptions.notify_subscribers(&bank);
// Simulate a block boundary
Ok(Arc::new(Bank::new_from_parent(&bank, &Pubkey::default())))
Ok(Arc::new(Bank::new_from_parent(&bank)))
}
fn create_session() -> Arc<Session> {