Extract ProgramError from BankError

This commit is contained in:
Greg Fitzgerald
2018-11-23 15:53:39 -07:00
parent f827bfd83f
commit 37f8dd57e2
4 changed files with 47 additions and 22 deletions

View File

@ -19,6 +19,7 @@ use native_loader;
use payment_plan::Payment; use payment_plan::Payment;
use poh_recorder::PohRecorder; use poh_recorder::PohRecorder;
use poh_service::NUM_TICKS_PER_SECOND; use poh_service::NUM_TICKS_PER_SECOND;
use program::ProgramError;
use rayon::prelude::*; use rayon::prelude::*;
use rpc::RpcSignatureStatus; use rpc::RpcSignatureStatus;
use signature::Keypair; use signature::Keypair;
@ -86,10 +87,8 @@ pub enum BankError {
/// Contract's instruction token balance does not equal the balance after the instruction /// Contract's instruction token balance does not equal the balance after the instruction
UnbalancedInstruction(u8), UnbalancedInstruction(u8),
/// Contract's transactions resulted in an account with a negative balance /// The program returned an error
/// The difference from InsufficientFundsForFee is that the transaction was executed by the ProgramError(u8, ProgramError),
/// contract
ResultWithNegativeTokens(u8),
/// Contract id is unknown /// Contract id is unknown
UnknownContractId(u8), UnknownContractId(u8),
@ -100,9 +99,6 @@ pub enum BankError {
/// Contract spent the tokens of an account that doesn't belong to it /// Contract spent the tokens of an account that doesn't belong to it
ExternalAccountTokenSpend(u8), ExternalAccountTokenSpend(u8),
/// The program returned an error
ProgramRuntimeError(u8),
/// Recoding into PoH failed /// Recoding into PoH failed
RecordFailure, RecordFailure,
@ -499,9 +495,7 @@ impl Bank {
let status = match res[i] { let status = match res[i] {
Ok(_) => RpcSignatureStatus::Confirmed, Ok(_) => RpcSignatureStatus::Confirmed,
Err(BankError::AccountInUse) => RpcSignatureStatus::AccountInUse, Err(BankError::AccountInUse) => RpcSignatureStatus::AccountInUse,
Err(BankError::ProgramRuntimeError(_)) => { Err(BankError::ProgramError(_, _)) => RpcSignatureStatus::ProgramRuntimeError,
RpcSignatureStatus::ProgramRuntimeError
}
Err(_) => RpcSignatureStatus::GenericFailure, Err(_) => RpcSignatureStatus::GenericFailure,
}; };
if status != RpcSignatureStatus::SignatureNotFound { if status != RpcSignatureStatus::SignatureNotFound {
@ -823,28 +817,31 @@ impl Bank {
{ {
let err = match err { let err = match err {
system_program::Error::ResultWithNegativeTokens => { system_program::Error::ResultWithNegativeTokens => {
BankError::ResultWithNegativeTokens(instruction_index as u8) ProgramError::ResultWithNegativeTokens
} }
_ => BankError::ProgramRuntimeError(instruction_index as u8), _ => ProgramError::RuntimeError,
}; };
return Err(err); return Err(BankError::ProgramError(instruction_index as u8, err));
} }
} else if budget_program::check_id(&program_id) { } else if budget_program::check_id(&program_id) {
if budget_program::process_instruction(&tx, instruction_index, program_accounts) if budget_program::process_instruction(&tx, instruction_index, program_accounts)
.is_err() .is_err()
{ {
return Err(BankError::ProgramRuntimeError(instruction_index as u8)); let err = ProgramError::RuntimeError;
return Err(BankError::ProgramError(instruction_index as u8, err));
} }
} else if storage_program::check_id(&program_id) { } else if storage_program::check_id(&program_id) {
if storage_program::process_instruction(&tx, instruction_index, program_accounts) if storage_program::process_instruction(&tx, instruction_index, program_accounts)
.is_err() .is_err()
{ {
return Err(BankError::ProgramRuntimeError(instruction_index as u8)); let err = ProgramError::RuntimeError;
return Err(BankError::ProgramError(instruction_index as u8, err));
} }
} else if vote_program::check_id(&program_id) { } else if vote_program::check_id(&program_id) {
if vote_program::process_instruction(&tx, instruction_index, program_accounts).is_err() if vote_program::process_instruction(&tx, instruction_index, program_accounts).is_err()
{ {
return Err(BankError::ProgramRuntimeError(instruction_index as u8)); let err = ProgramError::RuntimeError;
return Err(BankError::ProgramError(instruction_index as u8, err));
} }
} else { } else {
let mut accounts = self.load_executable_accounts(tx.program_ids[instruction_index])?; let mut accounts = self.load_executable_accounts(tx.program_ids[instruction_index])?;
@ -864,7 +861,8 @@ impl Bank {
&tx.instructions[instruction_index].userdata, &tx.instructions[instruction_index].userdata,
self.tick_height(), self.tick_height(),
) { ) {
return Err(BankError::ProgramRuntimeError(instruction_index as u8)); let err = ProgramError::RuntimeError;
return Err(BankError::ProgramError(instruction_index as u8, err));
} }
} }
@ -1606,13 +1604,22 @@ mod tests {
); );
let res = bank.process_transactions(&vec![t1.clone()]); let res = bank.process_transactions(&vec![t1.clone()]);
assert_eq!(res.len(), 1); assert_eq!(res.len(), 1);
assert_eq!(res[0], Err(BankError::ResultWithNegativeTokens(1))); assert_eq!(
res[0],
Err(BankError::ProgramError(
1,
ProgramError::ResultWithNegativeTokens
))
);
assert_eq!(bank.get_balance(&mint.pubkey()), 1); assert_eq!(bank.get_balance(&mint.pubkey()), 1);
assert_eq!(bank.get_balance(&key1), 0); assert_eq!(bank.get_balance(&key1), 0);
assert_eq!(bank.get_balance(&key2), 0); assert_eq!(bank.get_balance(&key2), 0);
assert_eq!( assert_eq!(
bank.get_signature(&t1.last_id, &t1.signatures[0]), bank.get_signature(&t1.last_id, &t1.signatures[0]),
Some(Err(BankError::ResultWithNegativeTokens(1))) Some(Err(BankError::ProgramError(
1,
ProgramError::ResultWithNegativeTokens
)))
); );
} }
@ -1667,7 +1674,10 @@ mod tests {
assert!(bank.has_signature(&signature)); assert!(bank.has_signature(&signature));
assert_matches!( assert_matches!(
bank.get_signature_status(&signature), bank.get_signature_status(&signature),
Err(BankError::ResultWithNegativeTokens(0)) Err(BankError::ProgramError(
0,
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.
@ -1700,7 +1710,10 @@ mod tests {
assert_eq!(bank.get_balance(&pubkey), 1_000); assert_eq!(bank.get_balance(&pubkey), 1_000);
assert_matches!( assert_matches!(
bank.transfer(10_001, &mint.keypair(), pubkey, mint.last_id()), bank.transfer(10_001, &mint.keypair(), pubkey, mint.last_id()),
Err(BankError::ResultWithNegativeTokens(0)) Err(BankError::ProgramError(
0,
ProgramError::ResultWithNegativeTokens
))
); );
assert_eq!(bank.transaction_count(), 1); assert_eq!(bank.transaction_count(), 1);

View File

@ -56,6 +56,7 @@ pub mod payment_plan;
pub mod poh; pub mod poh;
pub mod poh_recorder; pub mod poh_recorder;
pub mod poh_service; pub mod poh_service;
pub mod program;
pub mod recvmmsg; pub mod recvmmsg;
pub mod replicate_stage; pub mod replicate_stage;
pub mod replicator; pub mod replicator;

11
src/program.rs Normal file
View File

@ -0,0 +1,11 @@
/// Reasons a program might have rejected an instruction.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ProgramError {
/// Contract's transactions resulted in an account with a negative balance
/// The difference from InsufficientFundsForFee is that the transaction was executed by the
/// contract
ResultWithNegativeTokens,
/// The program returned an error
RuntimeError,
}

View File

@ -191,7 +191,7 @@ impl RpcSol for RpcSolImpl {
match meta.request_processor.get_signature_status(signature) { match meta.request_processor.get_signature_status(signature) {
Ok(_) => RpcSignatureStatus::Confirmed, Ok(_) => RpcSignatureStatus::Confirmed,
Err(BankError::AccountInUse) => RpcSignatureStatus::AccountInUse, Err(BankError::AccountInUse) => RpcSignatureStatus::AccountInUse,
Err(BankError::ProgramRuntimeError(_)) => RpcSignatureStatus::ProgramRuntimeError, Err(BankError::ProgramError(_, _)) => RpcSignatureStatus::ProgramRuntimeError,
// Report SignatureReserved as SignatureNotFound as SignatureReserved is // Report SignatureReserved as SignatureNotFound as SignatureReserved is
// transitory while the bank processes the associated transaction. // transitory while the bank processes the associated transaction.
Err(BankError::SignatureReserved) => RpcSignatureStatus::SignatureNotFound, Err(BankError::SignatureReserved) => RpcSignatureStatus::SignatureNotFound,