moved fee collection code to runtime

This commit is contained in:
Pankaj Garg
2019-02-21 13:37:08 -08:00
committed by Grimes
parent c142a82ae0
commit 5c9777970d
7 changed files with 176 additions and 129 deletions

View File

@ -104,6 +104,9 @@ 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 Default for Bank {
@ -117,6 +120,7 @@ impl Default for Bank {
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
slots_per_epoch: 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.
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();
bank.last_id_queue = RwLock::new(parent.last_id_queue.read().unwrap().clone());
bank.ticks_per_slot = parent.ticks_per_slot;
@ -141,6 +145,7 @@ impl Bank {
if *parent.hash.read().unwrap() == Hash::default() {
*parent.hash.write().unwrap() = parent.hash_internal_state();
}
bank.leader = leader.clone();
bank
}
@ -499,7 +504,7 @@ impl Bank {
txs: &[Transaction],
loaded_accounts: &[Result<(InstructionAccounts, InstructionLoaders)>],
executed: &[Result<()>],
) {
) -> Vec<Result<()>> {
let now = Instant::now();
self.accounts
.store_accounts(self.is_root(), txs, executed, loaded_accounts);
@ -512,6 +517,27 @@ impl Bank {
txs.len(),
);
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.
@ -525,8 +551,7 @@ impl Bank {
let (loaded_accounts, executed) =
self.load_and_execute_transactions(txs, lock_results, max_age);
self.commit_transactions(txs, &loaded_accounts, &executed);
executed
self.commit_transactions(txs, &loaded_accounts, &executed)
}
#[must_use]
@ -579,10 +604,19 @@ impl Bank {
parents
}
pub fn withdraw(&self, pubkey: &Pubkey, tokens: u64) {
let mut account = self.get_account(pubkey).unwrap_or_default();
account.tokens -= tokens;
self.accounts.store_slow(true, pubkey, &account);
pub fn withdraw(&self, pubkey: &Pubkey, tokens: u64) -> Result<()> {
match self.get_account(pubkey) {
Some(mut 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) {
@ -952,6 +986,77 @@ mod tests {
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]
fn test_debits_before_credits() {
let (genesis_block, mint_keypair) = GenesisBlock::new(2);
@ -1028,13 +1133,13 @@ mod tests {
let bank = Bank::new(&genesis_block);
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();
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));
let bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default());
assert_eq!(
bank.leader_schedule_bank().unwrap().slot_height(),
slot_height
@ -1164,7 +1269,7 @@ mod tests {
let (genesis_block, _) = GenesisBlock::new(1);
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));
}
@ -1183,7 +1288,7 @@ mod tests {
0,
);
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!(
bank.process_transaction(&tx),
Err(BankError::DuplicateSignature)
@ -1206,7 +1311,7 @@ mod tests {
0,
);
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);
assert_eq!(bank.process_transaction(&tx), Ok(()));
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());
// 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());
}
@ -1258,7 +1363,7 @@ mod tests {
0,
);
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 =
SystemTransaction::new_move(&key1, key2.pubkey(), 1, genesis_block.last_id(), 0);
assert_eq!(bank.process_transaction(&tx_move_1_to_2), Ok(()));