Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Verify sender's balance before importing transaction to queue #746

Merged
merged 14 commits into from
Mar 17, 2016
9 changes: 8 additions & 1 deletion ethcore/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ pub enum TransactionError {
/// Minimal expected gas price
minimal: U256,
/// Transaction gas price
got: U256
got: U256,
},
/// Sender doesn't have enough funds to pay for this transaction
InsufficientBalance {
/// Senders balance
balance: U256,
/// Transaction cost
cost: U256,
},
/// Transaction's gas limit (aka gas) is invalid.
InvalidGasLimit(OutOfBounds<U256>),
Expand Down
8 changes: 4 additions & 4 deletions miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ extern crate rayon;
mod miner;
mod transaction_queue;

pub use transaction_queue::TransactionQueue;
pub use transaction_queue::{TransactionQueue, AccountDetails};
pub use miner::{Miner};

use std::sync::Mutex;
use util::{H256, U256, Address, Bytes};
use util::{H256, Address, Bytes};
use ethcore::client::{BlockChainClient};
use ethcore::block::{ClosedBlock};
use ethcore::error::{Error};
Expand All @@ -79,8 +79,8 @@ pub trait MinerService : Send + Sync {
fn status(&self) -> MinerStatus;

/// Imports transactions to transaction queue.
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_nonce: T) -> Result<(), Error>
where T: Fn(&Address) -> U256;
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error>
where T: Fn(&Address) -> AccountDetails;

/// Returns hashes of transactions currently in pending
fn pending_transactions_hashes(&self) -> Vec<H256>;
Expand Down
52 changes: 35 additions & 17 deletions miner/src/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ use rayon::prelude::*;
use std::sync::{Mutex, RwLock, Arc};
use std::sync::atomic;
use std::sync::atomic::AtomicBool;
use std::collections::HashSet;

use util::{H256, U256, Address, Bytes, Uint};
use ethcore::views::{BlockView};
use ethcore::client::{BlockChainClient, BlockId};
use ethcore::block::{ClosedBlock};
use ethcore::error::{Error};
use ethcore::transaction::SignedTransaction;
use super::{MinerService, MinerStatus, TransactionQueue};
use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails};

/// Keeps track of transactions using priority queue and holds currently mined block.
pub struct Miner {
Expand Down Expand Up @@ -71,7 +72,7 @@ impl Miner {

/// Get the extra_data that we will seal blocks wuth.
fn gas_floor_target(&self) -> U256 {
self.gas_floor_target.read().unwrap().clone()
*self.gas_floor_target.read().unwrap()
}

/// Set the author that we will seal blocks as.
Expand Down Expand Up @@ -110,10 +111,10 @@ impl MinerService for Miner {
}
}

fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_nonce: T) -> Result<(), Error>
where T: Fn(&Address) -> U256 {
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error>
where T: Fn(&Address) -> AccountDetails {
let mut transaction_queue = self.transaction_queue.lock().unwrap();
transaction_queue.add_all(transactions, fetch_nonce)
transaction_queue.add_all(transactions, fetch_account)
}

fn pending_transactions_hashes(&self) -> Vec<H256> {
Expand Down Expand Up @@ -174,28 +175,45 @@ impl MinerService for Miner {
let block = BlockView::new(&block);
block.transactions()
}

{
let in_chain = vec![imported, enacted, invalid];
let in_chain = in_chain
.par_iter()
.flat_map(|h| h.par_iter().map(|h| fetch_transactions(chain, h)));
let out_of_chain = retracted
.par_iter()
.map(|h| fetch_transactions(chain, h));

in_chain.for_each(|txs| {
let mut transaction_queue = self.transaction_queue.lock().unwrap();
let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
transaction_queue.remove_all(&hashes, |a| chain.nonce(a));
});
out_of_chain.for_each(|txs| {
// populate sender
for tx in &txs {
let _sender = tx.sender();
}
let mut transaction_queue = self.transaction_queue.lock().unwrap();
let _ = transaction_queue.add_all(txs, |a| chain.nonce(a));
let _ = transaction_queue.add_all(txs, |a| AccountDetails {
nonce: chain.nonce(a),
balance: chain.balance(a)
});
});
}
// First import all transactions and after that remove old ones
{
let in_chain = {
let mut in_chain = HashSet::new();
in_chain.extend(imported);
in_chain.extend(enacted);
in_chain.extend(invalid);
in_chain
.into_iter()
.collect::<Vec<H256>>()
};

let in_chain = in_chain
.par_iter()
.map(|h: &H256| fetch_transactions(chain, h));

in_chain.for_each(|txs| {
let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
let mut transaction_queue = self.transaction_queue.lock().unwrap();
transaction_queue.remove_all(&hashes, |a| AccountDetails {
nonce: chain.nonce(a),
balance: chain.balance(a)
});
});
}

Expand Down