Return program error from process_transaction()

Our unit-test helper `process_transaction()` wasn't returning
program errors, which made testing programs tedious and
counter-intuitive.
This commit is contained in:
Greg Fitzgerald 2019-03-01 19:45:10 -07:00
parent db825b6e26
commit 49b7e67585
3 changed files with 21 additions and 33 deletions

View File

@ -1,8 +1,8 @@
//use solana_runtime::bank::BankError; use solana_runtime::bank::BankError;
use solana_runtime::bank::{Bank, Result}; use solana_runtime::bank::{Bank, Result};
use solana_sdk::genesis_block::GenesisBlock; use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::hash::hash; use solana_sdk::hash::hash;
//use solana_sdk::native_program::ProgramError; use solana_sdk::native_program::ProgramError;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction::SystemInstruction; use solana_sdk::system_instruction::SystemInstruction;
@ -86,15 +86,15 @@ fn test_vote_via_bank_with_no_signature() {
.push(vote_ix) .push(vote_ix)
.sign(&[&mallory_keypair], last_id); .sign(&[&mallory_keypair], last_id);
let _result = bank.process_transaction(&tx); let result = bank.process_transaction(&tx);
// And ensure there's no vote. // And ensure there's no vote.
let vote_account = bank.get_account(&vote_id).unwrap(); let vote_account = bank.get_account(&vote_id).unwrap();
let vote_state = VoteState::deserialize(&vote_account.userdata).unwrap(); let vote_state = VoteState::deserialize(&vote_account.userdata).unwrap();
assert_eq!(vote_state.votes.len(), 0); assert_eq!(vote_state.votes.len(), 0);
//assert_eq!( assert_eq!(
// result, result,
// Err(BankError::ProgramError(1, ProgramError::InvalidArgument)) Err(BankError::ProgramError(1, ProgramError::InvalidArgument))
//); );
} }

View File

@ -74,10 +74,9 @@ fn test_program_native_failure() {
// Call user program // Call user program
let tx = Transaction::new(&mint_keypair, &[], program_id, &1u8, bank.last_id(), 0); let tx = Transaction::new(&mint_keypair, &[], program_id, &1u8, bank.last_id(), 0);
bank.process_transaction(&tx).unwrap();
assert_eq!( assert_eq!(
bank.get_signature_status(&tx.signatures[0]), bank.process_transaction(&tx),
Some(Err(BankError::ProgramError(0, ProgramError::GenericError))) Err(BankError::ProgramError(0, ProgramError::GenericError))
); );
} }

View File

@ -358,13 +358,10 @@ impl Bank {
/// Process a Transaction. This is used for unit tests and simply calls the vector Bank::process_transactions method. /// Process a Transaction. This is used for unit tests and simply calls the vector Bank::process_transactions method.
pub fn process_transaction(&self, tx: &Transaction) -> Result<()> { pub fn process_transaction(&self, tx: &Transaction) -> Result<()> {
let txs = vec![tx.clone()]; let txs = vec![tx.clone()];
match self.process_transactions(&txs)[0] { self.process_transactions(&txs)[0].clone()?;
Err(ref e) => { tx.signatures
info!("process_transaction error: {:?}", e); .get(0)
Err((*e).clone()) .map_or(Ok(()), |sig| self.get_signature_status(sig).unwrap())
}
Ok(_) => Ok(()),
}
} }
pub fn lock_accounts(&self, txs: &[Transaction]) -> Vec<Result<()>> { pub fn lock_accounts(&self, txs: &[Transaction]) -> Vec<Result<()>> {
@ -951,7 +948,7 @@ mod tests {
// This test demonstrates that fees are paid even when a program fails. // This test demonstrates that fees are paid even when a program fails.
#[test] #[test]
fn test_detect_failed_duplicate_transactions_issue_1157() { fn test_detect_failed_duplicate_transactions() {
let (genesis_block, mint_keypair) = GenesisBlock::new(2); let (genesis_block, mint_keypair) = GenesisBlock::new(2);
let bank = Bank::new(&genesis_block); let bank = Bank::new(&genesis_block);
let dest = Keypair::new(); let dest = Keypair::new();
@ -967,16 +964,12 @@ mod tests {
let signature = tx.signatures[0]; let signature = tx.signatures[0];
assert!(!bank.has_signature(&signature)); assert!(!bank.has_signature(&signature));
// Assert that process_transaction has filtered out Program Errors
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert!(bank.has_signature(&signature));
assert_eq!( assert_eq!(
bank.get_signature_status(&signature), bank.process_transaction(&tx),
Some(Err(BankError::ProgramError( Err(BankError::ProgramError(
0, 0,
ProgramError::ResultWithNegativeTokens ProgramError::ResultWithNegativeTokens
))) ))
); );
// The tokens didn't move, but the from address paid the transaction fee. // The tokens didn't move, but the from address paid the transaction fee.
@ -1007,18 +1000,14 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!(bank.transaction_count(), 1); assert_eq!(bank.transaction_count(), 1);
assert_eq!(bank.get_balance(&pubkey), 1_000); assert_eq!(bank.get_balance(&pubkey), 1_000);
let signature = bank
.transfer(10_001, &mint_keypair, pubkey, genesis_block.hash())
.unwrap();
assert_eq!(bank.transaction_count(), 1);
assert!(bank.has_signature(&signature));
assert_eq!( assert_eq!(
bank.get_signature_status(&signature), bank.transfer(10_001, &mint_keypair, pubkey, genesis_block.hash()),
Some(Err(BankError::ProgramError( Err(BankError::ProgramError(
0, 0,
ProgramError::ResultWithNegativeTokens ProgramError::ResultWithNegativeTokens
))) ))
); );
assert_eq!(bank.transaction_count(), 1);
let mint_pubkey = mint_keypair.pubkey(); let mint_pubkey = mint_keypair.pubkey();
assert_eq!(bank.get_balance(&mint_pubkey), 10_000); assert_eq!(bank.get_balance(&mint_pubkey), 10_000);