Merge pull request #3865 from ethcore/tx-block

Delayed transactions
This commit is contained in:
Gav Wood
2016-12-16 20:28:18 +01:00
committed by GitHub
35 changed files with 478 additions and 279 deletions

View File

@@ -24,7 +24,7 @@ use ethcore::service::ClientIoMessage;
use ethcore::block_import_error::BlockImportError;
use ethcore::block_status::BlockStatus;
use ethcore::verification::queue::{HeaderQueue, QueueInfo};
use ethcore::transaction::SignedTransaction;
use ethcore::transaction::{SignedTransaction, PendingTransaction};
use ethcore::blockchain_info::BlockChainInfo;
use io::IoChannel;
@@ -114,7 +114,7 @@ impl Provider for Client {
Vec::new()
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
fn ready_transactions(&self) -> Vec<PendingTransaction> {
Vec::new()
}
}
}

View File

@@ -20,7 +20,7 @@
use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
use ethcore::ids::BlockId;
use ethcore::transaction::SignedTransaction;
use ethcore::transaction::PendingTransaction;
use network::{PeerId, NodeId};
use net::buffer_flow::FlowParams;
@@ -169,8 +169,8 @@ impl Provider for TestProvider {
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.0.client.pending_transactions()
fn ready_transactions(&self) -> Vec<PendingTransaction> {
self.0.client.ready_transactions()
}
}

View File

@@ -19,7 +19,7 @@
use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
use ethcore::transaction::SignedTransaction;
use ethcore::transaction::PendingTransaction;
use ethcore::ids::BlockId;
use util::{Bytes, H256};
@@ -79,7 +79,7 @@ pub trait Provider: Send + Sync {
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes>;
/// Provide pending transactions.
fn pending_transactions(&self) -> Vec<SignedTransaction>;
fn ready_transactions(&self) -> Vec<PendingTransaction>;
}
// Implementation of a light client data provider for a client.
@@ -178,7 +178,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
BlockChainClient::pending_transactions(self)
fn ready_transactions(&self) -> Vec<PendingTransaction> {
BlockChainClient::ready_transactions(self)
}
}
}

View File

