moved fee collection code to runtime
This commit is contained in:
parent
c142a82ae0
commit
5c9777970d
|
@ -130,7 +130,7 @@ fn main() {
|
||||||
last_id = entry.id;
|
last_id = entry.id;
|
||||||
num_entries += 1;
|
num_entries += 1;
|
||||||
|
|
||||||
if let Err(e) = blocktree_processor::process_entry(&bank, &entry).0 {
|
if let Err(e) = blocktree_processor::process_entry(&bank, &entry) {
|
||||||
eprintln!("verify failed at entry[{}], err: {:?}", i + 2, e);
|
eprintln!("verify failed at entry[{}], err: {:?}", i + 2, e);
|
||||||
if !matches.is_present("continue") {
|
if !matches.is_present("continue") {
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
@ -104,6 +104,9 @@ 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 Default for Bank {
|
impl Default for Bank {
|
||||||
|
@ -117,6 +120,7 @@ impl Default for Bank {
|
||||||
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
|
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
|
||||||
slots_per_epoch: DEFAULT_SLOTS_PER_EPOCH,
|
slots_per_epoch: DEFAULT_SLOTS_PER_EPOCH,
|
||||||
leader_schedule_slot_offset: DEFAULT_SLOTS_PER_EPOCH,
|
leader_schedule_slot_offset: DEFAULT_SLOTS_PER_EPOCH,
|
||||||
|
leader: Pubkey::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +134,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>) -> Self {
|
pub fn new_from_parent(parent: &Arc<Bank>, leader: &Pubkey) -> 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;
|
||||||
|
@ -141,6 +145,7 @@ 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.clone();
|
||||||
bank
|
bank
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +504,7 @@ impl Bank {
|
||||||
txs: &[Transaction],
|
txs: &[Transaction],
|
||||||
loaded_accounts: &[Result<(InstructionAccounts, InstructionLoaders)>],
|
loaded_accounts: &[Result<(InstructionAccounts, InstructionLoaders)>],
|
||||||
executed: &[Result<()>],
|
executed: &[Result<()>],
|
||||||
) {
|
) -> Vec<Result<()>> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
self.accounts
|
self.accounts
|
||||||
.store_accounts(self.is_root(), txs, executed, loaded_accounts);
|
.store_accounts(self.is_root(), txs, executed, loaded_accounts);
|
||||||
|
@ -512,6 +517,27 @@ impl Bank {
|
||||||
txs.len(),
|
txs.len(),
|
||||||
);
|
);
|
||||||
self.update_transaction_statuses(txs, &executed);
|
self.update_transaction_statuses(txs, &executed);
|
||||||
|
|
||||||
|
let mut fees = 0;
|
||||||
|
let results = txs
|
||||||
|
.iter()
|
||||||
|
.zip(executed.into_iter())
|
||||||
|
.map(|(tx, res)| match *res {
|
||||||
|
Err(BankError::ProgramError(_, _)) => {
|
||||||
|
// Charge the transaction fee even in case of ProgramError
|
||||||
|
self.withdraw(&tx.account_keys[0], tx.fee)?;
|
||||||
|
fees += tx.fee;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Ok(()) => {
|
||||||
|
fees += tx.fee;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => res.clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
self.deposit(&self.leader, fees);
|
||||||
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a batch of transactions.
|
/// Process a batch of transactions.
|
||||||
|
@ -525,8 +551,7 @@ impl Bank {
|
||||||
let (loaded_accounts, executed) =
|
let (loaded_accounts, executed) =
|
||||||
self.load_and_execute_transactions(txs, lock_results, max_age);
|
self.load_and_execute_transactions(txs, lock_results, max_age);
|
||||||
|
|
||||||
self.commit_transactions(txs, &loaded_accounts, &executed);
|
self.commit_transactions(txs, &loaded_accounts, &executed)
|
||||||
executed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -579,10 +604,19 @@ impl Bank {
|
||||||
parents
|
parents
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn withdraw(&self, pubkey: &Pubkey, tokens: u64) {
|
pub fn withdraw(&self, pubkey: &Pubkey, tokens: u64) -> Result<()> {
|
||||||
let mut account = self.get_account(pubkey).unwrap_or_default();
|
match self.get_account(pubkey) {
|
||||||
account.tokens -= tokens;
|
Some(mut account) => {
|
||||||
self.accounts.store_slow(true, pubkey, &account);
|
if tokens > account.tokens {
|
||||||
|
return Err(BankError::InsufficientFundsForFee);
|
||||||
|
}
|
||||||
|
|
||||||
|
account.tokens -= tokens;
|
||||||
|
self.accounts.store_slow(true, pubkey, &account);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(BankError::AccountNotFound),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deposit(&self, pubkey: &Pubkey, tokens: u64) {
|
pub fn deposit(&self, pubkey: &Pubkey, tokens: u64) {
|
||||||
|
@ -952,6 +986,77 @@ mod tests {
|
||||||
assert_eq!(bank.get_balance(&pubkey), 500);
|
assert_eq!(bank.get_balance(&pubkey), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bank_deposit() {
|
||||||
|
let (genesis_block, _mint_keypair) = GenesisBlock::new(100);
|
||||||
|
let bank = Bank::new(&genesis_block);
|
||||||
|
|
||||||
|
// Test new account
|
||||||
|
let key = Keypair::new();
|
||||||
|
bank.deposit(&key.pubkey(), 10);
|
||||||
|
assert_eq!(bank.get_balance(&key.pubkey()), 10);
|
||||||
|
|
||||||
|
// Existing account
|
||||||
|
bank.deposit(&key.pubkey(), 3);
|
||||||
|
assert_eq!(bank.get_balance(&key.pubkey()), 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bank_withdraw() {
|
||||||
|
let (genesis_block, _mint_keypair) = GenesisBlock::new(100);
|
||||||
|
let bank = Bank::new(&genesis_block);
|
||||||
|
|
||||||
|
// Test no account
|
||||||
|
let key = Keypair::new();
|
||||||
|
assert_eq!(
|
||||||
|
bank.withdraw(&key.pubkey(), 10),
|
||||||
|
Err(BankError::AccountNotFound)
|
||||||
|
);
|
||||||
|
|
||||||
|
bank.deposit(&key.pubkey(), 3);
|
||||||
|
assert_eq!(bank.get_balance(&key.pubkey()), 3);
|
||||||
|
|
||||||
|
// Low balance
|
||||||
|
assert_eq!(
|
||||||
|
bank.withdraw(&key.pubkey(), 10),
|
||||||
|
Err(BankError::InsufficientFundsForFee)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enough balance
|
||||||
|
assert_eq!(bank.withdraw(&key.pubkey(), 2), Ok(()));
|
||||||
|
assert_eq!(bank.get_balance(&key.pubkey()), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
|
||||||
|
let tx = SystemTransaction::new_move(
|
||||||
|
&mint_keypair,
|
||||||
|
key1.pubkey(),
|
||||||
|
2,
|
||||||
|
genesis_block.last_id(),
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
let initial_balance = bank.get_balance(&bank.leader);
|
||||||
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
|
assert_eq!(bank.get_balance(&bank.leader), initial_balance + 3);
|
||||||
|
assert_eq!(bank.get_balance(&key1.pubkey()), 2);
|
||||||
|
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 2 - 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(&key1.pubkey()), 0);
|
||||||
|
assert_eq!(bank.get_balance(&key2.pubkey()), 1);
|
||||||
|
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 2 - 3);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_debits_before_credits() {
|
fn test_debits_before_credits() {
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(2);
|
let (genesis_block, mint_keypair) = GenesisBlock::new(2);
|
||||||
|
@ -1028,13 +1133,13 @@ mod tests {
|
||||||
let bank = Bank::new(&genesis_block);
|
let bank = Bank::new(&genesis_block);
|
||||||
assert!(bank.leader_schedule_bank().is_none());
|
assert!(bank.leader_schedule_bank().is_none());
|
||||||
|
|
||||||
let bank = Bank::new_from_parent(&Arc::new(bank));
|
let bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default());
|
||||||
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));
|
let bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.leader_schedule_bank().unwrap().slot_height(),
|
bank.leader_schedule_bank().unwrap().slot_height(),
|
||||||
slot_height
|
slot_height
|
||||||
|
@ -1164,7 +1269,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);
|
let bank = Bank::new_from_parent(&parent, &Pubkey::default());
|
||||||
assert!(Arc::ptr_eq(&bank.parents()[0], &parent));
|
assert!(Arc::ptr_eq(&bank.parents()[0], &parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,7 +1288,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);
|
let bank = Bank::new_from_parent(&parent, &Pubkey::default());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.process_transaction(&tx),
|
bank.process_transaction(&tx),
|
||||||
Err(BankError::DuplicateSignature)
|
Err(BankError::DuplicateSignature)
|
||||||
|
@ -1206,7 +1311,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);
|
let bank = Bank::new_from_parent(&parent, &Pubkey::default());
|
||||||
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);
|
||||||
|
@ -1231,7 +1336,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));
|
let bank2 = Bank::new_from_parent(&Arc::new(bank1), &Pubkey::default());
|
||||||
assert_eq!(bank0.hash_internal_state(), bank2.hash_internal_state());
|
assert_eq!(bank0.hash_internal_state(), bank2.hash_internal_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,7 +1363,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);
|
let mut bank = Bank::new_from_parent(&parent, &Pubkey::default());
|
||||||
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,6 +38,7 @@ 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() {
|
||||||
|
@ -51,7 +52,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());
|
let child_bank = Bank::new_from_parent(&bank_forks.working_bank(), &Pubkey::default());
|
||||||
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);
|
||||||
|
|
|
@ -13,29 +13,20 @@ use solana_sdk::timing::MAX_ENTRY_IDS;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
pub fn process_entry(bank: &Bank, entry: &Entry) -> (Result<()>, u64) {
|
pub fn process_entry(bank: &Bank, entry: &Entry) -> Result<()> {
|
||||||
if !entry.is_tick() {
|
if !entry.is_tick() {
|
||||||
let old_results = bank.process_transactions(&entry.transactions);
|
for result in bank.process_transactions(&entry.transactions) {
|
||||||
let fee = entry
|
match result {
|
||||||
.transactions
|
// Entries that result in a ProgramError are still valid and are written in the
|
||||||
.iter()
|
// ledger so map them to an ok return value
|
||||||
.zip(&old_results)
|
Err(BankError::ProgramError(_, _)) => Ok(()),
|
||||||
.map(|(tx, res)| match res {
|
_ => result,
|
||||||
Err(BankError::ProgramError(_, _)) => {
|
}?;
|
||||||
// Charge the transaction fee in case of ProgramError
|
}
|
||||||
bank.withdraw(&tx.account_keys[0], tx.fee);
|
|
||||||
tx.fee
|
|
||||||
}
|
|
||||||
Ok(()) => tx.fee,
|
|
||||||
_ => 0,
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
let results = ignore_program_errors(old_results);
|
|
||||||
(first_err(&results), fee)
|
|
||||||
} else {
|
} else {
|
||||||
bank.register_tick(&entry.id);
|
bank.register_tick(&entry.id);
|
||||||
(Ok(()), 0)
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_err(results: &[Result<()>]) -> Result<()> {
|
fn first_err(results: &[Result<()>]) -> Result<()> {
|
||||||
|
@ -61,9 +52,9 @@ fn ignore_program_errors(results: Vec<Result<()>>) -> Vec<Result<()>> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn par_execute_entries(bank: &Bank, entries: &[(&Entry, Vec<Result<()>>)]) -> (Result<()>, u64) {
|
fn par_execute_entries(bank: &Bank, entries: &[(&Entry, Vec<Result<()>>)]) -> Result<()> {
|
||||||
inc_new_counter_info!("bank-par_execute_entries-count", entries.len());
|
inc_new_counter_info!("bank-par_execute_entries-count", entries.len());
|
||||||
let results_fees: Vec<(Result<()>, u64)> = entries
|
let results: Vec<Result<()>> = entries
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|(e, lock_results)| {
|
.map(|(e, lock_results)| {
|
||||||
let old_results = bank.load_execute_and_commit_transactions(
|
let old_results = bank.load_execute_and_commit_transactions(
|
||||||
|
@ -71,29 +62,13 @@ fn par_execute_entries(bank: &Bank, entries: &[(&Entry, Vec<Result<()>>)]) -> (R
|
||||||
lock_results.to_vec(),
|
lock_results.to_vec(),
|
||||||
MAX_ENTRY_IDS,
|
MAX_ENTRY_IDS,
|
||||||
);
|
);
|
||||||
let fee = e
|
|
||||||
.transactions
|
|
||||||
.iter()
|
|
||||||
.zip(&old_results)
|
|
||||||
.map(|(tx, res)| match res {
|
|
||||||
Err(BankError::ProgramError(_, _)) => {
|
|
||||||
// Charge the transaction fee in case of ProgramError
|
|
||||||
bank.withdraw(&tx.account_keys[0], tx.fee);
|
|
||||||
tx.fee
|
|
||||||
}
|
|
||||||
Ok(()) => tx.fee,
|
|
||||||
_ => 0,
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
let results = ignore_program_errors(old_results);
|
let results = ignore_program_errors(old_results);
|
||||||
bank.unlock_accounts(&e.transactions, &results);
|
bank.unlock_accounts(&e.transactions, &results);
|
||||||
(first_err(&results), fee)
|
first_err(&results)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let fee = results_fees.iter().map(|(_, fee)| fee).sum();
|
first_err(&results)
|
||||||
let results: Vec<Result<()>> = results_fees.into_iter().map(|(res, _)| res).collect();
|
|
||||||
(first_err(&results[..]), fee)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// process entries in parallel
|
/// process entries in parallel
|
||||||
|
@ -105,18 +80,13 @@ fn par_process_entries_with_scheduler(
|
||||||
bank: &Bank,
|
bank: &Bank,
|
||||||
entries: &[Entry],
|
entries: &[Entry],
|
||||||
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
||||||
) -> (Result<()>, u64) {
|
) -> Result<()> {
|
||||||
// accumulator for entries that can be processed in parallel
|
// accumulator for entries that can be processed in parallel
|
||||||
let mut mt_group = vec![];
|
let mut mt_group = vec![];
|
||||||
let mut fees = 0;
|
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
if entry.is_tick() {
|
if entry.is_tick() {
|
||||||
// if its a tick, execute the group and register the tick
|
// if its a tick, execute the group and register the tick
|
||||||
let (res, fee) = par_execute_entries(bank, &mt_group);
|
par_execute_entries(bank, &mt_group)?;
|
||||||
fees += fee;
|
|
||||||
if res.is_err() {
|
|
||||||
return (res, fees);
|
|
||||||
}
|
|
||||||
bank.register_tick(&entry.id);
|
bank.register_tick(&entry.id);
|
||||||
leader_scheduler
|
leader_scheduler
|
||||||
.write()
|
.write()
|
||||||
|
@ -130,11 +100,7 @@ fn par_process_entries_with_scheduler(
|
||||||
// if any of the locks error out
|
// if any of the locks error out
|
||||||
// execute the current group
|
// execute the current group
|
||||||
if first_err(&lock_results).is_err() {
|
if first_err(&lock_results).is_err() {
|
||||||
let (res, fee) = par_execute_entries(bank, &mt_group);
|
par_execute_entries(bank, &mt_group)?;
|
||||||
fees += fee;
|
|
||||||
if res.is_err() {
|
|
||||||
return (res, fees);
|
|
||||||
}
|
|
||||||
mt_group = vec![];
|
mt_group = vec![];
|
||||||
//reset the lock and push the entry
|
//reset the lock and push the entry
|
||||||
bank.unlock_accounts(&entry.transactions, &lock_results);
|
bank.unlock_accounts(&entry.transactions, &lock_results);
|
||||||
|
@ -145,9 +111,8 @@ fn par_process_entries_with_scheduler(
|
||||||
mt_group.push((entry, lock_results));
|
mt_group.push((entry, lock_results));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (res, fee) = par_execute_entries(bank, &mt_group);
|
par_execute_entries(bank, &mt_group)?;
|
||||||
fees += fee;
|
Ok(())
|
||||||
(res, fees)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process an ordered list of entries.
|
/// Process an ordered list of entries.
|
||||||
|
@ -155,7 +120,7 @@ pub fn process_entries(
|
||||||
bank: &Bank,
|
bank: &Bank,
|
||||||
entries: &[Entry],
|
entries: &[Entry],
|
||||||
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
||||||
) -> (Result<()>, u64) {
|
) -> Result<()> {
|
||||||
par_process_entries_with_scheduler(bank, entries, leader_scheduler)
|
par_process_entries_with_scheduler(bank, entries, leader_scheduler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,21 +132,11 @@ fn process_block(
|
||||||
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
let (res, fee) = process_entry(bank, entry);
|
process_entry(bank, entry)?;
|
||||||
if let Some(leader) = leader_scheduler
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.get_leader_for_tick(bank.tick_height())
|
|
||||||
{
|
|
||||||
// Credit the accumulated fees to the current leader and reset the fee to 0
|
|
||||||
bank.deposit(&leader, fee);
|
|
||||||
}
|
|
||||||
|
|
||||||
if entry.is_tick() {
|
if entry.is_tick() {
|
||||||
let mut leader_scheduler = leader_scheduler.write().unwrap();
|
let mut leader_scheduler = leader_scheduler.write().unwrap();
|
||||||
leader_scheduler.update_tick_height(bank.tick_height(), bank);
|
leader_scheduler.update_tick_height(bank.tick_height(), bank);
|
||||||
}
|
}
|
||||||
res?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -290,7 +245,12 @@ 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 child_bank = Bank::new_from_parent(&bank);
|
let leader = leader_scheduler
|
||||||
|
.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);
|
||||||
|
@ -486,7 +446,7 @@ mod tests {
|
||||||
assert_ne!(updated_results, expected_results);
|
assert_ne!(updated_results, expected_results);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn par_process_entries(bank: &Bank, entries: &[Entry]) -> (Result<()>, u64) {
|
fn par_process_entries(bank: &Bank, entries: &[Entry]) -> Result<()> {
|
||||||
let leader_scheduler = Arc::new(RwLock::new(LeaderScheduler::default()));
|
let leader_scheduler = Arc::new(RwLock::new(LeaderScheduler::default()));
|
||||||
par_process_entries_with_scheduler(bank, entries, &leader_scheduler)
|
par_process_entries_with_scheduler(bank, entries, &leader_scheduler)
|
||||||
}
|
}
|
||||||
|
@ -506,7 +466,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Now ensure the TX is accepted despite pointing to the ID of an empty entry.
|
// Now ensure the TX is accepted despite pointing to the ID of an empty entry.
|
||||||
par_process_entries(&bank, &[entry]).0.unwrap();
|
par_process_entries(&bank, &[entry]).unwrap();
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,7 +552,7 @@ mod tests {
|
||||||
|
|
||||||
// ensure bank can process a tick
|
// ensure bank can process a tick
|
||||||
let tick = next_entry(&genesis_block.last_id(), 1, vec![]);
|
let tick = next_entry(&genesis_block.last_id(), 1, vec![]);
|
||||||
assert_eq!(par_process_entries(&bank, &[tick.clone()]).0, Ok(()));
|
assert_eq!(par_process_entries(&bank, &[tick.clone()]), Ok(()));
|
||||||
assert_eq!(bank.last_id(), tick.id);
|
assert_eq!(bank.last_id(), tick.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,7 +572,7 @@ mod tests {
|
||||||
let tx =
|
let tx =
|
||||||
SystemTransaction::new_account(&mint_keypair, keypair2.pubkey(), 2, bank.last_id(), 0);
|
SystemTransaction::new_account(&mint_keypair, keypair2.pubkey(), 2, bank.last_id(), 0);
|
||||||
let entry_2 = next_entry(&entry_1.id, 1, vec![tx]);
|
let entry_2 = next_entry(&entry_1.id, 1, vec![tx]);
|
||||||
assert_eq!(par_process_entries(&bank, &[entry_1, entry_2]).0, Ok(()));
|
assert_eq!(par_process_entries(&bank, &[entry_1, entry_2]), Ok(()));
|
||||||
assert_eq!(bank.get_balance(&keypair1.pubkey()), 2);
|
assert_eq!(bank.get_balance(&keypair1.pubkey()), 2);
|
||||||
assert_eq!(bank.get_balance(&keypair2.pubkey()), 2);
|
assert_eq!(bank.get_balance(&keypair2.pubkey()), 2);
|
||||||
assert_eq!(bank.last_id(), last_id);
|
assert_eq!(bank.last_id(), last_id);
|
||||||
|
@ -665,7 +625,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
par_process_entries(&bank, &[entry_1_to_mint, entry_2_to_3_mint_to_1]).0,
|
par_process_entries(&bank, &[entry_1_to_mint, entry_2_to_3_mint_to_1]),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -685,21 +645,19 @@ mod tests {
|
||||||
|
|
||||||
//load accounts
|
//load accounts
|
||||||
let tx =
|
let tx =
|
||||||
SystemTransaction::new_account(&mint_keypair, keypair1.pubkey(), 4, bank.last_id(), 0);
|
SystemTransaction::new_account(&mint_keypair, keypair1.pubkey(), 1, bank.last_id(), 0);
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
let tx =
|
let tx =
|
||||||
SystemTransaction::new_account(&mint_keypair, keypair2.pubkey(), 4, bank.last_id(), 0);
|
SystemTransaction::new_account(&mint_keypair, keypair2.pubkey(), 1, bank.last_id(), 0);
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
|
|
||||||
// ensure bank can process 2 entries that do not have a common account and no tick is registered
|
// ensure bank can process 2 entries that do not have a common account and no tick is registered
|
||||||
let last_id = bank.last_id();
|
let last_id = bank.last_id();
|
||||||
let tx = SystemTransaction::new_account(&keypair1, keypair3.pubkey(), 1, bank.last_id(), 1);
|
let tx = SystemTransaction::new_account(&keypair1, keypair3.pubkey(), 1, bank.last_id(), 0);
|
||||||
let entry_1 = next_entry(&last_id, 1, vec![tx]);
|
let entry_1 = next_entry(&last_id, 1, vec![tx]);
|
||||||
let tx = SystemTransaction::new_account(&keypair2, keypair4.pubkey(), 1, bank.last_id(), 3);
|
let tx = SystemTransaction::new_account(&keypair2, keypair4.pubkey(), 1, bank.last_id(), 0);
|
||||||
let entry_2 = next_entry(&entry_1.id, 1, vec![tx]);
|
let entry_2 = next_entry(&entry_1.id, 1, vec![tx]);
|
||||||
let (res, fee) = par_process_entries(&bank, &[entry_1, entry_2]);
|
assert_eq!(par_process_entries(&bank, &[entry_1, entry_2]), Ok(()));
|
||||||
assert_eq!(res, Ok(()));
|
|
||||||
assert_eq!(fee, 4);
|
|
||||||
assert_eq!(bank.get_balance(&keypair3.pubkey()), 1);
|
assert_eq!(bank.get_balance(&keypair3.pubkey()), 1);
|
||||||
assert_eq!(bank.get_balance(&keypair4.pubkey()), 1);
|
assert_eq!(bank.get_balance(&keypair4.pubkey()), 1);
|
||||||
assert_eq!(bank.last_id(), last_id);
|
assert_eq!(bank.last_id(), last_id);
|
||||||
|
@ -716,32 +674,33 @@ mod tests {
|
||||||
|
|
||||||
//load accounts
|
//load accounts
|
||||||
let tx =
|
let tx =
|
||||||
SystemTransaction::new_account(&mint_keypair, keypair1.pubkey(), 6, bank.last_id(), 0);
|
SystemTransaction::new_account(&mint_keypair, keypair1.pubkey(), 1, bank.last_id(), 0);
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
let tx =
|
let tx =
|
||||||
SystemTransaction::new_account(&mint_keypair, keypair2.pubkey(), 3, bank.last_id(), 0);
|
SystemTransaction::new_account(&mint_keypair, keypair2.pubkey(), 1, bank.last_id(), 0);
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
|
|
||||||
let last_id = bank.last_id();
|
let last_id = bank.last_id();
|
||||||
|
|
||||||
// ensure bank can process 2 entries that do not have a common account and tick is registered
|
// ensure bank can process 2 entries that do not have a common account and tick is registered
|
||||||
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, bank.last_id(), 2);
|
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, bank.last_id(), 0);
|
||||||
let entry_1 = next_entry(&last_id, 1, vec![tx]);
|
let entry_1 = next_entry(&last_id, 1, vec![tx]);
|
||||||
let tick = next_entry(&entry_1.id, 1, vec![]);
|
let tick = next_entry(&entry_1.id, 1, vec![]);
|
||||||
let tx = SystemTransaction::new_account(&keypair1, keypair4.pubkey(), 1, tick.id, 5);
|
let tx = SystemTransaction::new_account(&keypair1, keypair4.pubkey(), 1, tick.id, 0);
|
||||||
let entry_2 = next_entry(&tick.id, 1, vec![tx]);
|
let entry_2 = next_entry(&tick.id, 1, vec![tx]);
|
||||||
let (res, fee) =
|
assert_eq!(
|
||||||
par_process_entries(&bank, &[entry_1.clone(), tick.clone(), entry_2.clone()]);
|
par_process_entries(&bank, &[entry_1.clone(), tick.clone(), entry_2.clone()]),
|
||||||
assert_eq!(res, Ok(()));
|
Ok(())
|
||||||
assert_eq!(fee, 7);
|
);
|
||||||
assert_eq!(bank.get_balance(&keypair3.pubkey()), 1);
|
assert_eq!(bank.get_balance(&keypair3.pubkey()), 1);
|
||||||
assert_eq!(bank.get_balance(&keypair4.pubkey()), 1);
|
assert_eq!(bank.get_balance(&keypair4.pubkey()), 1);
|
||||||
assert_eq!(bank.last_id(), tick.id);
|
assert_eq!(bank.last_id(), tick.id);
|
||||||
// ensure that an error is returned for an empty account (keypair2)
|
// ensure that an error is returned for an empty account (keypair2)
|
||||||
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, tick.id, 0);
|
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, tick.id, 0);
|
||||||
let entry_3 = next_entry(&entry_2.id, 1, vec![tx]);
|
let entry_3 = next_entry(&entry_2.id, 1, vec![tx]);
|
||||||
let (res, fee) = par_process_entries(&bank, &[entry_3]);
|
assert_eq!(
|
||||||
assert_eq!(fee, 0);
|
par_process_entries(&bank, &[entry_3]),
|
||||||
assert_eq!(res, Err(BankError::AccountNotFound));
|
Err(BankError::AccountNotFound)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,8 +319,7 @@ impl Fullnode {
|
||||||
}
|
}
|
||||||
None => FullnodeReturnType::LeaderToLeaderRotation, // value doesn't matter here...
|
None => FullnodeReturnType::LeaderToLeaderRotation, // value doesn't matter here...
|
||||||
};
|
};
|
||||||
|
let tpu_bank = Arc::new(Bank::new_from_parent(bank, &leader));
|
||||||
let tpu_bank = Arc::new(Bank::new_from_parent(bank));
|
|
||||||
self.node_services.tpu.switch_to_leader(
|
self.node_services.tpu.switch_to_leader(
|
||||||
&tpu_bank,
|
&tpu_bank,
|
||||||
PohServiceConfig::default(),
|
PohServiceConfig::default(),
|
||||||
|
|
|
@ -65,7 +65,6 @@ impl ReplayStage {
|
||||||
last_entry_id: &Arc<RwLock<Hash>>,
|
last_entry_id: &Arc<RwLock<Hash>>,
|
||||||
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
leader_scheduler: &Arc<RwLock<LeaderScheduler>>,
|
||||||
subscriptions: &Arc<RpcSubscriptions>,
|
subscriptions: &Arc<RpcSubscriptions>,
|
||||||
fees: &mut u64,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Coalesce all the available entries into a single vote
|
// Coalesce all the available entries into a single vote
|
||||||
submit(
|
submit(
|
||||||
|
@ -112,10 +111,7 @@ impl ReplayStage {
|
||||||
// If we don't process the entry now, the for loop will exit and the entry
|
// If we don't process the entry now, the for loop will exit and the entry
|
||||||
// will be dropped.
|
// will be dropped.
|
||||||
if 0 == num_ticks_to_next_vote || (i + 1) == entries.len() {
|
if 0 == num_ticks_to_next_vote || (i + 1) == entries.len() {
|
||||||
let (res_int, fee) =
|
res = blocktree_processor::process_entries(bank, &entries[0..=i], leader_scheduler);
|
||||||
blocktree_processor::process_entries(bank, &entries[0..=i], leader_scheduler);
|
|
||||||
res = res_int;
|
|
||||||
*fees += fee;
|
|
||||||
|
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
// TODO: This will return early from the first entry that has an erroneous
|
// TODO: This will return early from the first entry that has an erroneous
|
||||||
|
@ -130,15 +126,6 @@ impl ReplayStage {
|
||||||
|
|
||||||
if 0 == num_ticks_to_next_vote {
|
if 0 == num_ticks_to_next_vote {
|
||||||
subscriptions.notify_subscribers(&bank);
|
subscriptions.notify_subscribers(&bank);
|
||||||
if let Some(leader) = leader_scheduler
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.get_leader_for_tick(num_ticks)
|
|
||||||
{
|
|
||||||
// Credit the accumulated fees to the current leader and reset the fee to 0
|
|
||||||
bank.deposit(&leader, *fees);
|
|
||||||
*fees = 0;
|
|
||||||
}
|
|
||||||
if let Some(voting_keypair) = voting_keypair {
|
if let Some(voting_keypair) = voting_keypair {
|
||||||
let keypair = voting_keypair.as_ref();
|
let keypair = voting_keypair.as_ref();
|
||||||
let vote =
|
let vote =
|
||||||
|
@ -227,7 +214,6 @@ impl ReplayStage {
|
||||||
.expect("Database error")
|
.expect("Database error")
|
||||||
.map(|meta| meta.consumed)
|
.map(|meta| meta.consumed)
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let mut fees = 0;
|
|
||||||
|
|
||||||
// Loop through blocktree MAX_ENTRY_RECV_PER_ITER entries at a time for each
|
// Loop through blocktree MAX_ENTRY_RECV_PER_ITER entries at a time for each
|
||||||
// relevant slot to see if there are any available updates
|
// relevant slot to see if there are any available updates
|
||||||
|
@ -290,7 +276,6 @@ impl ReplayStage {
|
||||||
&last_entry_id,
|
&last_entry_id,
|
||||||
&leader_scheduler_,
|
&leader_scheduler_,
|
||||||
&subscriptions_,
|
&subscriptions_,
|
||||||
&mut fees,
|
|
||||||
) {
|
) {
|
||||||
error!("process_entries failed: {:?}", e);
|
error!("process_entries failed: {:?}", e);
|
||||||
}
|
}
|
||||||
|
@ -776,7 +761,6 @@ mod test {
|
||||||
let leader_scheduler_config = LeaderSchedulerConfig::default();
|
let leader_scheduler_config = LeaderSchedulerConfig::default();
|
||||||
let leader_scheduler = LeaderScheduler::new_with_bank(&leader_scheduler_config, &bank);
|
let leader_scheduler = LeaderScheduler::new_with_bank(&leader_scheduler_config, &bank);
|
||||||
let leader_scheduler = Arc::new(RwLock::new(leader_scheduler));
|
let leader_scheduler = Arc::new(RwLock::new(leader_scheduler));
|
||||||
let mut fee = 0;
|
|
||||||
let res = ReplayStage::process_entries(
|
let res = ReplayStage::process_entries(
|
||||||
entries.clone(),
|
entries.clone(),
|
||||||
&bank,
|
&bank,
|
||||||
|
@ -787,7 +771,6 @@ mod test {
|
||||||
&Arc::new(RwLock::new(last_entry_id)),
|
&Arc::new(RwLock::new(last_entry_id)),
|
||||||
&leader_scheduler,
|
&leader_scheduler,
|
||||||
&Arc::new(RpcSubscriptions::default()),
|
&Arc::new(RpcSubscriptions::default()),
|
||||||
&mut fee,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
|
@ -814,7 +797,6 @@ mod test {
|
||||||
&Arc::new(RwLock::new(last_entry_id)),
|
&Arc::new(RwLock::new(last_entry_id)),
|
||||||
&leader_scheduler,
|
&leader_scheduler,
|
||||||
&Arc::new(RpcSubscriptions::default()),
|
&Arc::new(RpcSubscriptions::default()),
|
||||||
&mut fee,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
|
|
|
@ -168,6 +168,7 @@ 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;
|
||||||
|
@ -184,7 +185,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)))
|
Ok(Arc::new(Bank::new_from_parent(&bank, &Pubkey::default())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_session() -> Arc<Session> {
|
fn create_session() -> Arc<Session> {
|
||||||
|
|
Loading…
Reference in New Issue