Common error handling

This commit is contained in:
Tomasz Drwięga 2016-03-17 15:49:29 +01:00 committed by arkpar
parent 2aae862330
commit 808f959a94
6 changed files with 29 additions and 19 deletions

View File

@ -65,6 +65,10 @@ pub enum ExecutionError {
#[derive(Debug)] #[derive(Debug)]
/// Errors concerning transaction processing. /// Errors concerning transaction processing.
pub enum TransactionError { pub enum TransactionError {
/// Transaction is already imported to the queue
AlreadyImported,
/// Transaction is not valid anymore (state already has higher nonce)
Old,
/// Transaction's gas price is below threshold. /// Transaction's gas price is below threshold.
InsufficientGasPrice { InsufficientGasPrice {
/// Minimal expected gas price /// Minimal expected gas price

View File

@ -79,7 +79,7 @@ pub trait MinerService : Send + Sync {
fn status(&self) -> MinerStatus; fn status(&self) -> MinerStatus;
/// Imports transactions to transaction queue. /// Imports transactions to transaction queue.
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error> fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Vec<Result<(), Error>>
where T: Fn(&Address) -> AccountDetails; where T: Fn(&Address) -> AccountDetails;
/// Returns hashes of transactions currently in pending /// Returns hashes of transactions currently in pending

View File

@ -135,7 +135,7 @@ impl MinerService for Miner {
} }
} }
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error> fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Vec<Result<(), Error>>
where T: Fn(&Address) -> AccountDetails { where T: Fn(&Address) -> AccountDetails {
let mut transaction_queue = self.transaction_queue.lock().unwrap(); let mut transaction_queue = self.transaction_queue.lock().unwrap();
transaction_queue.add_all(transactions, fetch_account) transaction_queue.add_all(transactions, fetch_account)

View File

@ -335,12 +335,12 @@ impl TransactionQueue {
} }
/// Adds all signed transactions to queue to be verified and imported /// Adds all signed transactions to queue to be verified and imported
pub fn add_all<T>(&mut self, txs: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error> pub fn add_all<T>(&mut self, txs: Vec<SignedTransaction>, fetch_account: T) -> Vec<Result<(), Error>>
where T: Fn(&Address) -> AccountDetails { where T: Fn(&Address) -> AccountDetails {
for tx in txs.into_iter() {
try!(self.add(tx, &fetch_account)); txs.into_iter()
} .map(|tx| self.add(tx, &fetch_account))
Ok(()) .collect()
} }
/// Add signed transaction to queue to be verified and imported /// Add signed transaction to queue to be verified and imported
@ -387,8 +387,7 @@ impl TransactionQueue {
})); }));
} }
self.import_tx(vtx, account.nonce); self.import_tx(vtx, account.nonce).map_err(Error::Transaction)
Ok(())
} }
/// Removes all transactions identified by hashes given in slice /// Removes all transactions identified by hashes given in slice
@ -542,12 +541,14 @@ impl TransactionQueue {
/// ///
/// It ignores transactions that has already been imported (same `hash`) and replaces the transaction /// It ignores transactions that has already been imported (same `hash`) and replaces the transaction
/// iff `(address, nonce)` is the same but `gas_price` is higher. /// iff `(address, nonce)` is the same but `gas_price` is higher.
fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) { ///
/// Returns `true` when transaction was imported successfuly
fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) -> Result<(), TransactionError> {
if self.by_hash.get(&tx.hash()).is_some() { if self.by_hash.get(&tx.hash()).is_some() {
// Transaction is already imported. // Transaction is already imported.
trace!(target: "miner", "Dropping already imported transaction: {:?}", tx.hash()); trace!(target: "miner", "Dropping already imported transaction: {:?}", tx.hash());
return; return Err(TransactionError::AlreadyImported);
} }
@ -564,11 +565,11 @@ impl TransactionQueue {
// We have a gap - put to future // We have a gap - put to future
Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash); Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash);
self.future.enforce_limit(&mut self.by_hash); self.future.enforce_limit(&mut self.by_hash);
return; return Ok(());
} else if nonce < state_nonce { } else if nonce < state_nonce {
// Droping transaction // Droping transaction
trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce); trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
return; return Err(TransactionError::Old);
} }
Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash); Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash);
@ -578,6 +579,7 @@ impl TransactionQueue {
self.current.enforce_limit(&mut self.by_hash); self.current.enforce_limit(&mut self.by_hash);
trace!(target: "miner", "status: {:?}", self.status()); trace!(target: "miner", "status: {:?}", self.status());
Ok(())
} }
/// Replaces transaction in given set (could be `future` or `current`). /// Replaces transaction in given set (could be `future` or `current`).
@ -1010,7 +1012,7 @@ mod test {
let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() }; let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() };
// when // when
txq.add(tx, &fetch_last_nonce).unwrap(); txq.add(tx, &fetch_last_nonce).unwrap_err();
// then // then
let stats = txq.status(); let stats = txq.status();
@ -1030,7 +1032,7 @@ mod test {
assert_eq!(txq.status().pending, 0); assert_eq!(txq.status().pending, 0);
// when // when
txq.add(tx2.clone(), &nonce).unwrap(); txq.add(tx2.clone(), &nonce).unwrap_err();
// then // then
let stats = txq.status(); let stats = txq.status();

View File

@ -385,7 +385,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
nonce: client.nonce(a), nonce: client.nonce(a),
balance: client.balance(a), balance: client.balance(a),
}); });
match import { match import.into_iter().collect::<Result<Vec<_>, _>>() {
Ok(_) => to_value(&hash), Ok(_) => to_value(&hash),
Err(e) => { Err(e) => {
warn!("Error sending transaction: {:?}", e); warn!("Error sending transaction: {:?}", e);

View File

@ -951,9 +951,13 @@ impl ChainSync {
transactions.push(tx); transactions.push(tx);
} }
let chain = io.chain(); let chain = io.chain();
let fetch_nonce = |a: &Address| chain.nonce(a); let fetch_account = |a: &Address| AccountDetails {
let res = self.miner.import_transactions(transactions, fetch_nonce); nonce: chain.nonce(a),
if res.is_ok() { balance: chain.balance(a),
};
let res = self.miner.import_transactions(transactions, fetch_account);
let any_transaction_imported = res.into_iter().any(|r| r.is_ok());
if any_transaction_imported {
self.miner.update_sealing(io.chain()); self.miner.update_sealing(io.chain());
} }
Ok(()) Ok(())