Delayed transactions
This commit is contained in:
parent
339b889ac4
commit
2952ea1b85
@ -24,7 +24,7 @@ use ethcore::service::ClientIoMessage;
|
|||||||
use ethcore::block_import_error::BlockImportError;
|
use ethcore::block_import_error::BlockImportError;
|
||||||
use ethcore::block_status::BlockStatus;
|
use ethcore::block_status::BlockStatus;
|
||||||
use ethcore::verification::queue::{HeaderQueue, QueueInfo};
|
use ethcore::verification::queue::{HeaderQueue, QueueInfo};
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::{SignedTransaction, PendingTransaction};
|
||||||
use ethcore::blockchain_info::BlockChainInfo;
|
use ethcore::blockchain_info::BlockChainInfo;
|
||||||
|
|
||||||
use io::IoChannel;
|
use io::IoChannel;
|
||||||
@ -114,7 +114,7 @@ impl Provider for Client {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,7 +20,7 @@
|
|||||||
use ethcore::blockchain_info::BlockChainInfo;
|
use ethcore::blockchain_info::BlockChainInfo;
|
||||||
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
|
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
|
||||||
use ethcore::ids::BlockId;
|
use ethcore::ids::BlockId;
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::PendingTransaction;
|
||||||
use network::{PeerId, NodeId};
|
use network::{PeerId, NodeId};
|
||||||
|
|
||||||
use net::buffer_flow::FlowParams;
|
use net::buffer_flow::FlowParams;
|
||||||
@ -169,7 +169,7 @@ impl Provider for TestProvider {
|
|||||||
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
|
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
self.0.client.pending_transactions()
|
self.0.client.pending_transactions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
use ethcore::blockchain_info::BlockChainInfo;
|
use ethcore::blockchain_info::BlockChainInfo;
|
||||||
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
|
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::PendingTransaction;
|
||||||
use ethcore::ids::BlockId;
|
use ethcore::ids::BlockId;
|
||||||
|
|
||||||
use util::{Bytes, H256};
|
use util::{Bytes, H256};
|
||||||
@ -79,7 +79,7 @@ pub trait Provider: Send + Sync {
|
|||||||
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes>;
|
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes>;
|
||||||
|
|
||||||
/// Provide pending transactions.
|
/// Provide pending transactions.
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction>;
|
fn pending_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of a light client data provider for a client.
|
// 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()
|
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
BlockChainClient::pending_transactions(self)
|
BlockChainClient::pending_transactions(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit 9028c4801fd39fbb71a9796979182549a24e81c8
|
Subproject commit e8f4624b7f1a15c63674eecf577c7ab76c3b16be
|
@ -42,7 +42,7 @@ use env_info::LastHashes;
|
|||||||
use verification;
|
use verification;
|
||||||
use verification::{PreverifiedBlock, Verifier};
|
use verification::{PreverifiedBlock, Verifier};
|
||||||
use block::*;
|
use block::*;
|
||||||
use transaction::{LocalizedTransaction, SignedTransaction, Action};
|
use transaction::{LocalizedTransaction, SignedTransaction, PendingTransaction, Action};
|
||||||
use blockchain::extras::TransactionAddress;
|
use blockchain::extras::TransactionAddress;
|
||||||
use types::filter::Filter;
|
use types::filter::Filter;
|
||||||
use types::mode::Mode as IpcMode;
|
use types::mode::Mode as IpcMode;
|
||||||
@ -1286,7 +1286,7 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
self.miner.pending_transactions(self.chain.read().best_block_number())
|
self.miner.pending_transactions(self.chain.read().best_block_number())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ use util::*;
|
|||||||
use rlp::*;
|
use rlp::*;
|
||||||
use ethkey::{Generator, Random};
|
use ethkey::{Generator, Random};
|
||||||
use devtools::*;
|
use devtools::*;
|
||||||
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
|
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, PendingTransaction, Action};
|
||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use client::{
|
use client::{
|
||||||
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId,
|
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId,
|
||||||
@ -663,7 +663,7 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
self.miner.import_external_transactions(self, txs);
|
self.miner.import_external_transactions(self, txs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
self.miner.pending_transactions(self.chain_info().best_block_number)
|
self.miner.pending_transactions(self.chain_info().best_block_number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ use blockchain::TreeRoute;
|
|||||||
use verification::queue::QueueInfo as BlockQueueInfo;
|
use verification::queue::QueueInfo as BlockQueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock};
|
||||||
use header::{BlockNumber};
|
use header::{BlockNumber};
|
||||||
use transaction::{LocalizedTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, SignedTransaction, PendingTransaction};
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use views::{BlockView};
|
use views::{BlockView};
|
||||||
@ -203,7 +203,7 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
fn queue_transactions(&self, transactions: Vec<Bytes>, peer_id: usize);
|
fn queue_transactions(&self, transactions: Vec<Bytes>, peer_id: usize);
|
||||||
|
|
||||||
/// list all transactions
|
/// list all transactions
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction>;
|
fn pending_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
|
|
||||||
/// Sorted list of transaction gas prices from at least last sample_size blocks.
|
/// Sorted list of transaction gas prices from at least last sample_size blocks.
|
||||||
fn gas_price_corpus(&self, sample_size: usize) -> Vec<U256> {
|
fn gas_price_corpus(&self, sample_size: usize) -> Vec<U256> {
|
||||||
|
@ -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.
|
/// Ban transaction with given hash.
|
||||||
@ -263,7 +263,7 @@ mod tests {
|
|||||||
let mut txq = queue();
|
let mut txq = queue();
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
// should also deref to queue
|
// should also deref to queue
|
||||||
|
@ -28,7 +28,7 @@ use client::TransactionImportResult;
|
|||||||
use executive::contract_address;
|
use executive::contract_address;
|
||||||
use block::{ClosedBlock, SealedBlock, IsBlock, Block};
|
use block::{ClosedBlock, SealedBlock, IsBlock, Block};
|
||||||
use error::*;
|
use error::*;
|
||||||
use transaction::{Action, SignedTransaction};
|
use transaction::{Action, SignedTransaction, PendingTransaction};
|
||||||
use receipt::{Receipt, RichReceipt};
|
use receipt::{Receipt, RichReceipt};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
@ -320,11 +320,12 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let _timer = PerfTimer::new("prepare_block");
|
let _timer = PerfTimer::new("prepare_block");
|
||||||
|
let chain_info = chain.chain_info();
|
||||||
let (transactions, mut open_block, original_work_hash) = {
|
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 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 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.
|
// check to see if last ClosedBlock in would_seals is actually same parent block.
|
||||||
// if so
|
// if so
|
||||||
@ -568,8 +569,14 @@ impl Miner {
|
|||||||
prepare_new
|
prepare_new
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_transactions_to_queue(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, default_origin: TransactionOrigin, transaction_queue: &mut BanningTransactionQueue) ->
|
fn add_transactions_to_queue(
|
||||||
Vec<Result<TransactionImportResult, Error>> {
|
&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 {
|
let fetch_account = |a: &Address| AccountDetails {
|
||||||
nonce: chain.latest_nonce(a),
|
nonce: chain.latest_nonce(a),
|
||||||
@ -604,7 +611,7 @@ impl Miner {
|
|||||||
|
|
||||||
match origin {
|
match origin {
|
||||||
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
|
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 => {
|
TransactionOrigin::External => {
|
||||||
transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required)
|
transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required)
|
||||||
@ -830,7 +837,7 @@ impl MinerService for Miner {
|
|||||||
let results = {
|
let results = {
|
||||||
let mut transaction_queue = self.transaction_queue.lock();
|
let mut transaction_queue = self.transaction_queue.lock();
|
||||||
self.add_transactions_to_queue(
|
self.add_transactions_to_queue(
|
||||||
chain, transactions, TransactionOrigin::External, &mut transaction_queue
|
chain, transactions, TransactionOrigin::External, None, &mut transaction_queue
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -848,17 +855,17 @@ impl MinerService for Miner {
|
|||||||
fn import_own_transaction(
|
fn import_own_transaction(
|
||||||
&self,
|
&self,
|
||||||
chain: &MiningBlockChainClient,
|
chain: &MiningBlockChainClient,
|
||||||
transaction: SignedTransaction,
|
pending: PendingTransaction,
|
||||||
) -> Result<TransactionImportResult, Error> {
|
) -> Result<TransactionImportResult, Error> {
|
||||||
|
|
||||||
let hash = transaction.hash();
|
let hash = pending.transaction.hash();
|
||||||
trace!(target: "own_tx", "Importing transaction: {:?}", transaction);
|
trace!(target: "own_tx", "Importing transaction: {:?}", pending);
|
||||||
|
|
||||||
let imported = {
|
let imported = {
|
||||||
// Be sure to release the lock before we call prepare_work_sealing
|
// Be sure to release the lock before we call prepare_work_sealing
|
||||||
let mut transaction_queue = self.transaction_queue.lock();
|
let mut transaction_queue = self.transaction_queue.lock();
|
||||||
let import = self.add_transactions_to_queue(
|
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");
|
).pop().expect("one result returned per added transaction; one added => one result; qed");
|
||||||
|
|
||||||
match import {
|
match import {
|
||||||
@ -893,9 +900,9 @@ impl MinerService for Miner {
|
|||||||
imported
|
imported
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction> {
|
fn all_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
let queue = self.transaction_queue.lock();
|
let queue = self.transaction_queue.lock();
|
||||||
queue.top_transactions()
|
queue.pending_transactions(BlockNumber::max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
||||||
@ -906,22 +913,26 @@ impl MinerService for Miner {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction> {
|
fn future_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
|
self.transaction_queue.lock().future_transactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction> {
|
||||||
let queue = self.transaction_queue.lock();
|
let queue = self.transaction_queue.lock();
|
||||||
match self.options.pending_set {
|
match self.options.pending_set {
|
||||||
PendingSet::AlwaysQueue => queue.top_transactions(),
|
PendingSet::AlwaysQueue => queue.pending_transactions(best_block),
|
||||||
PendingSet::SealingOrElseQueue => {
|
PendingSet::SealingOrElseQueue => {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
best_block,
|
best_block,
|
||||||
|| queue.top_transactions(),
|
|| queue.pending_transactions(best_block),
|
||||||
|sealing| sealing.transactions().to_owned()
|
|sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
PendingSet::AlwaysSealing => {
|
PendingSet::AlwaysSealing => {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
best_block,
|
best_block,
|
||||||
|| vec![],
|
|| vec![],
|
||||||
|sealing| sealing.transactions().to_owned()
|
|sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1116,7 +1127,7 @@ impl MinerService for Miner {
|
|||||||
}).for_each(|txs| {
|
}).for_each(|txs| {
|
||||||
let mut transaction_queue = self.transaction_queue.lock();
|
let mut transaction_queue = self.transaction_queue.lock();
|
||||||
let _ = self.add_transactions_to_queue(
|
let _ = self.add_transactions_to_queue(
|
||||||
chain, txs, TransactionOrigin::RetractedBlock, &mut transaction_queue
|
chain, txs, TransactionOrigin::RetractedBlock, None, &mut transaction_queue
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1149,7 +1160,7 @@ mod tests {
|
|||||||
use ethkey::{Generator, Random};
|
use ethkey::{Generator, Random};
|
||||||
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult};
|
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult};
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use types::transaction::{Transaction, SignedTransaction, Action};
|
use types::transaction::{Transaction, SignedTransaction, PendingTransaction, Action};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use tests::helpers::{generate_dummy_client};
|
use tests::helpers::{generate_dummy_client};
|
||||||
|
|
||||||
@ -1228,7 +1239,7 @@ mod tests {
|
|||||||
let transaction = transaction();
|
let transaction = transaction();
|
||||||
let best_block = 0;
|
let best_block = 0;
|
||||||
// when
|
// when
|
||||||
let res = miner.import_own_transaction(&client, transaction);
|
let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1248,7 +1259,7 @@ mod tests {
|
|||||||
let transaction = transaction();
|
let transaction = transaction();
|
||||||
let best_block = 10;
|
let best_block = 10;
|
||||||
// when
|
// when
|
||||||
let res = miner.import_own_transaction(&client, transaction);
|
let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1305,7 +1316,7 @@ mod tests {
|
|||||||
assert!(miner.pending_block().is_none());
|
assert!(miner.pending_block().is_none());
|
||||||
assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber);
|
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);
|
miner.update_sealing(client);
|
||||||
client.flush_queue();
|
client.flush_queue();
|
||||||
|
@ -62,7 +62,7 @@ use block::ClosedBlock;
|
|||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use receipt::{RichReceipt, Receipt};
|
use receipt::{RichReceipt, Receipt};
|
||||||
use error::{Error, CallError};
|
use error::{Error, CallError};
|
||||||
use transaction::SignedTransaction;
|
use transaction::{SignedTransaction, PendingTransaction};
|
||||||
|
|
||||||
/// Miner client API
|
/// Miner client API
|
||||||
pub trait MinerService : Send + Sync {
|
pub trait MinerService : Send + Sync {
|
||||||
@ -118,7 +118,7 @@ pub trait MinerService : Send + Sync {
|
|||||||
Vec<Result<TransactionImportResult, Error>>;
|
Vec<Result<TransactionImportResult, Error>>;
|
||||||
|
|
||||||
/// Imports own (node owner) transaction to queue.
|
/// 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>;
|
Result<TransactionImportResult, Error>;
|
||||||
|
|
||||||
/// Returns hashes of transactions currently in pending
|
/// Returns hashes of transactions currently in pending
|
||||||
@ -144,11 +144,14 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Query pending transactions for hash.
|
/// Query pending transactions for hash.
|
||||||
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction>;
|
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction>;
|
||||||
|
|
||||||
/// Get a list of all transactions.
|
/// Get a list of all ready transactions in the queue.
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction>;
|
fn all_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
|
|
||||||
/// Get a list of all pending transactions.
|
/// Get a list of all pending transactions.
|
||||||
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction>;
|
fn pending_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.
|
/// Get a list of local transactions with statuses.
|
||||||
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus>;
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus>;
|
||||||
|
@ -51,8 +51,8 @@
|
|||||||
//! let gas_estimator = |_tx: &SignedTransaction| 2.into();
|
//! let gas_estimator = |_tx: &SignedTransaction| 2.into();
|
||||||
//!
|
//!
|
||||||
//! let mut txq = TransactionQueue::default();
|
//! let mut txq = TransactionQueue::default();
|
||||||
//! txq.add(st2.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, &default_account_details, &gas_estimator).unwrap();
|
//! txq.add(st1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
//!
|
//!
|
||||||
//! // Check status
|
//! // Check status
|
||||||
//! assert_eq!(txq.status().pending, 2);
|
//! assert_eq!(txq.status().pending, 2);
|
||||||
@ -94,6 +94,7 @@ use util::table::Table;
|
|||||||
use transaction::*;
|
use transaction::*;
|
||||||
use error::{Error, TransactionError};
|
use error::{Error, TransactionError};
|
||||||
use client::TransactionImportResult;
|
use client::TransactionImportResult;
|
||||||
|
use header::BlockNumber;
|
||||||
use miner::local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus};
|
use miner::local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus};
|
||||||
|
|
||||||
/// Transaction origin
|
/// Transaction origin
|
||||||
@ -253,18 +254,21 @@ impl Ord for TransactionOrder {
|
|||||||
/// Verified transaction (with sender)
|
/// Verified transaction (with sender)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct VerifiedTransaction {
|
struct VerifiedTransaction {
|
||||||
/// Transaction
|
/// Transaction.
|
||||||
transaction: SignedTransaction,
|
transaction: SignedTransaction,
|
||||||
/// transaction origin
|
/// Transaction origin.
|
||||||
origin: TransactionOrigin,
|
origin: TransactionOrigin,
|
||||||
|
/// Delay until specifid block.
|
||||||
|
min_block: Option<BlockNumber>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerifiedTransaction {
|
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());
|
try!(transaction.sender());
|
||||||
Ok(VerifiedTransaction {
|
Ok(VerifiedTransaction {
|
||||||
transaction: transaction,
|
transaction: transaction,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
|
min_block: min_block,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,6 +624,7 @@ impl TransactionQueue {
|
|||||||
&mut self,
|
&mut self,
|
||||||
tx: SignedTransaction,
|
tx: SignedTransaction,
|
||||||
origin: TransactionOrigin,
|
origin: TransactionOrigin,
|
||||||
|
min_block: Option<BlockNumber>,
|
||||||
fetch_account: &F,
|
fetch_account: &F,
|
||||||
gas_estimator: &G,
|
gas_estimator: &G,
|
||||||
) -> Result<TransactionImportResult, Error> where
|
) -> Result<TransactionImportResult, Error> where
|
||||||
@ -630,7 +635,7 @@ impl TransactionQueue {
|
|||||||
let hash = tx.hash();
|
let hash = tx.hash();
|
||||||
let cloned_tx = tx.clone();
|
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 {
|
match result {
|
||||||
Ok(TransactionImportResult::Current) => {
|
Ok(TransactionImportResult::Current) => {
|
||||||
self.local_transactions.mark_pending(hash);
|
self.local_transactions.mark_pending(hash);
|
||||||
@ -651,7 +656,7 @@ impl TransactionQueue {
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
} else {
|
} 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,
|
&mut self,
|
||||||
tx: SignedTransaction,
|
tx: SignedTransaction,
|
||||||
origin: TransactionOrigin,
|
origin: TransactionOrigin,
|
||||||
|
min_block: Option<BlockNumber>,
|
||||||
fetch_account: &F,
|
fetch_account: &F,
|
||||||
gas_estimator: &G,
|
gas_estimator: &G,
|
||||||
) -> Result<TransactionImportResult, Error> where
|
) -> Result<TransactionImportResult, Error> where
|
||||||
@ -728,7 +734,7 @@ impl TransactionQueue {
|
|||||||
// Verify signature
|
// Verify signature
|
||||||
try!(tx.check_low_s());
|
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 client_account = fetch_account(&vtx.sender());
|
||||||
|
|
||||||
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
|
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.
|
/// Returns top transactions from the queue ordered by priority.
|
||||||
pub fn top_transactions(&self) -> Vec<SignedTransaction> {
|
pub fn top_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
self.current.by_priority
|
self.top_transactions_at(BlockNumber::max_value())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_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.transaction.sender().expect("Queue only contains transactions with valid 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.collect_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.collect_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()
|
.iter()
|
||||||
.map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"))
|
.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()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -980,15 +1024,6 @@ impl TransactionQueue {
|
|||||||
self.local_transactions.all_transactions()
|
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.
|
/// Returns hashes of all transactions from current, ordered by priority.
|
||||||
pub fn pending_hashes(&self) -> Vec<H256> {
|
pub fn pending_hashes(&self) -> Vec<H256> {
|
||||||
self.current.by_priority
|
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 (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into());
|
||||||
let sender = tx1.sender().unwrap();
|
let sender = tx1.sender().unwrap();
|
||||||
let nonce = tx1.nonce;
|
let nonce = tx1.nonce;
|
||||||
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();
|
||||||
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().pending, 2);
|
assert_eq!(txq.status().pending, 2);
|
||||||
assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into()));
|
assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into()));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let tx = new_tx(123.into(), 1.into());
|
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
|
// then
|
||||||
// No longer the case as we don't even consider a transaction that isn't above a full
|
// 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(),
|
gas_limit: !U256::zero(),
|
||||||
};
|
};
|
||||||
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External).unwrap();
|
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
|
||||||
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External).unwrap();
|
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
|
||||||
let mut by_hash = {
|
let mut by_hash = {
|
||||||
let mut x = HashMap::new();
|
let mut x = HashMap::new();
|
||||||
let tx1 = VerifiedTransaction::new(tx1.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).unwrap();
|
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
|
||||||
x.insert(tx1.hash(), tx1);
|
x.insert(tx1.hash(), tx1);
|
||||||
x.insert(tx2.hash(), tx2);
|
x.insert(tx2.hash(), tx2);
|
||||||
x
|
x
|
||||||
@ -1435,12 +1470,12 @@ mod test {
|
|||||||
// Create two transactions with same nonce
|
// Create two transactions with same nonce
|
||||||
// (same hash)
|
// (same hash)
|
||||||
let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into());
|
let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into());
|
||||||
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External).unwrap();
|
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
|
||||||
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External).unwrap();
|
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
|
||||||
let by_hash = {
|
let by_hash = {
|
||||||
let mut x = HashMap::new();
|
let mut x = HashMap::new();
|
||||||
let tx1 = VerifiedTransaction::new(tx1.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).unwrap();
|
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
|
||||||
x.insert(tx1.hash(), tx1);
|
x.insert(tx1.hash(), tx1);
|
||||||
x.insert(tx2.hash(), tx2);
|
x.insert(tx2.hash(), tx2);
|
||||||
x
|
x
|
||||||
@ -1482,10 +1517,10 @@ mod test {
|
|||||||
gas_limit: !U256::zero(),
|
gas_limit: !U256::zero(),
|
||||||
};
|
};
|
||||||
let tx = new_tx_default();
|
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);
|
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
|
||||||
assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none());
|
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);
|
let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
|
||||||
assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some());
|
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());
|
assert_eq!(set.gas_price_entry_limit(), 0.into());
|
||||||
let tx = new_tx_default();
|
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);
|
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
|
||||||
assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none());
|
assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none());
|
||||||
assert_eq!(set.gas_price_entry_limit(), 2.into());
|
assert_eq!(set.gas_price_entry_limit(), 2.into());
|
||||||
@ -1517,12 +1552,12 @@ mod test {
|
|||||||
!U256::zero() };
|
!U256::zero() };
|
||||||
|
|
||||||
// First insert one transaction to future
|
// 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!(res.unwrap(), TransactionImportResult::Future);
|
||||||
assert_eq!(txq.status().future, 1);
|
assert_eq!(txq.status().future, 1);
|
||||||
|
|
||||||
// now import second transaction to current
|
// 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)
|
// and then there should be only one transaction in current (the one with higher gas_price)
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1542,12 +1577,12 @@ mod test {
|
|||||||
!U256::zero() };
|
!U256::zero() };
|
||||||
|
|
||||||
// First insert one transaction to future
|
// 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!(res.unwrap(), TransactionImportResult::Future);
|
||||||
assert_eq!(txq.status().future, 1);
|
assert_eq!(txq.status().future, 1);
|
||||||
|
|
||||||
// now import second transaction to current
|
// 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
|
// then
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1566,7 +1601,7 @@ mod test {
|
|||||||
let tx = new_tx_default();
|
let tx = new_tx_default();
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1585,10 +1620,10 @@ mod test {
|
|||||||
txq.set_minimal_gas_price(15.into());
|
txq.set_minimal_gas_price(15.into());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res1 = txq.add(tx1, 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, &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, &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, &default_account_details, &gas_estimator);
|
let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1619,10 +1654,10 @@ mod test {
|
|||||||
txq.set_minimal_gas_price(15.into());
|
txq.set_minimal_gas_price(15.into());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res1 = txq.add(tx1, 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, &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, &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, &default_account_details, &gas_estimator);
|
let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1665,7 +1700,7 @@ mod test {
|
|||||||
txq.set_gas_limit(limit);
|
txq.set_gas_limit(limit);
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded {
|
assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded {
|
||||||
@ -1689,7 +1724,7 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res = txq.add(tx, TransactionOrigin::External, &account, &gas_estimator);
|
let res = txq.add(tx, TransactionOrigin::External, None, &account, &gas_estimator);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientBalance {
|
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientBalance {
|
||||||
@ -1709,7 +1744,7 @@ mod test {
|
|||||||
txq.set_minimal_gas_price(tx.gas_price + U256::one());
|
txq.set_minimal_gas_price(tx.gas_price + U256::one());
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientGasPrice {
|
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientGasPrice {
|
||||||
@ -1729,7 +1764,7 @@ mod test {
|
|||||||
txq.set_minimal_gas_price(tx.gas_price + U256::one());
|
txq.set_minimal_gas_price(tx.gas_price + U256::one());
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
@ -1759,7 +1794,7 @@ mod test {
|
|||||||
rlp::decode(s.as_raw())
|
rlp::decode(s.as_raw())
|
||||||
};
|
};
|
||||||
// when
|
// 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
|
// then
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
@ -1773,8 +1808,8 @@ mod test {
|
|||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
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();
|
||||||
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
|
// then
|
||||||
let top = txq.top_transactions();
|
let top = txq.top_transactions();
|
||||||
@ -1793,9 +1828,9 @@ mod test {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// first insert the one with higher gas price
|
// 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
|
// 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
|
// then
|
||||||
let top = txq.top_transactions();
|
let top = txq.top_transactions();
|
||||||
@ -1812,15 +1847,15 @@ mod test {
|
|||||||
// the second one has same nonce but higher `gas_price`
|
// the second one has same nonce but higher `gas_price`
|
||||||
let (_, tx0) = new_similar_tx_pair();
|
let (_, tx0) = new_similar_tx_pair();
|
||||||
|
|
||||||
txq.add(tx0.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, &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
|
// the one with higher gas price is first
|
||||||
assert_eq!(txq.top_transactions()[0], tx0);
|
assert_eq!(txq.top_transactions()[0], tx0);
|
||||||
assert_eq!(txq.top_transactions()[1], tx1);
|
assert_eq!(txq.top_transactions()[1], tx1);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
// insert second as local
|
// 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
|
// then
|
||||||
// the order should be updated
|
// the order should be updated
|
||||||
@ -1839,9 +1874,9 @@ mod test {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// first insert local one with higher gas price
|
// 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
|
// 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
|
// then
|
||||||
let top = txq.top_transactions();
|
let top = txq.top_transactions();
|
||||||
@ -1857,8 +1892,8 @@ mod test {
|
|||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
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();
|
||||||
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
|
// then
|
||||||
let top = txq.top_transactions();
|
let top = txq.top_transactions();
|
||||||
@ -1877,10 +1912,10 @@ mod test {
|
|||||||
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
||||||
|
|
||||||
// insert everything
|
// insert everything
|
||||||
txq.add(txa.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, &prev_nonce, &gas_estimator).unwrap();
|
txq.add(txb.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
|
||||||
txq.add(tx1.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
|
txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
|
||||||
txq.add(tx2.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap();
|
txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
|
||||||
|
|
||||||
assert_eq!(txq.status().future, 4);
|
assert_eq!(txq.status().future, 4);
|
||||||
|
|
||||||
@ -1889,10 +1924,10 @@ mod test {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
let top = txq.future_transactions();
|
let top = txq.future_transactions();
|
||||||
assert_eq!(top[0], txa);
|
assert_eq!(top[0].transaction, txa);
|
||||||
assert_eq!(top[1], txb);
|
assert_eq!(top[1].transaction, txb);
|
||||||
assert_eq!(top[2], tx1);
|
assert_eq!(top[2].transaction, tx1);
|
||||||
assert_eq!(top[3], tx2);
|
assert_eq!(top[3].transaction, tx2);
|
||||||
assert_eq!(top.len(), 4);
|
assert_eq!(top.len(), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1905,10 +1940,10 @@ mod test {
|
|||||||
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
||||||
|
|
||||||
// insert everything
|
// insert everything
|
||||||
txq.add(txa.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, &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, &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, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
|
||||||
let top = txq.top_transactions();
|
let top = txq.top_transactions();
|
||||||
assert_eq!(top[0], tx1);
|
assert_eq!(top[0], tx1);
|
||||||
@ -1938,10 +1973,10 @@ mod test {
|
|||||||
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
||||||
|
|
||||||
// insert everything
|
// insert everything
|
||||||
txq.add(txa.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, &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, &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, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
|
||||||
let top = txq.top_transactions();
|
let top = txq.top_transactions();
|
||||||
assert_eq!(top[0], tx1);
|
assert_eq!(top[0], tx1);
|
||||||
@ -1970,8 +2005,8 @@ mod test {
|
|||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
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();
|
||||||
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
|
// then
|
||||||
let top = txq.pending_hashes();
|
let top = txq.pending_hashes();
|
||||||
@ -1988,8 +2023,8 @@ mod test {
|
|||||||
let (tx, tx2) = new_tx_pair_default(2.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(2.into(), 0.into());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res1 = txq.add(tx.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, &default_account_details, &gas_estimator).unwrap();
|
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res1, TransactionImportResult::Current);
|
assert_eq!(res1, TransactionImportResult::Current);
|
||||||
@ -2002,6 +2037,26 @@ mod test {
|
|||||||
assert_eq!(top[0], tx);
|
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]
|
#[test]
|
||||||
fn should_correctly_update_futures_when_removing() {
|
fn should_correctly_update_futures_when_removing() {
|
||||||
// given
|
// given
|
||||||
@ -2012,8 +2067,8 @@ mod test {
|
|||||||
let mut txq = TransactionQueue::default();
|
let mut txq = TransactionQueue::default();
|
||||||
|
|
||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
txq.add(tx.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, &prev_nonce, &gas_estimator).unwrap();
|
txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
|
||||||
assert_eq!(txq.status().future, 2);
|
assert_eq!(txq.status().future, 2);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -2035,13 +2090,13 @@ mod test {
|
|||||||
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None);
|
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);
|
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);
|
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);
|
assert_eq!(txq.status().future, 1);
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
@ -2057,8 +2112,8 @@ mod test {
|
|||||||
// given
|
// given
|
||||||
let mut txq2 = TransactionQueue::default();
|
let mut txq2 = TransactionQueue::default();
|
||||||
let (tx, tx2) = new_tx_pair_default(3.into(), 0.into());
|
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(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
txq2.add(tx2.clone(), TransactionOrigin::External, &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().pending, 1);
|
||||||
assert_eq!(txq2.status().future, 1);
|
assert_eq!(txq2.status().future, 1);
|
||||||
|
|
||||||
@ -2079,10 +2134,10 @@ mod test {
|
|||||||
let mut txq = TransactionQueue::default();
|
let mut txq = TransactionQueue::default();
|
||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
let tx3 = new_tx_default();
|
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);
|
assert_eq!(txq.status().future, 1);
|
||||||
txq.add(tx3.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, &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);
|
assert_eq!(txq.status().pending, 3);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -2101,8 +2156,8 @@ mod test {
|
|||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
|
|
||||||
// add
|
// add
|
||||||
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();
|
||||||
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();
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
assert_eq!(stats.pending, 2);
|
assert_eq!(stats.pending, 2);
|
||||||
|
|
||||||
@ -2121,11 +2176,11 @@ mod test {
|
|||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
let sender = tx.sender().unwrap();
|
let sender = tx.sender().unwrap();
|
||||||
let nonce = tx.nonce;
|
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);
|
assert_eq!(txq.status().pending, 1);
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
let t = txq.top_transactions();
|
let t = txq.top_transactions();
|
||||||
@ -2142,14 +2197,14 @@ mod test {
|
|||||||
txq.current.set_limit(10);
|
txq.current.set_limit(10);
|
||||||
let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into());
|
let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into());
|
||||||
let (tx3, tx4) = new_tx_pair_default(4.into(), 2.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(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
txq.add(tx3.clone(), TransactionOrigin::External, &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);
|
assert_eq!(txq.status().pending, 2);
|
||||||
|
|
||||||
// when
|
// 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);
|
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
|
// then
|
||||||
assert_eq!(txq.status().future, 1);
|
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 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 (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 (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(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
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();
|
||||||
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
// limited by gas
|
// 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);
|
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 (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 (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
|
||||||
let (tx5, _) = 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(tx1.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
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();
|
||||||
// Not accepted because of limit
|
// Not accepted because of limit
|
||||||
txq.add(tx5.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap_err();
|
txq.add(tx5.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap_err();
|
||||||
txq.add(tx3.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx3.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
txq.add(tx4.clone(), TransactionOrigin::Local, &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);
|
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() };
|
let fetch_last_nonce = |_a: &Address| AccountDetails { nonce: last_nonce, balance: !U256::zero() };
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
assert_eq!(unwrap_tx_err(res), TransactionError::Old);
|
assert_eq!(unwrap_tx_err(res), TransactionError::Old);
|
||||||
@ -2207,12 +2262,12 @@ mod test {
|
|||||||
balance: !U256::zero() };
|
balance: !U256::zero() };
|
||||||
let mut txq = TransactionQueue::default();
|
let mut txq = TransactionQueue::default();
|
||||||
let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
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().future, 1);
|
||||||
assert_eq!(txq.status().pending, 0);
|
assert_eq!(txq.status().pending, 0);
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
assert_eq!(unwrap_tx_err(res), TransactionError::AlreadyImported);
|
assert_eq!(unwrap_tx_err(res), TransactionError::AlreadyImported);
|
||||||
@ -2226,15 +2281,15 @@ mod test {
|
|||||||
// given
|
// given
|
||||||
let mut txq = TransactionQueue::default();
|
let mut txq = TransactionQueue::default();
|
||||||
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
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(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
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().pending, 2);
|
assert_eq!(txq.status().pending, 2);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.remove_invalid(&tx1.hash(), &default_account_details);
|
txq.remove_invalid(&tx1.hash(), &default_account_details);
|
||||||
assert_eq!(txq.status().pending, 0);
|
assert_eq!(txq.status().pending, 0);
|
||||||
assert_eq!(txq.status().future, 1);
|
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
|
// then
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
@ -2248,10 +2303,10 @@ mod test {
|
|||||||
let mut txq = TransactionQueue::default();
|
let mut txq = TransactionQueue::default();
|
||||||
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
let tx3 = new_tx_default();
|
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);
|
assert_eq!(txq.status().future, 1);
|
||||||
txq.add(tx3.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, &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);
|
assert_eq!(txq.status().pending, 3);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -2278,8 +2333,8 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.add(tx, 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, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
@ -2306,10 +2361,10 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.add(tx1, 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, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
assert_eq!(txq.status().future, 1);
|
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
|
// then
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
@ -2327,8 +2382,8 @@ mod test {
|
|||||||
!U256::zero() };
|
!U256::zero() };
|
||||||
let mut txq = TransactionQueue::default();
|
let mut txq = TransactionQueue::default();
|
||||||
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
txq.add(tx1.clone(), TransactionOrigin::External, &previous_nonce, &gas_estimator).unwrap();
|
txq.add(tx1.clone(), TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
|
||||||
txq.add(tx2, TransactionOrigin::External, &previous_nonce, &gas_estimator).unwrap();
|
txq.add(tx2, TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
|
||||||
assert_eq!(txq.status().future, 2);
|
assert_eq!(txq.status().future, 2);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -2359,7 +2414,7 @@ mod test {
|
|||||||
let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
|
let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.add(tx, TransactionOrigin::External, &details, &gas_estimator).unwrap();
|
txq.add(tx, TransactionOrigin::External, None, &details, &gas_estimator).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(txq.last_nonce(&from), Some(nonce));
|
assert_eq!(txq.last_nonce(&from), Some(nonce));
|
||||||
@ -2374,7 +2429,7 @@ mod test {
|
|||||||
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
|
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
|
||||||
|
|
||||||
// Insert first transaction
|
// Insert first transaction
|
||||||
txq.add(tx1, TransactionOrigin::External, &details1, &gas_estimator).unwrap();
|
txq.add(tx1, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.remove_all(tx2.sender().unwrap(), nonce2 + U256::one());
|
txq.remove_all(tx2.sender().unwrap(), nonce2 + U256::one());
|
||||||
@ -2394,9 +2449,9 @@ mod test {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// Insert first transaction
|
// 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
|
// 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
|
// Now block is imported
|
||||||
txq.remove_all(sender, nonce2 - U256::from(1));
|
txq.remove_all(sender, nonce2 - U256::from(1));
|
||||||
// tx2 should be not be promoted to current
|
// tx2 should be not be promoted to current
|
||||||
@ -2415,9 +2470,9 @@ mod test {
|
|||||||
assert_eq!(txq.has_local_pending_transactions(), false);
|
assert_eq!(txq.has_local_pending_transactions(), false);
|
||||||
|
|
||||||
// when
|
// 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.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
|
// then
|
||||||
assert_eq!(txq.has_local_pending_transactions(), true);
|
assert_eq!(txq.has_local_pending_transactions(), true);
|
||||||
@ -2432,8 +2487,8 @@ mod test {
|
|||||||
default_account_details(a).balance };
|
default_account_details(a).balance };
|
||||||
|
|
||||||
// when
|
// when
|
||||||
assert_eq!(txq.add(tx2, 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, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
|
assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(txq.future.by_priority.len(), 1);
|
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))
|
(tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None))
|
||||||
};
|
};
|
||||||
let sender = tx1.sender().unwrap();
|
let sender = tx1.sender().unwrap();
|
||||||
txq.add(tx1, 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, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
txq.add(tx3, TransactionOrigin::Local, &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.future.by_priority.len(), 0);
|
||||||
assert_eq!(txq.current.by_priority.len(), 3);
|
assert_eq!(txq.current.by_priority.len(), 3);
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into());
|
assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into());
|
||||||
@ -2481,8 +2536,8 @@ mod test {
|
|||||||
let high_gas = |_: &SignedTransaction| 100_001.into();
|
let high_gas = |_: &SignedTransaction| 100_001.into();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res1 = txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator);
|
let res1 = txq.add(tx1, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
|
||||||
let res2 = txq.add(tx2, TransactionOrigin::Local, &default_account_details, &high_gas);
|
let res2 = txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &high_gas);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
||||||
@ -2502,10 +2557,10 @@ mod test {
|
|||||||
let nonce1 = tx1.nonce;
|
let nonce1 = tx1.nonce;
|
||||||
|
|
||||||
// Insert all transactions
|
// Insert all transactions
|
||||||
txq.add(tx1, 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, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
|
txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
|
||||||
txq.add(tx4, TransactionOrigin::External, &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);
|
assert_eq!(txq.top_transactions().len(), 4);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
@ -390,6 +390,34 @@ impl Deref for LocalizedTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queued information with additional information.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Binary)]
|
||||||
|
pub struct PendingTransaction {
|
||||||
|
/// Signed transaction data.
|
||||||
|
pub transaction: SignedTransaction,
|
||||||
|
/// Gas price.
|
||||||
|
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]
|
#[test]
|
||||||
fn sender_test() {
|
fn sender_test() {
|
||||||
let t: SignedTransaction = decode(&::rustc_serialize::hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
|
let t: SignedTransaction = decode(&::rustc_serialize::hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
|
||||||
|
@ -21,7 +21,7 @@ use util::bytes::ToPretty;
|
|||||||
use ethkey::Signature;
|
use ethkey::Signature;
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use ethcore::client::MiningBlockChainClient;
|
use ethcore::client::MiningBlockChainClient;
|
||||||
use ethcore::transaction::{Action, SignedTransaction, Transaction};
|
use ethcore::transaction::{Action, SignedTransaction, PendingTransaction, Transaction};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
@ -79,9 +79,9 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: O
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<H256, Error>
|
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: PendingTransaction) -> Result<H256, Error>
|
||||||
where C: MiningBlockChainClient, M: MinerService {
|
where C: MiningBlockChainClient, M: MinerService {
|
||||||
let hash = signed_transaction.hash();
|
let hash = signed_transaction.transaction.hash();
|
||||||
|
|
||||||
miner.import_own_transaction(client, signed_transaction)
|
miner.import_own_transaction(client, signed_transaction)
|
||||||
.map_err(errors::from_transaction_error)
|
.map_err(errors::from_transaction_error)
|
||||||
@ -120,10 +120,12 @@ pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider
|
|||||||
{
|
{
|
||||||
|
|
||||||
let network_id = client.signing_network_id();
|
let network_id = client.signing_network_id();
|
||||||
|
let min_block = filled.min_block.clone();
|
||||||
let signed_transaction = try!(sign_no_dispatch(client, miner, accounts, filled, password));
|
let signed_transaction = try!(sign_no_dispatch(client, miner, accounts, filled, password));
|
||||||
|
|
||||||
trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", rlp::encode(&signed_transaction).to_vec().pretty(), network_id);
|
trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", rlp::encode(&signed_transaction).to_vec().pretty(), network_id);
|
||||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
let pending_transaction = PendingTransaction::new(signed_transaction, min_block);
|
||||||
|
dispatch_transaction(&*client, &*miner, pending_transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_optional_fields<C, M>(request: TransactionRequest, client: &C, miner: &M) -> FilledTransactionRequest
|
pub fn fill_optional_fields<C, M>(request: TransactionRequest, client: &C, miner: &M) -> FilledTransactionRequest
|
||||||
@ -137,6 +139,7 @@ pub fn fill_optional_fields<C, M>(request: TransactionRequest, client: &C, miner
|
|||||||
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
||||||
value: request.value.unwrap_or_else(|| 0.into()),
|
value: request.value.unwrap_or_else(|| 0.into()),
|
||||||
data: request.data.unwrap_or_else(Vec::new),
|
data: request.data.unwrap_or_else(Vec::new),
|
||||||
|
min_block: request.min_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@ pub struct TransactionRequest {
|
|||||||
pub data: Option<Bytes>,
|
pub data: Option<Bytes>,
|
||||||
/// Transaction's nonce
|
/// Transaction's nonce
|
||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
|
/// Delay until this block if specified.
|
||||||
|
pub min_block: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transaction request coming from RPC with default values filled in.
|
/// Transaction request coming from RPC with default values filled in.
|
||||||
@ -52,6 +54,8 @@ pub struct FilledTransactionRequest {
|
|||||||
pub data: Bytes,
|
pub data: Bytes,
|
||||||
/// Transaction's nonce
|
/// Transaction's nonce
|
||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
|
/// Delay until this block if specified.
|
||||||
|
pub min_block: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FilledTransactionRequest> for TransactionRequest {
|
impl From<FilledTransactionRequest> for TransactionRequest {
|
||||||
@ -64,6 +68,7 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
|||||||
value: Some(r.value),
|
value: Some(r.value),
|
||||||
data: Some(r.data),
|
data: Some(r.data),
|
||||||
nonce: r.nonce,
|
nonce: r.nonce,
|
||||||
|
min_block: r.min_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,6 +328,7 @@ mod test {
|
|||||||
value: 10_000_000.into(),
|
value: 10_000_000.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber};
|
|||||||
use ethcore::block::IsBlock;
|
use ethcore::block::IsBlock;
|
||||||
use ethcore::views::*;
|
use ethcore::views::*;
|
||||||
use ethcore::ethereum::Ethash;
|
use ethcore::ethereum::Ethash;
|
||||||
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
|
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, PendingTransaction, Action};
|
||||||
use ethcore::log_entry::LogEntry;
|
use ethcore::log_entry::LogEntry;
|
||||||
use ethcore::filter::Filter as EthcoreFilter;
|
use ethcore::filter::Filter as EthcoreFilter;
|
||||||
use ethcore::snapshot::SnapshotService;
|
use ethcore::snapshot::SnapshotService;
|
||||||
@ -613,7 +613,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
|
|
||||||
let raw_transaction = raw.to_vec();
|
let raw_transaction = raw.to_vec();
|
||||||
match UntrustedRlp::new(&raw_transaction).as_val() {
|
match UntrustedRlp::new(&raw_transaction).as_val() {
|
||||||
Ok(signed_transaction) => dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), signed_transaction).map(Into::into),
|
Ok(signed_transaction) => dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), PendingTransaction::new(signed_transaction, None)).map(Into::into),
|
||||||
Err(e) => Err(errors::from_rlp_error(e)),
|
Err(e) => Err(errors::from_rlp_error(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,12 @@ impl<C, M, S: ?Sized> Parity for ParityClient<C, M, S> where
|
|||||||
Ok(take_weak!(self.miner).all_transactions().into_iter().map(Into::into).collect::<Vec<_>>())
|
Ok(take_weak!(self.miner).all_transactions().into_iter().map(Into::into).collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn future_transactions(&self) -> Result<Vec<Transaction>, Error> {
|
||||||
|
try!(self.active());
|
||||||
|
|
||||||
|
Ok(take_weak!(self.miner).future_transactions().into_iter().map(Into::into).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
|
|
||||||
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>, Error> {
|
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ use std::sync::{Arc, Weak};
|
|||||||
use rlp::{UntrustedRlp, View};
|
use rlp::{UntrustedRlp, View};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethcore::client::MiningBlockChainClient;
|
use ethcore::client::MiningBlockChainClient;
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::{SignedTransaction, PendingTransaction};
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
|
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
@ -96,6 +96,9 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
|
|||||||
if let Some(gas) = modification.gas {
|
if let Some(gas) = modification.gas {
|
||||||
request.gas = gas.into();
|
request.gas = gas.into();
|
||||||
}
|
}
|
||||||
|
if let Some(min_block) = modification.min_block {
|
||||||
|
request.min_block = min_block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Execute
|
// Execute
|
||||||
let result = dispatch::execute(&*client, &*miner, &*accounts, payload, Some(pass));
|
let result = dispatch::execute(&*client, &*miner, &*accounts, payload, Some(pass));
|
||||||
@ -135,7 +138,8 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
|
|||||||
|
|
||||||
// Dispatch if everything is ok
|
// Dispatch if everything is ok
|
||||||
if sender_matches && data_matches && value_matches && nonce_matches {
|
if sender_matches && data_matches && value_matches && nonce_matches {
|
||||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
let pending_transaction = PendingTransaction::new(signed_transaction, request.min_block);
|
||||||
|
dispatch_transaction(&*client, &*miner, pending_transaction)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.map(ConfirmationResponse::SendTransaction)
|
.map(ConfirmationResponse::SendTransaction)
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,7 +22,7 @@ use ethcore::error::{Error, CallError};
|
|||||||
use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
|
use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
|
||||||
use ethcore::block::{ClosedBlock, IsBlock};
|
use ethcore::block::{ClosedBlock, IsBlock};
|
||||||
use ethcore::header::BlockNumber;
|
use ethcore::header::BlockNumber;
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::{SignedTransaction, PendingTransaction};
|
||||||
use ethcore::receipt::{Receipt, RichReceipt};
|
use ethcore::receipt::{Receipt, RichReceipt};
|
||||||
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult, LocalTransactionStatus};
|
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult, LocalTransactionStatus};
|
||||||
use ethcore::account_provider::Error as AccountError;
|
use ethcore::account_provider::Error as AccountError;
|
||||||
@ -160,17 +160,17 @@ impl MinerService for TestMinerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction) ->
|
fn import_own_transaction(&self, chain: &MiningBlockChainClient, pending: PendingTransaction) ->
|
||||||
Result<TransactionImportResult, Error> {
|
Result<TransactionImportResult, Error> {
|
||||||
|
|
||||||
// keep the pending nonces up to date
|
// keep the pending nonces up to date
|
||||||
if let Ok(ref sender) = transaction.sender() {
|
if let Ok(ref sender) = pending.transaction.sender() {
|
||||||
let nonce = self.last_nonce(sender).unwrap_or(chain.latest_nonce(sender));
|
let nonce = self.last_nonce(sender).unwrap_or(chain.latest_nonce(sender));
|
||||||
self.last_nonces.write().insert(sender.clone(), nonce + U256::from(1));
|
self.last_nonces.write().insert(sender.clone(), nonce + U256::from(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// lets assume that all txs are valid
|
// lets assume that all txs are valid
|
||||||
self.imported_transactions.lock().push(transaction);
|
self.imported_transactions.lock().push(pending.transaction);
|
||||||
|
|
||||||
Ok(TransactionImportResult::Current)
|
Ok(TransactionImportResult::Current)
|
||||||
}
|
}
|
||||||
@ -204,16 +204,20 @@ impl MinerService for TestMinerService {
|
|||||||
self.pending_transactions.lock().get(hash).cloned()
|
self.pending_transactions.lock().get(hash).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction> {
|
fn all_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
self.pending_transactions.lock().values().cloned().collect()
|
self.pending_transactions.lock().values().cloned().map(Into::into).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
||||||
self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect()
|
self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self, _best_block: BlockNumber) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self, _best_block: BlockNumber) -> Vec<PendingTransaction> {
|
||||||
self.pending_transactions.lock().values().cloned().collect()
|
self.pending_transactions.lock().values().cloned().map(Into::into).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn future_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_receipt(&self, _best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
|
fn pending_receipt(&self, _best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
|
||||||
|
@ -494,7 +494,7 @@ fn rpc_eth_pending_transaction_by_hash() {
|
|||||||
tester.miner.pending_transactions.lock().insert(H256::zero(), tx);
|
tester.miner.pending_transactions.lock().insert(H256::zero(), tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","networkId":null,"nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","standardV":"0x0","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":"0x1b","value":"0xa"},"id":1}"#;
|
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","minBlock":null,"networkId":null,"nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","standardV":"0x0","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":"0x1b","value":"0xa"},"id":1}"#;
|
||||||
let request = r#"{
|
let request = r#"{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "eth_getTransactionByHash",
|
"method": "eth_getTransactionByHash",
|
||||||
@ -810,6 +810,7 @@ fn rpc_eth_sign_transaction() {
|
|||||||
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
||||||
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
||||||
r#""input":"0x","# +
|
r#""input":"0x","# +
|
||||||
|
r#""minBlock":null,"# +
|
||||||
&format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
&format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||||
r#""nonce":"0x1","# +
|
r#""nonce":"0x1","# +
|
||||||
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
||||||
|
@ -82,6 +82,7 @@ fn should_return_list_of_items_to_confirm() {
|
|||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
tester.signer.add_request(ConfirmationPayload::Signature(1.into(), 5.into())).unwrap();
|
tester.signer.add_request(ConfirmationPayload::Signature(1.into(), 5.into())).unwrap();
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ fn should_return_list_of_items_to_confirm() {
|
|||||||
let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#;
|
let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#;
|
||||||
let response = concat!(
|
let response = concat!(
|
||||||
r#"{"jsonrpc":"2.0","result":["#,
|
r#"{"jsonrpc":"2.0","result":["#,
|
||||||
r#"{"id":"0x1","payload":{"sendTransaction":{"data":"0x","from":"0x0000000000000000000000000000000000000001","gas":"0x989680","gasPrice":"0x2710","nonce":null,"to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","value":"0x1"}}},"#,
|
r#"{"id":"0x1","payload":{"sendTransaction":{"data":"0x","from":"0x0000000000000000000000000000000000000001","gas":"0x989680","gasPrice":"0x2710","minBlock":null,"nonce":null,"to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","value":"0x1"}}},"#,
|
||||||
r#"{"id":"0x2","payload":{"sign":{"address":"0x0000000000000000000000000000000000000001","hash":"0x0000000000000000000000000000000000000000000000000000000000000005"}}}"#,
|
r#"{"id":"0x2","payload":{"sign":{"address":"0x0000000000000000000000000000000000000001","hash":"0x0000000000000000000000000000000000000000000000000000000000000005"}}}"#,
|
||||||
r#"],"id":1}"#
|
r#"],"id":1}"#
|
||||||
);
|
);
|
||||||
@ -111,6 +112,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
|||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
|
||||||
@ -136,6 +138,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
|||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
|
||||||
@ -178,6 +181,7 @@ fn should_confirm_transaction_and_dispatch() {
|
|||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = Transaction {
|
||||||
@ -223,6 +227,7 @@ fn should_confirm_transaction_with_rlp() {
|
|||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = Transaction {
|
||||||
@ -270,6 +275,7 @@ fn should_return_error_when_sender_does_not_match() {
|
|||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = Transaction {
|
||||||
|
@ -285,6 +285,7 @@ fn should_add_sign_transaction_to_the_queue() {
|
|||||||
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
||||||
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
||||||
r#""input":"0x","# +
|
r#""input":"0x","# +
|
||||||
|
r#""minBlock":null,"# +
|
||||||
&format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
&format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||||
r#""nonce":"0x1","# +
|
r#""nonce":"0x1","# +
|
||||||
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
||||||
|
@ -122,6 +122,10 @@ build_rpc_trait! {
|
|||||||
#[rpc(name = "parity_pendingTransactions")]
|
#[rpc(name = "parity_pendingTransactions")]
|
||||||
fn pending_transactions(&self) -> Result<Vec<Transaction>, Error>;
|
fn pending_transactions(&self) -> Result<Vec<Transaction>, Error>;
|
||||||
|
|
||||||
|
/// Returns all future transactions from transaction queue.
|
||||||
|
#[rpc(name = "parity_futureTransactions")]
|
||||||
|
fn future_transactions(&self) -> Result<Vec<Transaction>, Error>;
|
||||||
|
|
||||||
/// Returns propagation statistics on transactions pending in the queue.
|
/// Returns propagation statistics on transactions pending in the queue.
|
||||||
#[rpc(name = "parity_pendingTransactionsStats")]
|
#[rpc(name = "parity_pendingTransactionsStats")]
|
||||||
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>, Error>;
|
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>, Error>;
|
||||||
|
@ -139,7 +139,7 @@ mod tests {
|
|||||||
fn test_serialize_block_transactions() {
|
fn test_serialize_block_transactions() {
|
||||||
let t = BlockTransactions::Full(vec![Transaction::default()]);
|
let t = BlockTransactions::Full(vec![Transaction::default()]);
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0"}]"#);
|
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0","minBlock":null}]"#);
|
||||||
|
|
||||||
let t = BlockTransactions::Hashes(vec![H256::default().into()]);
|
let t = BlockTransactions::Hashes(vec![H256::default().into()]);
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
@ -144,6 +144,9 @@ pub struct TransactionModification {
|
|||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
/// Modified gas
|
/// Modified gas
|
||||||
pub gas: Option<U256>,
|
pub gas: Option<U256>,
|
||||||
|
/// Modified min block
|
||||||
|
#[serde(rename="minBlock")]
|
||||||
|
pub min_block: Option<Option<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents two possible return values.
|
/// Represents two possible return values.
|
||||||
@ -218,12 +221,13 @@ mod tests {
|
|||||||
value: 100_000.into(),
|
value: 100_000.into(),
|
||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: Some(1.into()),
|
nonce: Some(1.into()),
|
||||||
|
min_block: None,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res = serde_json::to_string(&ConfirmationRequest::from(request));
|
let res = serde_json::to_string(&ConfirmationRequest::from(request));
|
||||||
let expected = r#"{"id":"0xf","payload":{"sendTransaction":{"from":"0x0000000000000000000000000000000000000000","to":null,"gasPrice":"0x2710","gas":"0x3a98","value":"0x186a0","data":"0x010203","nonce":"0x1"}}}"#;
|
let expected = r#"{"id":"0xf","payload":{"sendTransaction":{"from":"0x0000000000000000000000000000000000000000","to":null,"gasPrice":"0x2710","gas":"0x3a98","value":"0x186a0","data":"0x010203","nonce":"0x1","minBlock":null}}}"#;
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res.unwrap(), expected.to_owned());
|
assert_eq!(res.unwrap(), expected.to_owned());
|
||||||
@ -242,12 +246,13 @@ mod tests {
|
|||||||
value: 100_000.into(),
|
value: 100_000.into(),
|
||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: Some(1.into()),
|
nonce: Some(1.into()),
|
||||||
|
min_block: None,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res = serde_json::to_string(&ConfirmationRequest::from(request));
|
let res = serde_json::to_string(&ConfirmationRequest::from(request));
|
||||||
let expected = r#"{"id":"0xf","payload":{"signTransaction":{"from":"0x0000000000000000000000000000000000000000","to":null,"gasPrice":"0x2710","gas":"0x3a98","value":"0x186a0","data":"0x010203","nonce":"0x1"}}}"#;
|
let expected = r#"{"id":"0xf","payload":{"signTransaction":{"from":"0x0000000000000000000000000000000000000000","to":null,"gasPrice":"0x2710","gas":"0x3a98","value":"0x186a0","data":"0x010203","nonce":"0x1","minBlock":null}}}"#;
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res.unwrap(), expected.to_owned());
|
assert_eq!(res.unwrap(), expected.to_owned());
|
||||||
@ -275,7 +280,8 @@ mod tests {
|
|||||||
fn should_deserialize_modification() {
|
fn should_deserialize_modification() {
|
||||||
// given
|
// given
|
||||||
let s1 = r#"{
|
let s1 = r#"{
|
||||||
"gasPrice":"0xba43b7400"
|
"gasPrice":"0xba43b7400",
|
||||||
|
"minBlock":42
|
||||||
}"#;
|
}"#;
|
||||||
let s2 = r#"{"gas": "0x1233"}"#;
|
let s2 = r#"{"gas": "0x1233"}"#;
|
||||||
let s3 = r#"{}"#;
|
let s3 = r#"{}"#;
|
||||||
@ -289,14 +295,17 @@ mod tests {
|
|||||||
assert_eq!(res1, TransactionModification {
|
assert_eq!(res1, TransactionModification {
|
||||||
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
||||||
gas: None,
|
gas: None,
|
||||||
|
min_block: Some(Some(42)),
|
||||||
});
|
});
|
||||||
assert_eq!(res2, TransactionModification {
|
assert_eq!(res2, TransactionModification {
|
||||||
gas_price: None,
|
gas_price: None,
|
||||||
gas: Some(U256::from_str("1233").unwrap()),
|
gas: Some(U256::from_str("1233").unwrap()),
|
||||||
|
min_block: None,
|
||||||
});
|
});
|
||||||
assert_eq!(res3, TransactionModification {
|
assert_eq!(res3, TransactionModification {
|
||||||
gas_price: None,
|
gas_price: None,
|
||||||
gas: None,
|
gas: None,
|
||||||
|
min_block: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use ethcore::miner;
|
use ethcore::miner;
|
||||||
use ethcore::contract_address;
|
use ethcore::contract_address;
|
||||||
use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction};
|
use ethcore::transaction::{LocalizedTransaction, Action, PendingTransaction, SignedTransaction};
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
use v1::types::{Bytes, H160, H256, U256, H512};
|
use v1::types::{Bytes, H160, H256, U256, H512};
|
||||||
|
|
||||||
@ -69,6 +69,9 @@ pub struct Transaction {
|
|||||||
pub r: U256,
|
pub r: U256,
|
||||||
/// The S field of the signature.
|
/// The S field of the signature.
|
||||||
pub s: U256,
|
pub s: U256,
|
||||||
|
/// Transaction activates at specified block.
|
||||||
|
#[serde(rename="minBlock")]
|
||||||
|
pub min_block: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Local Transaction Status
|
/// Local Transaction Status
|
||||||
@ -187,6 +190,7 @@ impl From<LocalizedTransaction> for Transaction {
|
|||||||
v: t.original_v().into(),
|
v: t.original_v().into(),
|
||||||
r: signature.r().into(),
|
r: signature.r().into(),
|
||||||
s: signature.s().into(),
|
s: signature.s().into(),
|
||||||
|
min_block: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,10 +224,19 @@ impl From<SignedTransaction> for Transaction {
|
|||||||
v: t.original_v().into(),
|
v: t.original_v().into(),
|
||||||
r: signature.r().into(),
|
r: signature.r().into(),
|
||||||
s: signature.s().into(),
|
s: signature.s().into(),
|
||||||
|
min_block: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<PendingTransaction> for Transaction {
|
||||||
|
fn from(t: PendingTransaction) -> Transaction {
|
||||||
|
let mut r = Transaction::from(t.transaction);
|
||||||
|
r.min_block = t.min_block;
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<miner::LocalTransactionStatus> for LocalTransactionStatus {
|
impl From<miner::LocalTransactionStatus> for LocalTransactionStatus {
|
||||||
fn from(s: miner::LocalTransactionStatus) -> Self {
|
fn from(s: miner::LocalTransactionStatus) -> Self {
|
||||||
use ethcore::miner::LocalTransactionStatus::*;
|
use ethcore::miner::LocalTransactionStatus::*;
|
||||||
@ -248,7 +261,7 @@ mod tests {
|
|||||||
fn test_transaction_serialize() {
|
fn test_transaction_serialize() {
|
||||||
let t = Transaction::default();
|
let t = Transaction::default();
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0"}"#);
|
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0","minBlock":null}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -38,6 +38,9 @@ pub struct TransactionRequest {
|
|||||||
pub data: Option<Bytes>,
|
pub data: Option<Bytes>,
|
||||||
/// Transaction's nonce
|
/// Transaction's nonce
|
||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
|
/// Delay until this block if specified.
|
||||||
|
#[serde(rename="minBlock")]
|
||||||
|
pub min_block: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<helpers::TransactionRequest> for TransactionRequest {
|
impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||||
@ -50,6 +53,7 @@ impl From<helpers::TransactionRequest> for TransactionRequest {
|
|||||||
value: r.value.map(Into::into),
|
value: r.value.map(Into::into),
|
||||||
data: r.data.map(Into::into),
|
data: r.data.map(Into::into),
|
||||||
nonce: r.nonce.map(Into::into),
|
nonce: r.nonce.map(Into::into),
|
||||||
|
min_block: r.min_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,6 +68,7 @@ impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
|||||||
value: Some(r.value.into()),
|
value: Some(r.value.into()),
|
||||||
data: Some(r.data.into()),
|
data: Some(r.data.into()),
|
||||||
nonce: r.nonce.map(Into::into),
|
nonce: r.nonce.map(Into::into),
|
||||||
|
min_block: r.min_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,6 +83,7 @@ impl Into<helpers::TransactionRequest> for TransactionRequest {
|
|||||||
value: self.value.map(Into::into),
|
value: self.value.map(Into::into),
|
||||||
data: self.data.map(Into::into),
|
data: self.data.map(Into::into),
|
||||||
nonce: self.nonce.map(Into::into),
|
nonce: self.nonce.map(Into::into),
|
||||||
|
min_block: self.min_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,7 +106,8 @@ mod tests {
|
|||||||
"gas":"0x2",
|
"gas":"0x2",
|
||||||
"value":"0x3",
|
"value":"0x3",
|
||||||
"data":"0x123456",
|
"data":"0x123456",
|
||||||
"nonce":"0x4"
|
"nonce":"0x4",
|
||||||
|
"minBlock":13
|
||||||
}"#;
|
}"#;
|
||||||
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
|
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
|
||||||
|
|
||||||
@ -112,6 +119,7 @@ mod tests {
|
|||||||
value: Some(U256::from(3)),
|
value: Some(U256::from(3)),
|
||||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||||
nonce: Some(U256::from(4)),
|
nonce: Some(U256::from(4)),
|
||||||
|
min_block: Some(13),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +142,8 @@ mod tests {
|
|||||||
gas: Some(U256::from_str("76c0").unwrap()),
|
gas: Some(U256::from_str("76c0").unwrap()),
|
||||||
value: Some(U256::from_str("9184e72a").unwrap()),
|
value: Some(U256::from_str("9184e72a").unwrap()),
|
||||||
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||||
nonce: None
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +160,7 @@ mod tests {
|
|||||||
value: None,
|
value: None,
|
||||||
data: None,
|
data: None,
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +184,7 @@ mod tests {
|
|||||||
value: None,
|
value: None,
|
||||||
data: Some(vec![0x85, 0x95, 0xba, 0xb1].into()),
|
data: Some(vec![0x85, 0x95, 0xba, 0xb1].into()),
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
min_block: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1901,10 +1901,10 @@ impl ChainSync {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let all_transactions_hashes = transactions.iter().map(|tx| tx.hash()).collect::<HashSet<H256>>();
|
let all_transactions_hashes = transactions.iter().map(|tx| tx.transaction.hash()).collect::<HashSet<H256>>();
|
||||||
let all_transactions_rlp = {
|
let all_transactions_rlp = {
|
||||||
let mut packet = RlpStream::new_list(transactions.len());
|
let mut packet = RlpStream::new_list(transactions.len());
|
||||||
for tx in &transactions { packet.append(tx); }
|
for tx in &transactions { packet.append(&tx.transaction); }
|
||||||
packet.out()
|
packet.out()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1942,11 +1942,11 @@ impl ChainSync {
|
|||||||
// Construct RLP
|
// Construct RLP
|
||||||
let mut packet = RlpStream::new_list(to_send.len());
|
let mut packet = RlpStream::new_list(to_send.len());
|
||||||
for tx in &transactions {
|
for tx in &transactions {
|
||||||
if to_send.contains(&tx.hash()) {
|
if to_send.contains(&tx.transaction.hash()) {
|
||||||
packet.append(tx);
|
packet.append(&tx.transaction);
|
||||||
// update stats
|
// update stats
|
||||||
let id = io.peer_session_info(*peer_id).and_then(|info| info.id);
|
let id = io.peer_session_info(*peer_id).and_then(|info| info.id);
|
||||||
stats.propagated(tx.hash(), id, block_number);
|
stats.propagated(tx.transaction.hash(), id, block_number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ fn test_authority_round() {
|
|||||||
}.sign(s1.secret(), None);
|
}.sign(s1.secret(), None);
|
||||||
// exhange statuses
|
// exhange statuses
|
||||||
net.sync_steps(5);
|
net.sync_steps(5);
|
||||||
net.peer(0).chain.miner().import_own_transaction(&net.peer(0).chain, tx1).unwrap();
|
net.peer(0).chain.miner().import_own_transaction(&net.peer(0).chain, PendingTransaction::new(tx1, None)).unwrap();
|
||||||
net.sync();
|
net.sync();
|
||||||
assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1);
|
assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1);
|
||||||
assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1);
|
assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1);
|
||||||
@ -68,7 +68,7 @@ fn test_authority_round() {
|
|||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}.sign(s2.secret(), None);
|
}.sign(s2.secret(), None);
|
||||||
net.peer(1).chain.miner().import_own_transaction(&net.peer(1).chain, tx2).unwrap();
|
net.peer(1).chain.miner().import_own_transaction(&net.peer(1).chain, PendingTransaction::new(tx2, None)).unwrap();
|
||||||
net.peer(1).chain.engine().step();
|
net.peer(1).chain.engine().step();
|
||||||
net.peer(1).chain.miner().update_sealing(&net.peer(1).chain);
|
net.peer(1).chain.miner().update_sealing(&net.peer(1).chain);
|
||||||
net.sync();
|
net.sync();
|
||||||
|
Loading…
Reference in New Issue
Block a user