@@ -44,7 +44,7 @@ use env_info::LastHashes;
use verification;
use verification::{PreverifiedBlock, Verifier};
use block::*;
use transaction::{LocalizedTransaction, SignedTransaction, Transaction, Action};
use transaction::{LocalizedTransaction, SignedTransaction, Transaction, PendingTransaction, Action};
use blockchain::extras::TransactionAddress;
use types::filter::Filter;
use types::mode::Mode as IpcMode;
@@ -1334,8 +1334,8 @@ impl BlockChainClient for Client {
}
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.pending_transactions(self.chain.read().best_block_number())
fn ready_transactions(&self) -> Vec<PendingTransaction> {
self.miner.ready_transactions(self.chain.read().best_block_number())
}
fn queue_consensus_message(&self, message: Bytes) {

View File

@@ -21,7 +21,7 @@ use util::*;
use rlp::*;
use ethkey::{Generator, Random};
use devtools::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, PendingTransaction, Action};
use blockchain::TreeRoute;
use client::{
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId,
@@ -688,8 +688,8 @@ impl BlockChainClient for TestBlockChainClient {
fn broadcast_consensus_message(&self, _message: Bytes) {}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.pending_transactions(self.chain_info().best_block_number)
fn ready_transactions(&self) -> Vec<PendingTransaction> {
self.miner.ready_transactions(self.chain_info().best_block_number)
}
fn signing_network_id(&self) -> Option<u64> { None }

View File

@@ -21,7 +21,7 @@ use blockchain::TreeRoute;
use verification::queue::QueueInfo as BlockQueueInfo;
use block::{OpenBlock, SealedBlock};
use header::{BlockNumber};
use transaction::{LocalizedTransaction, SignedTransaction};
use transaction::{LocalizedTransaction, SignedTransaction, PendingTransaction};
use log_entry::LocalizedLogEntry;
use filter::Filter;
use views::{BlockView};
@@ -211,8 +211,8 @@ pub trait BlockChainClient : Sync + Send {
/// Used by PoA to communicate with peers.
fn broadcast_consensus_message(&self, message: Bytes);
/// list all transactions
fn pending_transactions(&self) -> Vec<SignedTransaction>;
/// List all transactions that are allowed into the next block.
fn ready_transactions(&self) -> Vec<PendingTransaction>;
/// Sorted list of transaction gas prices from at least last sample_size blocks.
fn gas_price_corpus(&self, sample_size: usize) -> Vec<U256> {

View File

@@ -115,7 +115,7 @@ impl BanningTransactionQueue {
}
}
}
self.queue.add(transaction, TransactionOrigin::External, account_details, gas_estimator)
self.queue.add(transaction, TransactionOrigin::External, None, account_details, gas_estimator)
}
/// Ban transaction with given hash.
@@ -263,7 +263,7 @@ mod tests {
let mut txq = queue();
// when
txq.queue().add(tx, TransactionOrigin::External, &default_account_details, &gas_required).unwrap();
txq.queue().add(tx, TransactionOrigin::External, None, &default_account_details, &gas_required).unwrap();
// then
// should also deref to queue

View File

@@ -28,7 +28,7 @@ use client::TransactionImportResult;
use executive::contract_address;
use block::{ClosedBlock, IsBlock, Block};
use error::*;
use transaction::{Action, SignedTransaction};
use transaction::{Action, SignedTransaction, PendingTransaction};
use receipt::{Receipt, RichReceipt};
use spec::Spec;
use engines::{Engine, Seal};
@@ -320,11 +320,12 @@ impl Miner {
}
let _timer = PerfTimer::new("prepare_block");
let chain_info = chain.chain_info();
let (transactions, mut open_block, original_work_hash) = {
let transactions = {self.transaction_queue.lock().top_transactions()};
let transactions = {self.transaction_queue.lock().top_transactions_at(chain_info.best_block_number)};
let mut sealing_work = self.sealing_work.lock();
let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().fields().header.hash());
let best_hash = chain.best_block_header().sha3();
let best_hash = chain_info.best_block_hash;
/*
// check to see if last ClosedBlock in would_seals is actually same parent block.
// if so
@@ -577,8 +578,14 @@ impl Miner {
prepare_new
}
fn add_transactions_to_queue(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, default_origin: TransactionOrigin, transaction_queue: &mut BanningTransactionQueue) ->
Vec<Result<TransactionImportResult, Error>> {
fn add_transactions_to_queue(
&self,
chain: &MiningBlockChainClient,
transactions: Vec<SignedTransaction>,
default_origin: TransactionOrigin,
min_block: Option<BlockNumber>,
transaction_queue: &mut BanningTransactionQueue)
-> Vec<Result<TransactionImportResult, Error>> {
let fetch_account = |a: &Address| AccountDetails {
nonce: chain.latest_nonce(a),
@@ -613,7 +620,7 @@ impl Miner {
match origin {
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
transaction_queue.add(tx, origin, &fetch_account, &gas_required)
transaction_queue.add(tx, origin, min_block, &fetch_account, &gas_required)
},
TransactionOrigin::External => {
transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required)
@@ -839,7 +846,7 @@ impl MinerService for Miner {
let results = {
let mut transaction_queue = self.transaction_queue.lock();
self.add_transactions_to_queue(
chain, transactions, TransactionOrigin::External, &mut transaction_queue
chain, transactions, TransactionOrigin::External, None, &mut transaction_queue
)
};
@@ -857,17 +864,17 @@ impl MinerService for Miner {
fn import_own_transaction(
&self,
chain: &MiningBlockChainClient,
transaction: SignedTransaction,
pending: PendingTransaction,
) -> Result<TransactionImportResult, Error> {
let hash = transaction.hash();
trace!(target: "own_tx", "Importing transaction: {:?}", transaction);
let hash = pending.transaction.hash();
trace!(target: "own_tx", "Importing transaction: {:?}", pending);
let imported = {
// Be sure to release the lock before we call prepare_work_sealing
let mut transaction_queue = self.transaction_queue.lock();
let import = self.add_transactions_to_queue(
chain, vec![transaction], TransactionOrigin::Local, &mut transaction_queue
chain, vec![pending.transaction], TransactionOrigin::Local, pending.min_block, &mut transaction_queue
).pop().expect("one result returned per added transaction; one added => one result; qed");
match import {
@@ -902,9 +909,9 @@ impl MinerService for Miner {
imported
}
fn all_transactions(&self) -> Vec<SignedTransaction> {
fn pending_transactions(&self) -> Vec<PendingTransaction> {
let queue = self.transaction_queue.lock();
queue.top_transactions()
queue.pending_transactions(BlockNumber::max_value())
}
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
@@ -915,22 +922,26 @@ impl MinerService for Miner {
.collect()
}
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction> {
fn future_transactions(&self) -> Vec<PendingTransaction> {
self.transaction_queue.lock().future_transactions()
}
fn ready_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction> {
let queue = self.transaction_queue.lock();
match self.options.pending_set {
PendingSet::AlwaysQueue => queue.top_transactions(),
PendingSet::AlwaysQueue => queue.pending_transactions(best_block),
PendingSet::SealingOrElseQueue => {
self.from_pending_block(
best_block,
|| queue.top_transactions(),
|sealing| sealing.transactions().to_owned()
|| queue.pending_transactions(best_block),
|sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
)
},
PendingSet::AlwaysSealing => {
self.from_pending_block(
best_block,
|| vec![],
|sealing| sealing.transactions().to_owned()
|sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
)
},
}
@@ -1126,7 +1137,7 @@ impl MinerService for Miner {
}).for_each(|txs| {
let mut transaction_queue = self.transaction_queue.lock();
let _ = self.add_transactions_to_queue(
chain, txs, TransactionOrigin::RetractedBlock, &mut transaction_queue
chain, txs, TransactionOrigin::RetractedBlock, None, &mut transaction_queue
);
});
}
@@ -1159,7 +1170,7 @@ mod tests {
use ethkey::{Generator, Random};
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult};
use header::BlockNumber;
use types::transaction::{Transaction, SignedTransaction, Action};
use types::transaction::{Transaction, SignedTransaction, PendingTransaction, Action};
use spec::Spec;
use tests::helpers::{generate_dummy_client};
@@ -1238,12 +1249,12 @@ mod tests {
let transaction = transaction();
let best_block = 0;
// when
let res = miner.import_own_transaction(&client, transaction);
let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None));
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1);
assert_eq!(miner.pending_transactions(best_block).len(), 1);
assert_eq!(miner.pending_transactions().len(), 1);
assert_eq!(miner.ready_transactions(best_block).len(), 1);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1);
assert_eq!(miner.pending_receipts(best_block).len(), 1);
// This method will let us know if pending block was created (before calling that method)
@@ -1258,12 +1269,12 @@ mod tests {
let transaction = transaction();
let best_block = 10;
// when
let res = miner.import_own_transaction(&client, transaction);
let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None));
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1);
assert_eq!(miner.pending_transactions(best_block).len(), 0);
assert_eq!(miner.pending_transactions().len(), 1);
assert_eq!(miner.ready_transactions(best_block).len(), 0);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
assert_eq!(miner.pending_receipts(best_block).len(), 0);
}
@@ -1280,9 +1291,9 @@ mod tests {
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1);
assert_eq!(miner.pending_transactions().len(), 1);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
assert_eq!(miner.pending_transactions(best_block).len(), 0);
assert_eq!(miner.ready_transactions(best_block).len(), 0);
assert_eq!(miner.pending_receipts(best_block).len(), 0);
// This method will let us know if pending block was created (before calling that method)
assert!(miner.prepare_work_sealing(&client));
@@ -1315,7 +1326,7 @@ mod tests {
assert!(miner.pending_block().is_none());
assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber);
assert_eq!(miner.import_own_transaction(client, transaction()).unwrap(), TransactionImportResult::Current);
assert_eq!(miner.import_own_transaction(client, PendingTransaction::new(transaction(), None)).unwrap(), TransactionImportResult::Current);
miner.update_sealing(client);
client.flush_queue();

View File

@@ -62,7 +62,7 @@ use block::ClosedBlock;
use header::BlockNumber;
use receipt::{RichReceipt, Receipt};
use error::{Error, CallError};
use transaction::SignedTransaction;
use transaction::{SignedTransaction, PendingTransaction};
/// Miner client API
pub trait MinerService : Send + Sync {
@@ -118,7 +118,7 @@ pub trait MinerService : Send + Sync {
Vec<Result<TransactionImportResult, Error>>;
/// Imports own (node owner) transaction to queue.
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction) ->
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: PendingTransaction) ->
Result<TransactionImportResult, Error>;
/// Returns hashes of transactions currently in pending
@@ -144,11 +144,14 @@ pub trait MinerService : Send + Sync {
/// Query pending transactions for hash.
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction>;
/// Get a list of all transactions.
fn all_transactions(&self) -> Vec<SignedTransaction>;
/// Get a list of all pending transactions in the queue.
fn pending_transactions(&self) -> Vec<PendingTransaction>;
/// Get a list of all pending transactions.
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction>;
/// Get a list of all transactions that can go into the given block.
fn ready_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction>;
/// Get a list of all future transactions.
fn future_transactions(&self) -> Vec<PendingTransaction>;
/// Get a list of local transactions with statuses.
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus>;

View File

@@ -51,8 +51,8 @@
//! let gas_estimator = |_tx: &SignedTransaction| 2.into();
//!
//! let mut txq = TransactionQueue::default();
//! txq.add(st2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
//! txq.add(st1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
//! txq.add(st2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
//! txq.add(st1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
//!
//! // Check status
//! assert_eq!(txq.status().pending, 2);
@@ -94,6 +94,7 @@ use util::table::Table;
use transaction::*;
use error::{Error, TransactionError};
use client::TransactionImportResult;
use header::BlockNumber;
use miner::local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus};
/// Transaction origin
@@ -253,18 +254,21 @@ impl Ord for TransactionOrder {
/// Verified transaction (with sender)
#[derive(Debug)]
struct VerifiedTransaction {
/// Transaction
/// Transaction.
transaction: SignedTransaction,
/// transaction origin
/// Transaction origin.
origin: TransactionOrigin,
/// Delay until specifid block.
min_block: Option<BlockNumber>,
}
impl VerifiedTransaction {
fn new(transaction: SignedTransaction, origin: TransactionOrigin) -> Result<Self, Error> {
fn new(transaction: SignedTransaction, origin: TransactionOrigin, min_block: Option<BlockNumber>) -> Result<Self, Error> {
try!(transaction.sender());
Ok(VerifiedTransaction {
transaction: transaction,
origin: origin,
min_block: min_block,
})
}
@@ -620,6 +624,7 @@ impl TransactionQueue {
&mut self,
tx: SignedTransaction,
origin: TransactionOrigin,
min_block: Option<BlockNumber>,
fetch_account: &F,
gas_estimator: &G,
) -> Result<TransactionImportResult, Error> where
@@ -630,7 +635,7 @@ impl TransactionQueue {
let hash = tx.hash();
let cloned_tx = tx.clone();
let result = self.add_internal(tx, origin, fetch_account, gas_estimator);
let result = self.add_internal(tx, origin, min_block, fetch_account, gas_estimator);
match result {
Ok(TransactionImportResult::Current) => {
self.local_transactions.mark_pending(hash);
@@ -651,7 +656,7 @@ impl TransactionQueue {
}
result
} else {
self.add_internal(tx, origin, fetch_account, gas_estimator)
self.add_internal(tx, origin, min_block, fetch_account, gas_estimator)
}
}
@@ -660,6 +665,7 @@ impl TransactionQueue {
&mut self,
tx: SignedTransaction,
origin: TransactionOrigin,
min_block: Option<BlockNumber>,
fetch_account: &F,
gas_estimator: &G,
) -> Result<TransactionImportResult, Error> where
@@ -728,7 +734,7 @@ impl TransactionQueue {
// Verify signature
try!(tx.check_low_s());
let vtx = try!(VerifiedTransaction::new(tx, origin));
let vtx = try!(VerifiedTransaction::new(tx, origin, min_block));
let client_account = fetch_account(&vtx.sender());
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
@@ -968,10 +974,48 @@ impl TransactionQueue {
/// Returns top transactions from the queue ordered by priority.
pub fn top_transactions(&self) -> Vec<SignedTransaction> {
self.current.by_priority
self.top_transactions_at(BlockNumber::max_value())
}
fn filter_pending_transaction<F>(&self, best_block: BlockNumber, mut f: F)
where F: FnMut(&VerifiedTransaction) {
let mut delayed = HashSet::new();
for t in self.current.by_priority.iter() {
let tx = self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`");
let sender = tx.sender();
if delayed.contains(&sender) {
continue;
}
if tx.min_block.unwrap_or(0) > best_block {
delayed.insert(sender);
continue;
}
f(&tx);
}
}
/// Returns top transactions from the queue ordered by priority.
pub fn top_transactions_at(&self, best_block: BlockNumber) -> Vec<SignedTransaction> {
let mut r = Vec::new();
self.filter_pending_transaction(best_block, |tx| r.push(tx.transaction.clone()));
r
}
/// Return all ready transactions.
pub fn pending_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction> {
let mut r = Vec::new();
self.filter_pending_transaction(best_block, |tx| r.push(PendingTransaction::new(tx.transaction.clone(), tx.min_block)));
r
}
/// Return all ready transactions.
pub fn future_transactions(&self) -> Vec<PendingTransaction> {
self.future.by_priority
.iter()
.map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"))
.map(|t| t.transaction.clone())
.map(|t| PendingTransaction { transaction: t.transaction.clone(), min_block: t.min_block })
.collect()
}
@@ -980,15 +1024,6 @@ impl TransactionQueue {
self.local_transactions.all_transactions()
}
#[cfg(test)]
fn future_transactions(&self) -> Vec<SignedTransaction> {
self.future.by_priority
.iter()
.map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"))
.map(|t| t.transaction.clone())
.collect()
}
/// Returns hashes of all transactions from current, ordered by priority.
pub fn pending_hashes(&self) -> Vec<H256> {
self.current.by_priority
@@ -1353,14 +1388,14 @@ mod test {
let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into());
let sender = tx1.sender().unwrap();
let nonce = tx1.nonce;
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2);
assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into()));
// when
let tx = new_tx(123.into(), 1.into());
let res = txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
// No longer the case as we don't even consider a transaction that isn't above a full
@@ -1392,12 +1427,12 @@ mod test {
gas_limit: !U256::zero(),
};
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External).unwrap();
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
let mut by_hash = {
let mut x = HashMap::new();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External).unwrap();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
x.insert(tx1.hash(), tx1);
x.insert(tx2.hash(), tx2);
x
@@ -1435,12 +1470,12 @@ mod test {
// Create two transactions with same nonce
// (same hash)
let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into());
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External).unwrap();
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
let by_hash = {
let mut x = HashMap::new();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External).unwrap();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
x.insert(tx1.hash(), tx1);
x.insert(tx2.hash(), tx2);
x
@@ -1482,10 +1517,10 @@ mod test {
gas_limit: !U256::zero(),
};
let tx = new_tx_default();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None).unwrap();
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none());
let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External).unwrap();
let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External, None).unwrap();
let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some());
}
@@ -1502,7 +1537,7 @@ mod test {
assert_eq!(set.gas_price_entry_limit(), 0.into());
let tx = new_tx_default();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None).unwrap();
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none());
assert_eq!(set.gas_price_entry_limit(), 2.into());
@@ -1517,12 +1552,12 @@ mod test {
!U256::zero() };
// First insert one transaction to future
let res = txq.add(tx, TransactionOrigin::External, &prev_nonce, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, None, &prev_nonce, &gas_estimator);
assert_eq!(res.unwrap(), TransactionImportResult::Future);
assert_eq!(txq.status().future, 1);
// now import second transaction to current
let res = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// and then there should be only one transaction in current (the one with higher gas_price)
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@@ -1542,12 +1577,12 @@ mod test {
!U256::zero() };
// First insert one transaction to future
let res = txq.add(tx.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator);
let res = txq.add(tx.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator);
assert_eq!(res.unwrap(), TransactionImportResult::Future);
assert_eq!(txq.status().future, 1);
// now import second transaction to current
let res = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@@ -1566,7 +1601,7 @@ mod test {
let tx = new_tx_default();
// when
let res = txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@@ -1585,10 +1620,10 @@ mod test {
txq.set_minimal_gas_price(15.into());
// when
let res1 = txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res1 = txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@@ -1619,10 +1654,10 @@ mod test {
txq.set_minimal_gas_price(15.into());
// when
let res1 = txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res1 = txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@@ -1665,7 +1700,7 @@ mod test {
txq.set_gas_limit(limit);
// when
let res = txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded {
@@ -1689,7 +1724,7 @@ mod test {
};
// when
let res = txq.add(tx, TransactionOrigin::External, &account, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, None, &account, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientBalance {
@@ -1709,7 +1744,7 @@ mod test {
txq.set_minimal_gas_price(tx.gas_price + U256::one());
// when
let res = txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientGasPrice {
@@ -1729,7 +1764,7 @@ mod test {
txq.set_minimal_gas_price(tx.gas_price + U256::one());
// when
let res = txq.add(tx, TransactionOrigin::Local, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@@ -1759,7 +1794,7 @@ mod test {
rlp::decode(s.as_raw())
};
// when
let res = txq.add(stx, TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(stx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
assert!(res.is_err());
@@ -1773,8 +1808,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@@ -1793,9 +1828,9 @@ mod test {
// when
// first insert the one with higher gas price
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then the one with lower gas price, but local
txq.add(tx.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@@ -1812,15 +1847,15 @@ mod test {
// the second one has same nonce but higher `gas_price`
let (_, tx0) = new_similar_tx_pair();
txq.add(tx0.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx0.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// the one with higher gas price is first
assert_eq!(txq.top_transactions()[0], tx0);
assert_eq!(txq.top_transactions()[1], tx1);
// when
// insert second as local
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then
// the order should be updated
@@ -1839,9 +1874,9 @@ mod test {
// when
// first insert local one with higher gas price
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then the one with lower gas price, but from retracted block
txq.add(tx.clone(), TransactionOrigin::RetractedBlock, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::RetractedBlock, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@@ -1857,8 +1892,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@@ -1877,10 +1912,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything
txq.add(txa.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
txq.add(txa.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 4);
@@ -1889,10 +1924,10 @@ mod test {
// then
let top = txq.future_transactions();
assert_eq!(top[0], txa);
assert_eq!(top[1], txb);
assert_eq!(top[2], tx1);
assert_eq!(top[3], tx2);
assert_eq!(top[0].transaction, txa);
assert_eq!(top[1].transaction, txb);
assert_eq!(top[2].transaction, tx1);
assert_eq!(top[3].transaction, tx2);
assert_eq!(top.len(), 4);
}
@@ -1905,10 +1940,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything
txq.add(txa.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(txa.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
let top = txq.top_transactions();
assert_eq!(top[0], tx1);
@@ -1938,10 +1973,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything
txq.add(txa.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(txa.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let top = txq.top_transactions();
assert_eq!(top[0], tx1);
@@ -1970,8 +2005,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.pending_hashes();
@@ -1988,8 +2023,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(2.into(), 0.into());
// when
let res1 = txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
let res1 = txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
assert_eq!(res1, TransactionImportResult::Current);
@@ -2002,6 +2037,26 @@ mod test {
assert_eq!(top[0], tx);
}
#[test]
fn should_handle_min_block() {
// given
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
let res1 = txq.add(tx.clone(), TransactionOrigin::External, Some(1), &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
assert_eq!(res1, TransactionImportResult::Current);
assert_eq!(res2, TransactionImportResult::Current);
let top = txq.top_transactions_at(0);
assert_eq!(top.len(), 0);
let top = txq.top_transactions_at(1);
assert_eq!(top.len(), 2);
}
#[test]
fn should_correctly_update_futures_when_removing() {
// given
@@ -2012,8 +2067,8 @@ mod test {
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 2);
// when
@@ -2035,13 +2090,13 @@ mod test {
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None);
let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None);
txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 1);
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
// when
txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@@ -2057,8 +2112,8 @@ mod test {
// given
let mut txq2 = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(3.into(), 0.into());
txq2.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq2.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq2.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq2.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq2.status().pending, 1);
assert_eq!(txq2.status().future, 1);
@@ -2079,10 +2134,10 @@ mod test {
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx3 = new_tx_default();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 3);
// when
@@ -2101,8 +2156,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// add
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let stats = txq.status();
assert_eq!(stats.pending, 2);
@@ -2121,11 +2176,11 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let sender = tx.sender().unwrap();
let nonce = tx.nonce;
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 1);
// when
let res = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then
let t = txq.top_transactions();
@@ -2142,14 +2197,14 @@ mod test {
txq.current.set_limit(10);
let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into());
let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into());
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2);
// when
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx4.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
assert_eq!(txq.status().future, 1);
@@ -2160,11 +2215,11 @@ mod test {
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero());
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// limited by gas
txq.add(tx4.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap_err();
txq.add(tx4.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap_err();
assert_eq!(txq.status().pending, 2);
}
@@ -2174,12 +2229,12 @@ mod test {
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
let (tx5, _) = new_tx_pair_default(U256::from(1), U256::from(2));
txq.add(tx1.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// Not accepted because of limit
txq.add(tx5.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap_err();
txq.add(tx3.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx5.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap_err();
txq.add(tx3.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 4);
}
@@ -2191,7 +2246,7 @@ mod test {
let fetch_last_nonce = |_a: &Address| AccountDetails { nonce: last_nonce, balance: !U256::zero() };
// when
let res = txq.add(tx, TransactionOrigin::External, &fetch_last_nonce, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, None, &fetch_last_nonce, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::Old);
@@ -2207,12 +2262,12 @@ mod test {
balance: !U256::zero() };
let mut txq = TransactionQueue::default();
let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
assert_eq!(txq.status().pending, 0);
// when
let res = txq.add(tx2.clone(), TransactionOrigin::External, &nonce, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &nonce, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::AlreadyImported);
@@ -2226,15 +2281,15 @@ mod test {
// given
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2);
// when
txq.remove_invalid(&tx1.hash(), &default_account_details);
assert_eq!(txq.status().pending, 0);
assert_eq!(txq.status().future, 1);
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@@ -2248,10 +2303,10 @@ mod test {
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx3 = new_tx_default();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 3);
// when
@@ -2278,8 +2333,8 @@ mod test {
};
// when
txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@@ -2306,10 +2361,10 @@ mod test {
};
// when
txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx0, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx0, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@@ -2327,8 +2382,8 @@ mod test {
!U256::zero() };
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx1.clone(), TransactionOrigin::External, &previous_nonce, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &previous_nonce, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 2);
// when
@@ -2359,7 +2414,7 @@ mod test {
let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
// when
txq.add(tx, TransactionOrigin::External, &details, &gas_estimator).unwrap();
txq.add(tx, TransactionOrigin::External, None, &details, &gas_estimator).unwrap();
// then
assert_eq!(txq.last_nonce(&from), Some(nonce));
@@ -2374,7 +2429,7 @@ mod test {
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
// Insert first transaction
txq.add(tx1, TransactionOrigin::External, &details1, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap();
// when
txq.remove_all(tx2.sender().unwrap(), nonce2 + U256::one());
@@ -2394,9 +2449,9 @@ mod test {
// when
// Insert first transaction
assert_eq!(txq.add(tx1, TransactionOrigin::External, &details1, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.add(tx1, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Current);
// Second should go to future
assert_eq!(txq.add(tx2, TransactionOrigin::External, &details1, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx2, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Future);
// Now block is imported
txq.remove_all(sender, nonce2 - U256::from(1));
// tx2 should be not be promoted to current
@@ -2415,9 +2470,9 @@ mod test {
assert_eq!(txq.has_local_pending_transactions(), false);
// when
assert_eq!(txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.has_local_pending_transactions(), false);
assert_eq!(txq.add(tx2, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
// then
assert_eq!(txq.has_local_pending_transactions(), true);
@@ -2432,8 +2487,8 @@ mod test {
default_account_details(a).balance };
// when
assert_eq!(txq.add(tx2, TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx2, TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
// then
assert_eq!(txq.future.by_priority.len(), 1);
@@ -2458,14 +2513,14 @@ mod test {
(tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None))
};
let sender = tx1.sender().unwrap();
txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.future.by_priority.len(), 0);
assert_eq!(txq.current.by_priority.len(), 3);
// when
let res = txq.add(tx2_2, TransactionOrigin::Local, &default_account_details, &gas_estimator);
let res = txq.add(tx2_2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
// then
assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into());
@@ -2481,8 +2536,8 @@ mod test {
let high_gas = |_: &SignedTransaction| 100_001.into();
// when
let res1 = txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::Local, &default_account_details, &high_gas);
let res1 = txq.add(tx1, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &high_gas);
// then
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@@ -2502,10 +2557,10 @@ mod test {
let nonce1 = tx1.nonce;
// Insert all transactions
txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.top_transactions().len(), 4);
// when

View File

@@ -28,6 +28,9 @@ use rlp::{Rlp, View};
use spec::Spec;
use views::BlockView;
use util::stats::Histogram;
use ethkey::KeyPair;
use transaction::{PendingTransaction, Transaction, Action};
use miner::MinerService;
#[test]
fn imports_from_empty() {
@@ -284,3 +287,37 @@ fn change_history_size() {
let client = Client::new(config, &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap();
assert_eq!(client.state().balance(&address), 100.into());
}
#[test]
fn does_not_propagate_delayed_transactions() {
let key = KeyPair::from_secret("test".sha3()).unwrap();
let secret = key.secret();
let tx0 = PendingTransaction::new(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}.sign(secret, None), Some(2));
let tx1 = PendingTransaction::new(Transaction {
nonce: 1.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}.sign(secret, None), None);
let client_result = generate_dummy_client(1);
let client = client_result.reference();
client.miner().import_own_transaction(&**client, tx0).unwrap();
client.miner().import_own_transaction(&**client, tx1).unwrap();
assert_eq!(0, client.ready_transactions().len());
assert_eq!(2, client.miner().pending_transactions().len());
push_blocks_to_client(client, 53, 2, 2);
client.import_verified_blocks();
assert_eq!(2, client.ready_transactions().len());
assert_eq!(2, client.miner().pending_transactions().len());
}

View File

@@ -390,6 +390,34 @@ impl Deref for LocalizedTransaction {
}
}
/// Queued transaction with additional information.
#[derive(Debug, Clone, PartialEq, Eq, Binary)]
pub struct PendingTransaction {
/// Signed transaction data.
pub transaction: SignedTransaction,
/// To be activated at this block. `None` for immediately.
pub min_block: Option<BlockNumber>,
}
impl PendingTransaction {
/// Create a new pending transaction from signed transaction.
pub fn new(signed: SignedTransaction, min_block: Option<BlockNumber>) -> Self {
PendingTransaction {
transaction: signed,
min_block: min_block,
}
}
}
impl From<SignedTransaction> for PendingTransaction {
fn from(t: SignedTransaction) -> Self {
PendingTransaction {
transaction: t,
min_block: None,
}
}
}
#[test]
fn sender_test() {
let t: SignedTransaction = decode(&::rustc_serialize::hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());