Let clients know when transactions failed

This commit is contained in:
Greg Fitzgerald
2018-09-26 15:57:34 -06:00
parent 25edb9e447
commit e416cf7adf
2 changed files with 22 additions and 14 deletions

View File

@ -89,6 +89,10 @@ pub enum BankError {
/// the `last_id` has been discarded. /// the `last_id` has been discarded.
LastIdNotFound(Hash), LastIdNotFound(Hash),
/// The bank has not seen a transaction with the given `Signature` or the transaction is
/// too old and has been discarded.
SignatureNotFound,
/// Proof of History verification failed. /// Proof of History verification failed.
LedgerVerificationFailed, LedgerVerificationFailed,
/// Contract's transaction token balance does not equal the balance after the transaction /// Contract's transaction token balance does not equal the balance after the transaction
@ -711,17 +715,18 @@ impl Bank {
self.transaction_count.load(Ordering::Relaxed) self.transaction_count.load(Ordering::Relaxed)
} }
pub fn get_signature_status(&self, signature: &Signature) -> Result<()> {
let last_ids_sigs = self.last_ids_sigs.read().unwrap();
for (_hash, (signatures, _)) in last_ids_sigs.iter() {
if let Some(res) = signatures.get(signature) {
return res.clone();
}
}
Err(BankError::SignatureNotFound)
}
pub fn has_signature(&self, signature: &Signature) -> bool { pub fn has_signature(&self, signature: &Signature) -> bool {
let last_ids_sigs = self self.get_signature_status(signature) != Err(BankError::SignatureNotFound)
.last_ids_sigs
.read()
.expect("'last_ids_sigs' read lock");
for (_hash, signatures) in last_ids_sigs.iter() {
if signatures.0.contains_key(signature) {
return true;
}
}
false
} }
/// Hash the `accounts` HashMap. This represents a validator's interpretation /// Hash the `accounts` HashMap. This represents a validator's interpretation

View File

@ -1,6 +1,6 @@
//! The `rpc` module implements the Solana RPC interface. //! The `rpc` module implements the Solana RPC interface.
use bank::{Account, Bank}; use bank::{Account, Bank, BankError};
use bincode::deserialize; use bincode::deserialize;
use bs58; use bs58;
use jsonrpc_core::*; use jsonrpc_core::*;
@ -9,6 +9,7 @@ use service::Service;
use signature::{Pubkey, Signature}; use signature::{Pubkey, Signature};
use std::mem; use std::mem;
use std::net::{SocketAddr, UdpSocket}; use std::net::{SocketAddr, UdpSocket};
use std::result;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread::{self, sleep, Builder, JoinHandle}; use std::thread::{self, sleep, Builder, JoinHandle};
@ -125,7 +126,9 @@ impl RpcSol for RpcSolImpl {
return Err(Error::invalid_request()); return Err(Error::invalid_request());
} }
let signature = Signature::new(&signature_vec); let signature = Signature::new(&signature_vec);
meta.request_processor.get_signature_status(signature) meta.request_processor
.get_signature_status(signature)
.map(|res| res.is_ok())
} }
fn get_account_info(&self, meta: Self::Metadata, id: String) -> Result<Account> { fn get_account_info(&self, meta: Self::Metadata, id: String) -> Result<Account> {
let pubkey_vec = bs58::decode(id) let pubkey_vec = bs58::decode(id)
@ -174,7 +177,7 @@ impl RpcSol for RpcSolImpl {
.get_signature_status(signature) .get_signature_status(signature)
.map_err(|_| Error::internal_error())?; .map_err(|_| Error::internal_error())?;
if signature_status { if signature_status.is_ok() {
return Ok(bs58::encode(signature).into_string()); return Ok(bs58::encode(signature).into_string());
} else if now.elapsed().as_secs() > 5 { } else if now.elapsed().as_secs() > 5 {
return Err(Error::internal_error()); return Err(Error::internal_error());
@ -224,8 +227,8 @@ impl JsonRpcRequestProcessor {
let id = self.bank.last_id(); let id = self.bank.last_id();
Ok(bs58::encode(id).into_string()) Ok(bs58::encode(id).into_string())
} }
fn get_signature_status(&self, signature: Signature) -> Result<bool> { fn get_signature_status(&self, signature: Signature) -> Result<result::Result<(), BankError>> {
Ok(self.bank.has_signature(&signature)) Ok(self.bank.get_signature_status(&signature))
} }
fn get_transaction_count(&self) -> Result<u64> { fn get_transaction_count(&self) -> Result<u64> {
Ok(self.bank.transaction_count() as u64) Ok(self.bank.transaction_count() as u64)