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:
parent
0947ec59c9
commit
ec48c58df1
|
@ -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::token_program;
|
||||||
use solana_sdk::transaction::Transaction;
|
use solana_sdk::transaction::Transaction;
|
||||||
use solana_sdk::vote_program::{self, VoteState};
|
use solana_sdk::vote_program::{self, VoteState};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -103,9 +104,6 @@ pub struct Bank {
|
||||||
// A number of slots before slot_index 0. Used to generate the current
|
// A number of slots before slot_index 0. Used to generate the current
|
||||||
// epoch's leader schedule.
|
// epoch's leader schedule.
|
||||||
leader_schedule_slot_offset: u64,
|
leader_schedule_slot_offset: u64,
|
||||||
|
|
||||||
/// Slot leader
|
|
||||||
leader: Pubkey,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bank {
|
impl Bank {
|
||||||
|
@ -117,7 +115,7 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new bank that points to an immutable checkpoint of another 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();
|
let mut bank = Self::default();
|
||||||
bank.last_id_queue = RwLock::new(parent.last_id_queue.read().unwrap().clone());
|
bank.last_id_queue = RwLock::new(parent.last_id_queue.read().unwrap().clone());
|
||||||
bank.ticks_per_slot = parent.ticks_per_slot;
|
bank.ticks_per_slot = parent.ticks_per_slot;
|
||||||
|
@ -128,7 +126,6 @@ impl Bank {
|
||||||
if *parent.hash.read().unwrap() == Hash::default() {
|
if *parent.hash.read().unwrap() == Hash::default() {
|
||||||
*parent.hash.write().unwrap() = parent.hash_internal_state();
|
*parent.hash.write().unwrap() = parent.hash_internal_state();
|
||||||
}
|
}
|
||||||
bank.leader = *leader;
|
|
||||||
bank
|
bank
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +472,7 @@ impl Bank {
|
||||||
_ => res.clone(),
|
_ => res.clone(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.deposit(&self.leader, fees);
|
self.deposit(&self.slot_leader(), fees);
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,13 +633,22 @@ impl Bank {
|
||||||
where
|
where
|
||||||
F: Fn(&VoteState) -> bool,
|
F: Fn(&VoteState) -> bool,
|
||||||
{
|
{
|
||||||
self.accounts
|
let parents = self.parents();
|
||||||
.accounts_db
|
let mut accounts = vec![&self.accounts];
|
||||||
.read()
|
accounts.extend(parents.iter().map(|b| &b.accounts));
|
||||||
.unwrap()
|
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
|
.accounts
|
||||||
.values()
|
.iter()
|
||||||
.filter_map(|account| {
|
.filter_map(|(key, account)| {
|
||||||
|
if exists.contains(key) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
exists.insert(key.clone());
|
||||||
if vote_program::check_id(&account.owner) {
|
if vote_program::check_id(&account.owner) {
|
||||||
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
|
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
|
||||||
if cond(&vote_state) {
|
if cond(&vote_state) {
|
||||||
|
@ -651,6 +657,10 @@ impl Bank {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
vote_states
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -676,8 +686,8 @@ impl Bank {
|
||||||
|
|
||||||
/// Return the checkpointed bank that should be used to generate a leader schedule.
|
/// Return the checkpointed bank that should be used to generate a leader schedule.
|
||||||
/// Return None if a sufficiently old bank checkpoint doesn't exist.
|
/// Return None if a sufficiently old bank checkpoint doesn't exist.
|
||||||
fn leader_schedule_bank(&self) -> Option<Arc<Bank>> {
|
fn leader_schedule_bank(&self, epoch_height: u64) -> Option<Arc<Bank>> {
|
||||||
let epoch_slot_height = self.slot_height() - self.slot_index();
|
let epoch_slot_height = epoch_height * self.slots_per_epoch();
|
||||||
let expected = epoch_slot_height.saturating_sub(self.leader_schedule_slot_offset);
|
let expected = epoch_slot_height.saturating_sub(self.leader_schedule_slot_offset);
|
||||||
self.parents()
|
self.parents()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -685,8 +695,8 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the leader schedule for the current epoch.
|
/// Return the leader schedule for the current epoch.
|
||||||
fn leader_schedule(&self) -> LeaderSchedule {
|
fn leader_schedule(&self, epoch_height: u64) -> LeaderSchedule {
|
||||||
match self.leader_schedule_bank() {
|
match self.leader_schedule_bank(epoch_height) {
|
||||||
None => LeaderSchedule::new_with_bank(self),
|
None => LeaderSchedule::new_with_bank(self),
|
||||||
Some(bank) => LeaderSchedule::new_with_bank(&bank),
|
Some(bank) => LeaderSchedule::new_with_bank(&bank),
|
||||||
}
|
}
|
||||||
|
@ -694,7 +704,8 @@ impl Bank {
|
||||||
|
|
||||||
/// Return the leader for the current slot.
|
/// Return the leader for the current slot.
|
||||||
pub fn slot_leader(&self) -> Pubkey {
|
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.
|
/// Return the number of ticks since genesis.
|
||||||
|
@ -998,9 +1009,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bank_tx_fee() {
|
fn test_bank_tx_fee() {
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(100);
|
let leader = Keypair::new().pubkey();
|
||||||
let mut bank = Bank::new(&genesis_block);
|
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, leader, 2);
|
||||||
bank.leader = Pubkey::default();
|
let bank = Bank::new(&genesis_block);
|
||||||
|
|
||||||
let key1 = Keypair::new();
|
let key1 = Keypair::new();
|
||||||
let key2 = Keypair::new();
|
let key2 = Keypair::new();
|
||||||
|
@ -1012,25 +1023,25 @@ mod tests {
|
||||||
genesis_block.last_id(),
|
genesis_block.last_id(),
|
||||||
3,
|
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.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(&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);
|
let tx = SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 1);
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
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(&key1.pubkey()), 0);
|
||||||
assert_eq!(bank.get_balance(&key2.pubkey()), 1);
|
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]
|
#[test]
|
||||||
fn test_filter_program_errors_and_collect_fee() {
|
fn test_filter_program_errors_and_collect_fee() {
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(100);
|
let leader = Keypair::new().pubkey();
|
||||||
let mut bank = Bank::new(&genesis_block);
|
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, leader, 2);
|
||||||
bank.leader = Pubkey::default();
|
let bank = Bank::new(&genesis_block);
|
||||||
|
|
||||||
let key = Keypair::new();
|
let key = Keypair::new();
|
||||||
let tx1 =
|
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);
|
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[0], Ok(()));
|
||||||
assert_eq!(results[1], Ok(()));
|
assert_eq!(results[1], Ok(()));
|
||||||
}
|
}
|
||||||
|
@ -1127,17 +1138,19 @@ mod tests {
|
||||||
fn test_leader_schedule_bank() {
|
fn test_leader_schedule_bank() {
|
||||||
let (genesis_block, _) = GenesisBlock::new(5);
|
let (genesis_block, _) = GenesisBlock::new(5);
|
||||||
let bank = Bank::new(&genesis_block);
|
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();
|
let ticks_per_offset = bank.leader_schedule_slot_offset * bank.ticks_per_slot();
|
||||||
register_ticks(&bank, ticks_per_offset);
|
register_ticks(&bank, ticks_per_offset);
|
||||||
assert_eq!(bank.slot_height(), bank.leader_schedule_slot_offset);
|
assert_eq!(bank.slot_height(), bank.leader_schedule_slot_offset);
|
||||||
|
|
||||||
let slot_height = bank.slots_per_epoch() - 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!(
|
assert_eq!(
|
||||||
bank.leader_schedule_bank().unwrap().slot_height(),
|
bank.leader_schedule_bank(bank.epoch_height())
|
||||||
|
.unwrap()
|
||||||
|
.slot_height(),
|
||||||
slot_height
|
slot_height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1259,7 +1272,7 @@ mod tests {
|
||||||
let (genesis_block, _) = GenesisBlock::new(1);
|
let (genesis_block, _) = GenesisBlock::new(1);
|
||||||
let parent = Arc::new(Bank::new(&genesis_block));
|
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));
|
assert!(Arc::ptr_eq(&bank.parents()[0], &parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1278,7 +1291,7 @@ mod tests {
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(parent.process_transaction(&tx), Ok(()));
|
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!(
|
assert_eq!(
|
||||||
bank.process_transaction(&tx),
|
bank.process_transaction(&tx),
|
||||||
Err(BankError::DuplicateSignature)
|
Err(BankError::DuplicateSignature)
|
||||||
|
@ -1301,7 +1314,7 @@ mod tests {
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(parent.process_transaction(&tx), Ok(()));
|
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);
|
let tx = SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 0);
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
assert_eq!(parent.get_signature_status(&tx.signatures[0]), None);
|
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());
|
assert_eq!(bank0.hash_internal_state(), bank1.hash_internal_state());
|
||||||
|
|
||||||
// Checkpointing should not change its 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());
|
assert_eq!(bank0.hash_internal_state(), bank2.hash_internal_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1353,7 +1366,7 @@ mod tests {
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(parent.process_transaction(&tx_move_mint_to_1), Ok(()));
|
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 =
|
let tx_move_1_to_2 =
|
||||||
SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 0);
|
SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 0);
|
||||||
assert_eq!(bank.process_transaction(&tx_move_1_to_2), Ok(()));
|
assert_eq!(bank.process_transaction(&tx_move_1_to_2), Ok(()));
|
||||||
|
|
|
@ -38,7 +38,6 @@ impl BankForks {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_sdk::hash::Hash;
|
use solana_sdk::hash::Hash;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bank_forks_root() {
|
fn test_bank_forks_root() {
|
||||||
|
@ -52,7 +51,7 @@ mod tests {
|
||||||
fn test_bank_forks_parent() {
|
fn test_bank_forks_parent() {
|
||||||
let bank = Bank::default();
|
let bank = Bank::default();
|
||||||
let mut bank_forks = BankForks::new(0, bank);
|
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());
|
child_bank.register_tick(&Hash::default());
|
||||||
let child_bank_id = 1;
|
let child_bank_id = 1;
|
||||||
bank_forks.insert(child_bank_id, child_bank);
|
bank_forks.insert(child_bank_id, child_bank);
|
||||||
|
|
|
@ -221,12 +221,7 @@ pub fn process_blocktree(
|
||||||
_ => {
|
_ => {
|
||||||
// This is a fork point, create a new child bank for each fork
|
// This is a fork point, create a new child bank for each fork
|
||||||
pending_slots.extend(meta.next_slots.iter().map(|next_slot| {
|
pending_slots.extend(meta.next_slots.iter().map(|next_slot| {
|
||||||
let leader = leader_scheduler
|
let child_bank = Bank::new_from_parent(&bank);
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.get_leader_for_slot(*next_slot)
|
|
||||||
.unwrap();
|
|
||||||
let child_bank = Bank::new_from_parent(&bank, &leader);
|
|
||||||
trace!("Add child bank for slot={}", next_slot);
|
trace!("Add child bank for slot={}", next_slot);
|
||||||
let child_bank_id = *next_slot;
|
let child_bank_id = *next_slot;
|
||||||
bank_forks.insert(child_bank_id, child_bank);
|
bank_forks.insert(child_bank_id, child_bank);
|
||||||
|
|
|
@ -211,7 +211,7 @@ impl ReplayStage {
|
||||||
// state
|
// state
|
||||||
to_leader_sender
|
to_leader_sender
|
||||||
.send(TvuRotationInfo {
|
.send(TvuRotationInfo {
|
||||||
bank: Bank::new_from_parent(&bank, &leader_id),
|
bank: Bank::new_from_parent(&bank),
|
||||||
last_entry_id: *last_entry_id.read().unwrap(),
|
last_entry_id: *last_entry_id.read().unwrap(),
|
||||||
slot,
|
slot,
|
||||||
leader_id,
|
leader_id,
|
||||||
|
@ -331,7 +331,7 @@ impl ReplayStage {
|
||||||
if my_id == leader_id || my_id == last_leader_id {
|
if my_id == leader_id || my_id == last_leader_id {
|
||||||
to_leader_sender
|
to_leader_sender
|
||||||
.send(TvuRotationInfo {
|
.send(TvuRotationInfo {
|
||||||
bank: Bank::new_from_parent(&bank, &leader_id),
|
bank: Bank::new_from_parent(&bank),
|
||||||
last_entry_id: *last_entry_id.read().unwrap(),
|
last_entry_id: *last_entry_id.read().unwrap(),
|
||||||
slot: next_slot,
|
slot: next_slot,
|
||||||
leader_id,
|
leader_id,
|
||||||
|
|
|
@ -168,7 +168,6 @@ mod tests {
|
||||||
use solana_sdk::budget_program;
|
use solana_sdk::budget_program;
|
||||||
use solana_sdk::budget_transaction::BudgetTransaction;
|
use solana_sdk::budget_transaction::BudgetTransaction;
|
||||||
use solana_sdk::genesis_block::GenesisBlock;
|
use solana_sdk::genesis_block::GenesisBlock;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||||
use solana_sdk::system_transaction::SystemTransaction;
|
use solana_sdk::system_transaction::SystemTransaction;
|
||||||
use solana_sdk::transaction::Transaction;
|
use solana_sdk::transaction::Transaction;
|
||||||
|
@ -185,7 +184,7 @@ mod tests {
|
||||||
subscriptions.notify_subscribers(&bank);
|
subscriptions.notify_subscribers(&bank);
|
||||||
|
|
||||||
// Simulate a block boundary
|
// 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> {
|
fn create_session() -> Arc<Session> {
|
||||||
|
|
Loading…
Reference in New Issue