Replace Transaction::fee with a FeeCalculator

This commit is contained in:
Greg Fitzgerald
2019-03-29 16:11:21 -06:00
parent 9369ea86ea
commit 7896e8288d
8 changed files with 127 additions and 62 deletions

View File

@ -7,6 +7,7 @@ use log::*;
use rand::{thread_rng, Rng};
use solana_metrics::counter::Counter;
use solana_sdk::account::Account;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::hash::{hash, Hash};
use solana_sdk::native_loader;
use solana_sdk::pubkey::Pubkey;
@ -611,11 +612,12 @@ impl AccountsDB {
&self,
fork: Fork,
tx: &Transaction,
fee: u64,
error_counters: &mut ErrorCounters,
) -> Result<Vec<Account>> {
// Copy all the accounts
let message = tx.message();
if tx.signatures.is_empty() && message.fee != 0 {
if tx.signatures.is_empty() && fee != 0 {
Err(TransactionError::MissingSignatureForFee)
} else {
// Check for unique account keys
@ -633,11 +635,11 @@ impl AccountsDB {
if called_accounts.is_empty() || called_accounts[0].lamports == 0 {
error_counters.account_not_found += 1;
Err(TransactionError::AccountNotFound)
} else if called_accounts[0].lamports < message.fee {
} else if called_accounts[0].lamports < fee {
error_counters.insufficient_funds += 1;
Err(TransactionError::InsufficientFundsForFee)
} else {
called_accounts[0].lamports -= message.fee;
called_accounts[0].lamports -= fee;
Ok(called_accounts)
}
}
@ -711,13 +713,15 @@ impl AccountsDB {
fork: Fork,
txs: &[Transaction],
lock_results: Vec<Result<()>>,
fee_calculator: &FeeCalculator,
error_counters: &mut ErrorCounters,
) -> Vec<Result<(InstructionAccounts, InstructionLoaders)>> {
txs.iter()
.zip(lock_results.into_iter())
.map(|etx| match etx {
(tx, Ok(())) => {
let accounts = self.load_tx_accounts(fork, tx, error_counters)?;
let fee = fee_calculator.calculate_fee(tx.message());
let accounts = self.load_tx_accounts(fork, tx, fee, error_counters)?;
let loaders = self.load_loaders(fork, tx, error_counters)?;
Ok((accounts, loaders))
}
@ -943,10 +947,11 @@ impl Accounts {
fork: Fork,
txs: &[Transaction],
results: Vec<Result<()>>,
fee_calculator: &FeeCalculator,
error_counters: &mut ErrorCounters,
) -> Vec<Result<(InstructionAccounts, InstructionLoaders)>> {
self.accounts_db
.load_accounts(fork, txs, results, error_counters)
.load_accounts(fork, txs, results, fee_calculator, error_counters)
}
/// Store the accounts into the DB
@ -1006,9 +1011,10 @@ mod tests {
});
}
fn load_accounts(
fn load_accounts_with_fee(
tx: Transaction,
ka: &Vec<(Pubkey, Account)>,
fee_calculator: &FeeCalculator,
error_counters: &mut ErrorCounters,
) -> Vec<Result<(InstructionAccounts, InstructionLoaders)>> {
let accounts = Accounts::new(0, None);
@ -1016,10 +1022,19 @@ mod tests {
accounts.store_slow(0, &ka.0, &ka.1);
}
let res = accounts.load_accounts(0, &[tx], vec![Ok(())], error_counters);
let res = accounts.load_accounts(0, &[tx], vec![Ok(())], &fee_calculator, error_counters);
res
}
fn load_accounts(
tx: Transaction,
ka: &Vec<(Pubkey, Account)>,
error_counters: &mut ErrorCounters,
) -> Vec<Result<(InstructionAccounts, InstructionLoaders)>> {
let fee_calculator = FeeCalculator::default();
load_accounts_with_fee(tx, ka, &fee_calculator, error_counters)
}
#[test]
fn test_load_accounts_no_key() {
let accounts: Vec<(Pubkey, Account)> = Vec::new();
@ -1119,7 +1134,11 @@ mod tests {
instructions,
);
let loaded_accounts = load_accounts(tx, &accounts, &mut error_counters);
let fee_calculator = FeeCalculator::new(10);
assert_eq!(fee_calculator.calculate_fee(tx.message()), 10);
let loaded_accounts =
load_accounts_with_fee(tx, &accounts, &fee_calculator, &mut error_counters);
assert_eq!(error_counters.insufficient_funds, 1);
assert_eq!(loaded_accounts.len(), 1);

View File

@ -12,6 +12,7 @@ use hashbrown::HashMap;
use log::*;
use solana_metrics::counter::Counter;
use solana_sdk::account::Account;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::hash::{extend_and_hash, Hash};
use solana_sdk::native_loader;
@ -143,6 +144,9 @@ pub struct Bank {
/// The pubkey to send transactions fees to.
collector_id: Pubkey,
/// An object to calculate transaction fees.
pub fee_calculator: FeeCalculator,
/// initialized from genesis
epoch_schedule: EpochSchedule,
@ -465,8 +469,13 @@ impl Bank {
results: Vec<Result<()>>,
error_counters: &mut ErrorCounters,
) -> Vec<Result<(InstructionAccounts, InstructionLoaders)>> {
self.accounts
.load_accounts(self.accounts_id, txs, results, error_counters)
self.accounts.load_accounts(
self.accounts_id,
txs,
results,
&self.fee_calculator,
error_counters,
)
}
fn check_refs(
&self,
@ -659,16 +668,17 @@ impl Bank {
.iter()
.zip(executed.iter())
.map(|(tx, res)| {
let fee = self.fee_calculator.calculate_fee(tx.message());
let message = tx.message();
match *res {
Err(TransactionError::InstructionError(_, _)) => {
// Charge the transaction fee even in case of InstructionError
self.withdraw(&message.account_keys[0], message.fee)?;
fees += message.fee;
self.withdraw(&message.account_keys[0], fee)?;
fees += fee;
Ok(())
}
Ok(()) => {
fees += message.fee;
fees += fee;
Ok(())
}
_ => res.clone(),
@ -1059,7 +1069,9 @@ mod tests {
#[test]
fn test_detect_failed_duplicate_transactions() {
let (genesis_block, mint_keypair) = GenesisBlock::new(2);
let bank = Bank::new(&genesis_block);
let mut bank = Bank::new(&genesis_block);
bank.fee_calculator.lamports_per_signature = 1;
let dest = Keypair::new();
// source with 0 program context
@ -1068,7 +1080,7 @@ mod tests {
&dest.pubkey(),
2,
genesis_block.hash(),
1,
0,
);
let signature = tx.signatures[0];
assert!(!bank.has_signature(&signature));
@ -1176,19 +1188,22 @@ mod tests {
fn test_bank_tx_fee() {
let leader = Keypair::new().pubkey();
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, &leader, 3);
let bank = Bank::new(&genesis_block);
let mut bank = Bank::new(&genesis_block);
bank.fee_calculator.lamports_per_signature = 3;
let key1 = Keypair::new();
let key2 = Keypair::new();
let tx =
SystemTransaction::new_move(&mint_keypair, &key1.pubkey(), 2, genesis_block.hash(), 3);
SystemTransaction::new_move(&mint_keypair, &key1.pubkey(), 2, genesis_block.hash(), 0);
let initial_balance = bank.get_balance(&leader);
assert_eq!(bank.process_transaction(&tx), Ok(()));
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 - 5 - 3);
let tx = SystemTransaction::new_move(&key1, &key2.pubkey(), 1, genesis_block.hash(), 1);
bank.fee_calculator.lamports_per_signature = 1;
let tx = SystemTransaction::new_move(&key1, &key2.pubkey(), 1, genesis_block.hash(), 0);
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert_eq!(bank.get_balance(&leader), initial_balance + 4);
assert_eq!(bank.get_balance(&key1.pubkey()), 0);
@ -1200,13 +1215,13 @@ mod tests {
fn test_filter_program_errors_and_collect_fee() {
let leader = Keypair::new().pubkey();
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, &leader, 3);
let bank = Bank::new(&genesis_block);
let mut bank = Bank::new(&genesis_block);
let key = Keypair::new();
let tx1 =
SystemTransaction::new_move(&mint_keypair, &key.pubkey(), 2, genesis_block.hash(), 3);
SystemTransaction::new_move(&mint_keypair, &key.pubkey(), 2, genesis_block.hash(), 0);
let tx2 =
SystemTransaction::new_move(&mint_keypair, &key.pubkey(), 5, genesis_block.hash(), 1);
SystemTransaction::new_move(&mint_keypair, &key.pubkey(), 5, genesis_block.hash(), 0);
let results = vec![
Ok(()),
@ -1216,9 +1231,10 @@ mod tests {
)),
];
bank.fee_calculator.lamports_per_signature = 2;
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(&leader), initial_balance + 3 + 1);
assert_eq!(bank.get_balance(&leader), initial_balance + 2 + 2);
assert_eq!(results[0], Ok(()));
assert_eq!(results[1], Ok(()));
}
@ -1586,29 +1602,21 @@ mod tests {
fn test_zero_signatures() {
solana_logger::setup();
let (genesis_block, mint_keypair) = GenesisBlock::new(500);
let bank = Arc::new(Bank::new(&genesis_block));
let mut bank = Bank::new(&genesis_block);
bank.fee_calculator.lamports_per_signature = 2;
let key = Keypair::new();
let mut move_instruction =
SystemInstruction::new_move(&mint_keypair.pubkey(), &key.pubkey(), 1);
SystemInstruction::new_move(&mint_keypair.pubkey(), &key.pubkey(), 0);
move_instruction.accounts[0].is_signer = false;
let mut tx = Transaction::new_signed_instructions(
let tx = Transaction::new_signed_instructions(
&Vec::<&Keypair>::new(),
vec![move_instruction],
bank.last_blockhash(),
2,
0,
);
assert_eq!(
bank.process_transaction(&tx),
Err(TransactionError::MissingSignatureForFee)
);
// Set the fee to 0, this should give an InstructionError
// but since no signature we cannot look up the error.
tx.message.fee = 0;
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert_eq!(bank.get_balance(&key.pubkey()), 0);
}