New Transaction Queue implementation (#8074)

* Implementation of Verifier, Scoring and Ready.

* Queue in progress.

* TransactionPool.

* Prepare for txpool release.

* Miner refactor [WiP]

* WiP reworking miner.

* Make it compile.

* Add some docs.

* Split blockchain access to a separate file.

* Work on miner API.

* Fix ethcore tests.

* Refactor miner interface for sealing/work packages.

* Implement next nonce.

* RPC compiles.

* Implement couple of missing methdods for RPC.

* Add transaction queue listeners.

* Compiles!

* Clean-up and parallelize.

* Get rid of RefCell in header.

* Revert "Get rid of RefCell in header."

This reverts commit 0f2424c9b7319a786e1565ea2a8a6d801a21b4fb.

* Override Sync requirement.

* Fix status display.

* Unify logging.

* Extract some cheap checks.

* Measurements and optimizations.

* Fix scoring bug, heap size of bug and add cache

* Disable tx queueing and parallel verification.

* Make ethcore and ethcore-miner compile again.

* Make RPC compile again.

* Bunch of txpool tests.

* Migrate transaction queue tests.

* Nonce Cap

* Nonce cap cache and tests.

* Remove stale future transactions from the queue.

* Optimize scoring and write some tests.

* Simple penalization.

* Clean up and support for different scoring algorithms.

* Add CLI parameters for the new queue.

* Remove banning queue.

* Disable debug build.

* Change per_sender limit to be 1% instead of 5%

* Avoid cloning when propagating transactions.

* Remove old todo.

* Post-review fixes.

* Fix miner options default.

* Implement back ready transactions for light client.

* Get rid of from_pending_block

* Pass rejection reason.

* Add more details to drop.

* Rollback heap size of.

* Avoid cloning hashes when propagating and include more details on rejection.

* Fix tests.

* Introduce nonces cache.

* Remove uneccessary hashes allocation.

* Lower the mem limit.

* Re-enable parallel verification.

* Add miner log. Don't check the type if not below min_gas_price.

* Add more traces, fix disabling miner.

* Fix creating pending blocks twice on AuRa authorities.

* Fix tests.

* re-use pending blocks in AuRa

* Use reseal_min_period to prevent too frequent update_sealing.

* Fix log to contain hash not sender.

* Optimize local transactions.

* Fix aura tests.

* Update locks comments.

* Get rid of unsafe Sync impl.

* Review fixes.

* Remove excessive matches.

* Fix compilation errors.

* Use new pool in private transactions.

* Fix private-tx test.

* Fix secret store tests.

* Actually use gas_floor_target

* Fix config tests.

* Fix pool tests.

* Address grumbles.
This commit is contained in:
Tomasz Drwięga
2018-04-13 17:34:27 +02:00
committed by Marek Kotewicz
parent 03b96a7c0a
commit 1cd93e4ceb
105 changed files with 5185 additions and 5784 deletions

View File

@@ -79,6 +79,8 @@ extern crate serde_derive;
#[cfg(test)]
extern crate ethjson;
#[cfg(test)]
extern crate transaction_pool as txpool;
#[cfg(test)]
#[macro_use]

View File

@@ -34,8 +34,8 @@ use stats::Corpus;
use ethkey::Signature;
use sync::LightSync;
use ethcore::ids::BlockId;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use ethcore::client::BlockChainClient;
use ethcore::miner::{self, MinerService};
use ethcore::account_provider::AccountProvider;
use crypto::DEFAULT_MAC;
use transaction::{Action, SignedTransaction, PendingTransaction, Transaction};
@@ -117,10 +117,9 @@ impl<C, M> Clone for FullDispatcher<C, M> {
}
}
impl<C: MiningBlockChainClient, M: MinerService> FullDispatcher<C, M> {
impl<C: miner::BlockChainClient, M: MinerService> FullDispatcher<C, M> {
fn state_nonce(&self, from: &Address) -> U256 {
self.miner.last_nonce(from).map(|nonce| nonce + U256::one())
.unwrap_or_else(|| self.client.latest_nonce(from))
self.miner.next_nonce(&*self.client, from)
}
/// Imports transaction to the miner's queue.
@@ -133,7 +132,7 @@ impl<C: MiningBlockChainClient, M: MinerService> FullDispatcher<C, M> {
}
}
impl<C: MiningBlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C, M> {
impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C, M> {
fn fill_optional_fields(&self, request: TransactionRequest, default_sender: Address, force_nonce: bool)
-> BoxFuture<FilledTransactionRequest>
{
@@ -747,7 +746,7 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: S
/// Extract the default gas price from a client and miner.
pub fn default_gas_price<C, M>(client: &C, miner: &M, percentile: usize) -> U256 where
C: MiningBlockChainClient,
C: BlockChainClient,
M: MinerService,
{
client.gas_price_corpus(100).percentile(percentile).cloned().unwrap_or_else(|| miner.sensible_gas_price())

View File

@@ -391,11 +391,11 @@ pub fn no_light_peers() -> Error {
}
}
pub fn deprecated<T: Into<Option<String>>>(message: T) -> Error {
pub fn deprecated<S: Into<String>, T: Into<Option<S>>>(message: T) -> Error {
Error {
code: ErrorCode::ServerError(codes::DEPRECATED),
message: "Method deprecated".into(),
data: message.into().map(Value::String),
data: message.into().map(Into::into).map(Value::String),
}
}

View File

@@ -26,13 +26,12 @@ use parking_lot::Mutex;
use ethash::SeedHashCompute;
use ethcore::account_provider::{AccountProvider, DappId};
use ethcore::block::IsBlock;
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo};
use ethcore::client::{BlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo};
use ethcore::ethereum::Ethash;
use ethcore::filter::Filter as EthcoreFilter;
use ethcore::header::{BlockNumber as EthBlockNumber};
use ethcore::log_entry::LogEntry;
use ethcore::miner::MinerService;
use ethcore::miner::{self, MinerService};
use ethcore::snapshot::SnapshotService;
use ethcore::encoded;
use sync::{SyncProvider};
@@ -92,7 +91,7 @@ impl Default for EthClientOptions {
/// Eth rpc implementation.
pub struct EthClient<C, SN: ?Sized, S: ?Sized, M, EM> where
C: MiningBlockChainClient,
C: miner::BlockChainClient + BlockChainClient,
SN: SnapshotService,
S: SyncProvider,
M: MinerService,
@@ -142,7 +141,7 @@ enum PendingTransactionId {
}
impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S, M, EM> where
C: MiningBlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo,
C: miner::BlockChainClient + BlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo,
SN: SnapshotService,
S: SyncProvider,
M: MinerService<State=T>,
@@ -420,7 +419,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S
}
pub fn pending_logs<M>(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFilter) -> Vec<Log> where M: MinerService {
let receipts = miner.pending_receipts(best_block);
let receipts = miner.pending_receipts(best_block).unwrap_or_default();
let pending_logs = receipts.into_iter()
.flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::<Vec<(H256, LogEntry)>>())
@@ -438,7 +437,7 @@ pub fn pending_logs<M>(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFi
result
}
fn check_known<C>(client: &C, number: BlockNumber) -> Result<()> where C: MiningBlockChainClient {
fn check_known<C>(client: &C, number: BlockNumber) -> Result<()> where C: BlockChainClient {
use ethcore::block_status::BlockStatus;
let id = match number {
@@ -458,7 +457,7 @@ fn check_known<C>(client: &C, number: BlockNumber) -> Result<()> where C: Mining
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<C, SN, S, M, EM> where
C: MiningBlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo + 'static,
C: miner::BlockChainClient + BlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo + 'static,
SN: SnapshotService + 'static,
S: SyncProvider + 'static,
M: MinerService<State=T> + 'static,
@@ -506,7 +505,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
fn author(&self, meta: Metadata) -> Result<RpcH160> {
let dapp = meta.dapp_id();
let mut miner = self.miner.author();
let mut miner = self.miner.authoring_params().author;
if miner == 0.into() {
miner = self.dapp_accounts(dapp.into())?.get(0).cloned().unwrap_or_default();
}
@@ -571,16 +570,8 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
let res = match num.unwrap_or_default() {
BlockNumber::Pending if self.options.pending_nonce_from_queue => {
let nonce = self.miner.last_nonce(&address)
.map(|n| n + 1.into())
.or_else(|| self.client.nonce(&address, BlockId::Latest));
match nonce {
Some(nonce) => Ok(nonce.into()),
None => Err(errors::database("latest nonce missing"))
}
},
Ok(self.miner.next_nonce(&*self.client, &address).into())
}
BlockNumber::Pending => {
let info = self.client.chain_info();
let nonce = self.miner
@@ -596,7 +587,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
None => Err(errors::database("latest nonce missing"))
}
},
number => {
try_bf!(check_known(&*self.client, number.clone()));
match self.client.nonce(&address, block_number_to_id(number)) {
@@ -615,13 +605,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
}
fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
let block_number = self.client.chain_info().best_block_number;
Box::new(future::ok(match num {
BlockNumber::Pending => Some(
self.miner.status().transactions_in_pending_block.into()
),
BlockNumber::Pending =>
self.miner.pending_transactions(block_number).map(|x| x.len().into()),
_ =>
self.client.block(block_number_to_id(num))
.map(|block| block.transactions_count().into())
self.client.block(block_number_to_id(num)).map(|block| block.transactions_count().into())
}))
}
@@ -665,8 +655,8 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
let hash: H256 = hash.into();
let block_number = self.client.chain_info().best_block_number;
let tx = try_bf!(self.transaction(PendingTransactionId::Hash(hash))).or_else(|| {
self.miner.transaction(block_number, &hash)
.map(|t| Transaction::from_pending(t, block_number, self.eip86_transition))
self.miner.transaction(&hash)
.map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition))
});
Box::new(future::ok(tx))
@@ -745,11 +735,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
}
fn work(&self, no_new_work_timeout: Trailing<u64>) -> Result<Work> {
if !self.miner.can_produce_work_package() {
warn!(target: "miner", "Cannot give work package - engine seals internally.");
return Err(errors::no_work_required())
}
let no_new_work_timeout = no_new_work_timeout.unwrap_or_default();
// check if we're still syncing and return empty strings in that case
@@ -768,50 +753,58 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
}
}
if self.miner.author().is_zero() {
if self.miner.authoring_params().author.is_zero() {
warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!");
return Err(errors::no_author())
}
self.miner.map_sealing_work(&*self.client, |b| {
let pow_hash = b.hash();
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
let seed_hash = self.seed_compute.lock().hash_block_number(b.block().header().number());
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs();
if no_new_work_timeout > 0 && b.block().header().timestamp() + no_new_work_timeout < now {
Err(errors::no_new_work())
} else if self.options.send_block_number_in_get_work {
let block_number = b.block().header().number();
Ok(Work {
pow_hash: pow_hash.into(),
seed_hash: seed_hash.into(),
target: target.into(),
number: Some(block_number),
})
} else {
Ok(Work {
pow_hash: pow_hash.into(),
seed_hash: seed_hash.into(),
target: target.into(),
number: None
})
}
}).unwrap_or(Err(errors::internal("No work found.", "")))
let work = self.miner.work_package(&*self.client).ok_or_else(|| {
warn!(target: "miner", "Cannot give work package - engine seals internally.");
errors::no_work_required()
})?;
let (pow_hash, number, timestamp, difficulty) = work;
let target = Ethash::difficulty_to_boundary(&difficulty);
let seed_hash = self.seed_compute.lock().hash_block_number(number);
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs();
if no_new_work_timeout > 0 && timestamp + no_new_work_timeout < now {
Err(errors::no_new_work())
} else if self.options.send_block_number_in_get_work {
Ok(Work {
pow_hash: pow_hash.into(),
seed_hash: seed_hash.into(),
target: target.into(),
number: Some(number),
})
} else {
Ok(Work {
pow_hash: pow_hash.into(),
seed_hash: seed_hash.into(),
target: target.into(),
number: None
})
}
}
fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result<bool> {
if !self.miner.can_produce_work_package() {
warn!(target: "miner", "Cannot submit work - engine seals internally.");
return Err(errors::no_work_required())
}
// TODO [ToDr] Should disallow submissions in case of PoA?
let nonce: H64 = nonce.into();
let pow_hash: H256 = pow_hash.into();
let mix_hash: H256 = mix_hash.into();
trace!(target: "miner", "submit_work: Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash);
let seal = vec![rlp::encode(&mix_hash).into_vec(), rlp::encode(&nonce).into_vec()];
Ok(self.miner.submit_seal(&*self.client, pow_hash, seal).is_ok())
let import = self.miner.submit_seal(pow_hash, seal)
.and_then(|block| self.client.import_sealed_block(block));
match import {
Ok(_) => Ok(true),
Err(err) => {
warn!(target: "miner", "Cannot submit work - {:?}.", err);
Ok(false)
},
}
}
fn submit_hashrate(&self, rate: RpcU256, id: RpcH256) -> Result<bool> {

View File

@@ -19,7 +19,7 @@
use std::sync::Arc;
use std::collections::HashSet;
use ethcore::miner::MinerService;
use ethcore::miner::{self, MinerService};
use ethcore::filter::Filter as EthcoreFilter;
use ethcore::client::{BlockChainClient, BlockId};
use ethereum_types::H256;
@@ -42,7 +42,7 @@ pub trait Filterable {
fn block_hash(&self, id: BlockId) -> Option<RpcH256>;
/// pending transaction hashes at the given block.
fn pending_transactions_hashes(&self, block_number: u64) -> Vec<H256>;
fn pending_transactions_hashes(&self) -> Vec<H256>;
/// Get logs that match the given filter.
fn logs(&self, filter: EthcoreFilter) -> BoxFuture<Vec<Log>>;
@@ -55,16 +55,13 @@ pub trait Filterable {
}
/// Eth filter rpc implementation for a full node.
pub struct EthFilterClient<C, M> where
C: BlockChainClient,
M: MinerService {
pub struct EthFilterClient<C, M> {
client: Arc<C>,
miner: Arc<M>,
polls: Mutex<PollManager<PollFilter>>,
}
impl<C, M> EthFilterClient<C, M> where C: BlockChainClient, M: MinerService {
impl<C, M> EthFilterClient<C, M> {
/// Creates new Eth filter client.
pub fn new(client: Arc<C>, miner: Arc<M>) -> Self {
EthFilterClient {
@@ -75,7 +72,10 @@ impl<C, M> EthFilterClient<C, M> where C: BlockChainClient, M: MinerService {
}
}
impl<C, M> Filterable for EthFilterClient<C, M> where C: BlockChainClient, M: MinerService {
impl<C, M> Filterable for EthFilterClient<C, M> where
C: miner::BlockChainClient + BlockChainClient,
M: MinerService,
{
fn best_block_number(&self) -> u64 {
self.client.chain_info().best_block_number
}
@@ -84,8 +84,11 @@ impl<C, M> Filterable for EthFilterClient<C, M> where C: BlockChainClient, M: Mi
self.client.block_hash(id).map(Into::into)
}
fn pending_transactions_hashes(&self, best: u64) -> Vec<H256> {
self.miner.pending_transactions_hashes(best)
fn pending_transactions_hashes(&self) -> Vec<H256> {
self.miner.ready_transactions(&*self.client)
.into_iter()
.map(|tx| tx.signed().hash())
.collect()
}
fn logs(&self, filter: EthcoreFilter) -> BoxFuture<Vec<Log>> {
@@ -118,8 +121,7 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
fn new_pending_transaction_filter(&self) -> Result<RpcU256> {
let mut polls = self.polls().lock();
let best_block = self.best_block_number();
let pending_transactions = self.pending_transactions_hashes(best_block);
let pending_transactions = self.pending_transactions_hashes();
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
Ok(id.into())
}
@@ -143,8 +145,7 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
},
PollFilter::PendingTransaction(ref mut previous_hashes) => {
// get hashes of pending transactions
let best_block = self.best_block_number();
let current_hashes = self.pending_transactions_hashes(best_block);
let current_hashes = self.pending_transactions_hashes();
let new_hashes =
{

View File

@@ -533,7 +533,7 @@ impl<T: LightChainClient + 'static> Filterable for EthClient<T> {
self.client.block_hash(id).map(Into::into)
}
fn pending_transactions_hashes(&self, _block_number: u64) -> Vec<::ethereum_types::H256> {
fn pending_transactions_hashes(&self) -> Vec<::ethereum_types::H256> {
Vec::new()
}

View File

@@ -275,6 +275,21 @@ impl Parity for ParityClient {
)
}
fn all_transactions(&self) -> Result<Vec<Transaction>> {
let txq = self.light_dispatch.transaction_queue.read();
let chain_info = self.light_dispatch.client.chain_info();
let current = txq.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp);
let future = txq.future_transactions(chain_info.best_block_number, chain_info.best_block_timestamp);
Ok(
current
.into_iter()
.chain(future.into_iter())
.map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition))
.collect::<Vec<_>>()
)
}
fn future_transactions(&self) -> Result<Vec<Transaction>> {
let txq = self.light_dispatch.transaction_queue.read();
let chain_info = self.light_dispatch.client.chain_info();

View File

@@ -27,9 +27,9 @@ use ethkey::{Brain, Generator};
use ethstore::random_phrase;
use sync::{SyncProvider, ManageNetwork};
use ethcore::account_provider::AccountProvider;
use ethcore::client::{MiningBlockChainClient, StateClient, Call};
use ethcore::client::{BlockChainClient, StateClient, Call};
use ethcore::ids::BlockId;
use ethcore::miner::MinerService;
use ethcore::miner::{self, MinerService};
use ethcore::mode::Mode;
use ethcore::state::StateInfo;
use ethcore_logger::RotatingLogger;
@@ -72,7 +72,7 @@ pub struct ParityClient<C, M, U> {
}
impl<C, M, U> ParityClient<C, M, U> where
C: MiningBlockChainClient,
C: BlockChainClient,
{
/// Creates new `ParityClient`.
pub fn new(
@@ -116,7 +116,7 @@ impl<C, M, U> ParityClient<C, M, U> where
impl<C, M, U, S> Parity for ParityClient<C, M, U> where
S: StateInfo + 'static,
C: MiningBlockChainClient + StateClient<State=S> + Call<State=S> + 'static,
C: miner::BlockChainClient + BlockChainClient + StateClient<State=S> + Call<State=S> + 'static,
M: MinerService<State=S> + 'static,
U: UpdateService + 'static,
{
@@ -170,23 +170,23 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
}
fn transactions_limit(&self) -> Result<usize> {
Ok(self.miner.transactions_limit())
Ok(self.miner.queue_status().limits.max_count)
}
fn min_gas_price(&self) -> Result<U256> {
Ok(U256::from(self.miner.minimal_gas_price()))
Ok(self.miner.queue_status().options.minimal_gas_price.into())
}
fn extra_data(&self) -> Result<Bytes> {
Ok(Bytes::new(self.miner.extra_data()))
Ok(Bytes::new(self.miner.authoring_params().extra_data))
}
fn gas_floor_target(&self) -> Result<U256> {
Ok(U256::from(self.miner.gas_floor_target()))
Ok(U256::from(self.miner.authoring_params().gas_range_target.0))
}
fn gas_ceil_target(&self) -> Result<U256> {
Ok(U256::from(self.miner.gas_ceil_target()))
Ok(U256::from(self.miner.authoring_params().gas_range_target.1))
}
fn dev_logs(&self) -> Result<Vec<String>> {
@@ -315,12 +315,28 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
fn pending_transactions(&self) -> Result<Vec<Transaction>> {
let block_number = self.client.chain_info().best_block_number;
Ok(self.miner.pending_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::<Vec<_>>())
let ready_transactions = self.miner.ready_transactions(&*self.client);
Ok(ready_transactions
.into_iter()
.map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition))
.collect()
)
}
fn all_transactions(&self) -> Result<Vec<Transaction>> {
let block_number = self.client.chain_info().best_block_number;
let all_transactions = self.miner.queued_transactions();
Ok(all_transactions
.into_iter()
.map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition))
.collect()
)
}
fn future_transactions(&self) -> Result<Vec<Transaction>> {
let block_number = self.client.chain_info().best_block_number;
Ok(self.miner.future_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::<Vec<_>>())
Err(errors::deprecated("Use `parity_allTransaction` instead."))
}
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>> {
@@ -359,11 +375,7 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
fn next_nonce(&self, address: H160) -> BoxFuture<U256> {
let address: Address = address.into();
Box::new(future::ok(self.miner.last_nonce(&address)
.map(|n| n + 1.into())
.unwrap_or_else(|| self.client.latest_nonce(&address))
.into()
))
Box::new(future::ok(self.miner.next_nonce(&*self.client, &address).into()))
}
fn mode(&self) -> Result<String> {

View File

@@ -18,8 +18,8 @@
use std::io;
use std::sync::Arc;
use ethcore::client::BlockChainClient;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use ethcore::mode::Mode;
use sync::ManageNetwork;
use fetch::{self, Fetch};
@@ -47,7 +47,7 @@ pub struct ParitySetClient<C, M, U, F = fetch::Client> {
}
impl<C, M, U, F> ParitySetClient<C, M, U, F>
where C: MiningBlockChainClient + 'static,
where C: BlockChainClient + 'static,
{
/// Creates new `ParitySetClient` with given `Fetch`.
pub fn new(
@@ -73,24 +73,38 @@ impl<C, M, U, F> ParitySetClient<C, M, U, F>
}
impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
C: MiningBlockChainClient + 'static,
C: BlockChainClient + 'static,
M: MinerService + 'static,
U: UpdateService + 'static,
F: Fetch + 'static,
{
fn set_min_gas_price(&self, gas_price: U256) -> Result<bool> {
self.miner.set_minimal_gas_price(gas_price.into());
Ok(true)
fn set_min_gas_price(&self, _gas_price: U256) -> Result<bool> {
warn!("setMinGasPrice is deprecated. Ignoring request.");
Ok(false)
}
fn set_transactions_limit(&self, _limit: usize) -> Result<bool> {
warn!("setTransactionsLimit is deprecated. Ignoring request.");
Ok(false)
}
fn set_tx_gas_limit(&self, _limit: U256) -> Result<bool> {
warn!("setTxGasLimit is deprecated. Ignoring request.");
Ok(false)
}
fn set_gas_floor_target(&self, target: U256) -> Result<bool> {
self.miner.set_gas_floor_target(target.into());
let mut range = self.miner.authoring_params().gas_range_target.clone();
range.0 = target.into();
self.miner.set_gas_range_target(range);
Ok(true)
}
fn set_gas_ceil_target(&self, target: U256) -> Result<bool> {
self.miner.set_gas_ceil_target(target.into());
let mut range = self.miner.authoring_params().gas_range_target.clone();
range.1 = target.into();
self.miner.set_gas_range_target(range);
Ok(true)
}
@@ -99,23 +113,13 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
Ok(true)
}
fn set_author(&self, author: H160) -> Result<bool> {
self.miner.set_author(author.into());
fn set_author(&self, address: H160) -> Result<bool> {
self.miner.set_author(address.into(), None).map_err(Into::into).map_err(errors::password)?;
Ok(true)
}
fn set_engine_signer(&self, address: H160, password: String) -> Result<bool> {
self.miner.set_engine_signer(address.into(), password).map_err(Into::into).map_err(errors::password)?;
Ok(true)
}
fn set_transactions_limit(&self, limit: usize) -> Result<bool> {
self.miner.set_transactions_limit(limit);
Ok(true)
}
fn set_tx_gas_limit(&self, limit: U256) -> Result<bool> {
self.miner.set_tx_gas_limit(limit.into());
self.miner.set_author(address.into(), Some(password)).map_err(Into::into).map_err(errors::password)?;
Ok(true)
}
@@ -202,6 +206,8 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
let block_number = self.client.chain_info().best_block_number;
let hash = hash.into();
Ok(self.miner.remove_pending_transaction(&*self.client, &hash).map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)))
Ok(self.miner.remove_transaction(&hash)
.map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition))
)
}
}

View File

@@ -18,7 +18,7 @@
use std::sync::Arc;
use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId};
use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId};
use rlp::UntrustedRlp;
use transaction::SignedTransaction;
@@ -53,7 +53,7 @@ impl<C> TracesClient<C> {
impl<C, S> Traces for TracesClient<C> where
S: StateInfo + 'static,
C: MiningBlockChainClient + StateClient<State=S> + Call<State=S> + 'static
C: BlockChainClient + StateClient<State=S> + Call<State=S> + 'static
{
type Metadata = Metadata;

View File

@@ -17,15 +17,14 @@
//! rpc integration tests.
use std::env;
use std::sync::Arc;
use std::time::Duration;
use ethereum_types::{U256, H256, Address};
use ethereum_types::{H256, Address};
use ethcore::account_provider::AccountProvider;
use ethcore::block::Block;
use ethcore::client::{BlockChainClient, Client, ClientConfig, ChainInfo, ImportBlock};
use ethcore::ethereum;
use ethcore::ids::BlockId;
use ethcore::miner::{MinerOptions, Banning, GasPricer, Miner, PendingSet, GasLimit};
use ethcore::miner::Miner;
use ethcore::spec::{Genesis, Spec};
use ethcore::views::BlockView;
use ethjson::blockchain::BlockChain;
@@ -33,7 +32,6 @@ use ethjson::state::test::ForkSpec;
use io::IoChannel;
use kvdb_memorydb;
use miner::external::ExternalMiner;
use miner::transaction_queue::PrioritizationStrategy;
use parking_lot::Mutex;
use jsonrpc_core::IoHandler;
@@ -58,30 +56,7 @@ fn sync_provider() -> Arc<TestSyncProvider> {
}
fn miner_service(spec: &Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
Miner::new(
MinerOptions {
force_sealing: true,
reseal_on_external_tx: true,
reseal_on_own_tx: true,
reseal_on_uncle: false,
tx_queue_size: 1024,
tx_gas_limit: !U256::zero(),
tx_queue_strategy: PrioritizationStrategy::GasPriceOnly,
tx_queue_gas_limit: GasLimit::None,
tx_queue_banning: Banning::Disabled,
tx_queue_memory_limit: None,
pending_set: PendingSet::SealingOrElseQueue,
reseal_min_period: Duration::from_secs(0),
reseal_max_period: Duration::from_secs(120),
work_queue_size: 50,
enable_resubmission: true,
refuse_service_transactions: false,
infinite_pending_block: false,
},
GasPricer::new_fixed(20_000_000_000u64.into()),
&spec,
Some(accounts),
)
Arc::new(Miner::new_for_tests(spec, Some(accounts)))
}
fn snapshot_service() -> Arc<TestSnapshotService> {

View File

@@ -16,82 +16,68 @@
//! Test implementation of miner service.
use std::sync::Arc;
use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map::Entry;
use bytes::Bytes;
use ethcore::account_provider::SignError as AccountError;
use ethcore::block::{Block, ClosedBlock};
use ethcore::block::{Block, SealedBlock, IsBlock};
use ethcore::client::{Nonce, PrepareOpenBlock, StateClient, EngineInfo};
use ethcore::engines::EthEngine;
use ethcore::error::Error;
use ethcore::header::{BlockNumber, Header};
use ethcore::ids::BlockId;
use ethcore::miner::{MinerService, MinerStatus};
use ethcore::miner::{MinerService, AuthoringParams};
use ethcore::receipt::{Receipt, RichReceipt};
use ethereum_types::{H256, U256, Address};
use miner::local_transactions::Status as LocalTransactionStatus;
use miner::pool::local_transactions::Status as LocalTransactionStatus;
use miner::pool::{verifier, VerifiedTransaction, QueueStatus};
use parking_lot::{RwLock, Mutex};
use transaction::{UnverifiedTransaction, SignedTransaction, PendingTransaction, ImportResult as TransactionImportResult};
use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction};
use txpool;
/// Test miner service.
pub struct TestMinerService {
/// Imported transactions.
pub imported_transactions: Mutex<Vec<SignedTransaction>>,
/// Latest closed block.
pub latest_closed_block: Mutex<Option<ClosedBlock>>,
/// Pre-existed pending transactions
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
/// Pre-existed local transactions
pub local_transactions: Mutex<BTreeMap<H256, LocalTransactionStatus>>,
/// Pre-existed pending receipts
pub pending_receipts: Mutex<BTreeMap<H256, Receipt>>,
/// Last nonces.
pub last_nonces: RwLock<HashMap<Address, U256>>,
/// Next nonces.
pub next_nonces: RwLock<HashMap<Address, U256>>,
/// Password held by Engine.
pub password: RwLock<String>,
min_gas_price: RwLock<U256>,
gas_range_target: RwLock<(U256, U256)>,
author: RwLock<Address>,
extra_data: RwLock<Bytes>,
limit: RwLock<usize>,
tx_gas_limit: RwLock<U256>,
authoring_params: RwLock<AuthoringParams>,
}
impl Default for TestMinerService {
fn default() -> TestMinerService {
TestMinerService {
imported_transactions: Mutex::new(Vec::new()),
latest_closed_block: Mutex::new(None),
pending_transactions: Mutex::new(HashMap::new()),
local_transactions: Mutex::new(BTreeMap::new()),
pending_receipts: Mutex::new(BTreeMap::new()),
last_nonces: RwLock::new(HashMap::new()),
min_gas_price: RwLock::new(U256::from(20_000_000)),
gas_range_target: RwLock::new((U256::from(12345), U256::from(54321))),
author: RwLock::new(Address::zero()),
next_nonces: RwLock::new(HashMap::new()),
password: RwLock::new(String::new()),
extra_data: RwLock::new(vec![1, 2, 3, 4]),
limit: RwLock::new(1024),
tx_gas_limit: RwLock::new(!U256::zero()),
authoring_params: RwLock::new(AuthoringParams {
author: Address::zero(),
gas_range_target: (12345.into(), 54321.into()),
extra_data: vec![1, 2, 3, 4],
}),
}
}
}
impl TestMinerService {
/// Increments last nonce for given address.
pub fn increment_last_nonce(&self, address: Address) {
let mut last_nonces = self.last_nonces.write();
match last_nonces.entry(address) {
Entry::Occupied(mut occupied) => {
let val = *occupied.get();
*occupied.get_mut() = val + 1.into();
},
Entry::Vacant(vacant) => {
vacant.insert(0.into());
},
}
/// Increments nonce for given address.
pub fn increment_nonce(&self, address: &Address) {
let mut next_nonces = self.next_nonces.write();
let nonce = next_nonces.entry(*address).or_insert_with(|| 0.into());
*nonce = *nonce + 1.into();
}
}
@@ -129,164 +115,112 @@ impl MinerService for TestMinerService {
None
}
/// Returns miner's status.
fn status(&self) -> MinerStatus {
MinerStatus {
transactions_in_pending_queue: 0,
transactions_in_future_queue: 0,
transactions_in_pending_block: 1
fn authoring_params(&self) -> AuthoringParams {
self.authoring_params.read().clone()
}
fn set_author(&self, author: Address, password: Option<String>) -> Result<(), AccountError> {
self.authoring_params.write().author = author;
if let Some(password) = password {
*self.password.write() = password;
}
}
fn set_author(&self, author: Address) {
*self.author.write() = author;
}
fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> {
*self.author.write() = address;
*self.password.write() = password;
Ok(())
}
fn set_extra_data(&self, extra_data: Bytes) {
*self.extra_data.write() = extra_data;
self.authoring_params.write().extra_data = extra_data;
}
/// Set the lower gas limit we wish to target when sealing a new block.
fn set_gas_floor_target(&self, target: U256) {
self.gas_range_target.write().0 = target;
}
/// Set the upper gas limit we wish to target when sealing a new block.
fn set_gas_ceil_target(&self, target: U256) {
self.gas_range_target.write().1 = target;
}
fn set_minimal_gas_price(&self, min_gas_price: U256) {
*self.min_gas_price.write() = min_gas_price;
}
fn set_transactions_limit(&self, limit: usize) {
*self.limit.write() = limit;
}
fn set_tx_gas_limit(&self, limit: U256) {
*self.tx_gas_limit.write() = limit;
}
fn transactions_limit(&self) -> usize {
*self.limit.read()
}
fn author(&self) -> Address {
*self.author.read()
}
fn minimal_gas_price(&self) -> U256 {
*self.min_gas_price.read()
}
fn extra_data(&self) -> Bytes {
self.extra_data.read().clone()
}
fn gas_floor_target(&self) -> U256 {
self.gas_range_target.read().0
}
fn gas_ceil_target(&self) -> U256 {
self.gas_range_target.read().1
fn set_gas_range_target(&self, target: (U256, U256)) {
self.authoring_params.write().gas_range_target = target;
}
/// Imports transactions to transaction queue.
fn import_external_transactions<C>(&self, _chain: &C, transactions: Vec<UnverifiedTransaction>) ->
Vec<Result<TransactionImportResult, Error>> {
fn import_external_transactions<C: Nonce + Sync>(&self, chain: &C, transactions: Vec<UnverifiedTransaction>)
-> Vec<Result<(), transaction::Error>>
{
// lets assume that all txs are valid
let transactions: Vec<_> = transactions.into_iter().map(|tx| SignedTransaction::new(tx).unwrap()).collect();
self.imported_transactions.lock().extend_from_slice(&transactions);
for sender in transactions.iter().map(|tx| tx.sender()) {
let nonce = self.last_nonce(&sender).expect("last_nonce must be populated in tests");
self.last_nonces.write().insert(sender, nonce + U256::from(1));
let nonce = self.next_nonce(chain, &sender);
self.next_nonces.write().insert(sender, nonce);
}
transactions
.iter()
.map(|_| Ok(TransactionImportResult::Current))
.map(|_| Ok(()))
.collect()
}
/// Imports transactions to transaction queue.
fn import_own_transaction<C: Nonce>(&self, chain: &C, pending: PendingTransaction) ->
Result<TransactionImportResult, Error> {
fn import_own_transaction<C: Nonce + Sync>(&self, chain: &C, pending: PendingTransaction)
-> Result<(), transaction::Error> {
// keep the pending nonces up to date
let sender = pending.transaction.sender();
let nonce = self.last_nonce(&sender).unwrap_or(chain.latest_nonce(&sender));
self.last_nonces.write().insert(sender, nonce + U256::from(1));
let nonce = self.next_nonce(chain, &sender);
self.next_nonces.write().insert(sender, nonce);
// lets assume that all txs are valid
self.imported_transactions.lock().push(pending.transaction);
Ok(TransactionImportResult::Current)
}
/// Returns hashes of transactions currently in pending
fn pending_transactions_hashes(&self, _best_block: BlockNumber) -> Vec<H256> {
vec![]
}
/// Removes all transactions from the queue and restart mining operation.
fn clear_and_reset<C>(&self, _chain: &C) {
unimplemented!();
Ok(())
}
/// Called when blocks are imported to chain, updates transactions queue.
fn chain_new_blocks<C>(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
fn chain_new_blocks<C>(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256], _is_internal: bool) {
unimplemented!();
}
/// PoW chain - can produce work package
fn can_produce_work_package(&self) -> bool {
true
}
/// New chain head event. Restart mining operation.
fn update_sealing<C>(&self, _chain: &C) {
unimplemented!();
}
fn map_sealing_work<C: PrepareOpenBlock, F, T>(&self, chain: &C, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
let open_block = chain.prepare_open_block(self.author(), *self.gas_range_target.write(), self.extra_data());
Some(f(&open_block.close()))
fn work_package<C: PrepareOpenBlock>(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> {
let params = self.authoring_params();
let open_block = chain.prepare_open_block(params.author, params.gas_range_target, params.extra_data);
let closed = open_block.close();
let header = closed.header();
Some((header.hash(), header.number(), header.timestamp(), *header.difficulty()))
}
fn transaction(&self, _best_block: BlockNumber, hash: &H256) -> Option<PendingTransaction> {
self.pending_transactions.lock().get(hash).cloned().map(Into::into)
fn transaction(&self, hash: &H256) -> Option<Arc<VerifiedTransaction>> {
self.pending_transactions.lock().get(hash).cloned().map(|tx| {
Arc::new(VerifiedTransaction::from_pending_block_transaction(tx))
})
}
fn remove_pending_transaction<C>(&self, _chain: &C, hash: &H256) -> Option<PendingTransaction> {
self.pending_transactions.lock().remove(hash).map(Into::into)
fn remove_transaction(&self, hash: &H256) -> Option<Arc<VerifiedTransaction>> {
self.pending_transactions.lock().remove(hash).map(|tx| {
Arc::new(VerifiedTransaction::from_pending_block_transaction(tx))
})
}
fn pending_transactions(&self) -> Vec<PendingTransaction> {
self.pending_transactions.lock().values().cloned().map(Into::into).collect()
fn pending_transactions(&self, _best_block: BlockNumber) -> Option<Vec<SignedTransaction>> {
Some(self.pending_transactions.lock().values().cloned().collect())
}
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect()
}
fn ready_transactions(&self, _best_block: BlockNumber, _best_timestamp: u64) -> Vec<PendingTransaction> {
self.pending_transactions.lock().values().cloned().map(Into::into).collect()
fn ready_transactions<C>(&self, _chain: &C) -> Vec<Arc<VerifiedTransaction>> {
self.queued_transactions()
}
fn future_transactions(&self) -> Vec<PendingTransaction> {
vec![]
fn queued_transactions(&self) -> Vec<Arc<VerifiedTransaction>> {
self.pending_transactions.lock().values().cloned().map(|tx| {
Arc::new(VerifiedTransaction::from_pending_block_transaction(tx))
}).collect()
}
fn pending_receipt(&self, _best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
// Not much point implementing this since the logic is complex and the only thing it relies on is pending_receipts, which is already tested.
self.pending_receipts(0).get(hash).map(|r|
self.pending_receipts(0).unwrap().get(hash).map(|r|
RichReceipt {
transaction_hash: Default::default(),
transaction_index: Default::default(),
@@ -300,25 +234,49 @@ impl MinerService for TestMinerService {
)
}
fn pending_receipts(&self, _best_block: BlockNumber) -> BTreeMap<H256, Receipt> {
self.pending_receipts.lock().clone()
fn pending_receipts(&self, _best_block: BlockNumber) -> Option<BTreeMap<H256, Receipt>> {
Some(self.pending_receipts.lock().clone())
}
fn last_nonce(&self, address: &Address) -> Option<U256> {
self.last_nonces.read().get(address).cloned()
fn next_nonce<C: Nonce + Sync>(&self, _chain: &C, address: &Address) -> U256 {
self.next_nonces.read().get(address).cloned().unwrap_or_default()
}
fn is_currently_sealing(&self) -> bool {
false
}
fn queue_status(&self) -> QueueStatus {
QueueStatus {
options: verifier::Options {
minimal_gas_price: 0x1312d00.into(),
block_gas_limit: 5_000_000.into(),
tx_gas_limit: 5_000_000.into(),
},
status: txpool::LightStatus {
mem_usage: 1_000,
transaction_count: 52,
senders: 1,
},
limits: txpool::Options {
max_count: 1_024,
max_per_sender: 16,
max_mem_usage: 5_000,
},
}
}
/// Submit `seal` as a valid solution for the header of `pow_hash`.
/// Will check the seal, but not actually insert the block into the chain.
fn submit_seal<C>(&self, _chain: &C, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
fn submit_seal(&self, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<SealedBlock, Error> {
unimplemented!();
}
fn sensible_gas_price(&self) -> U256 {
20000000000u64.into()
20_000_000_000u64.into()
}
fn sensible_gas_limit(&self) -> U256 {
0x5208.into()
}
}

View File

@@ -368,7 +368,7 @@ fn rpc_eth_author() {
for i in 0..20 {
let addr = tester.accounts_provider.new_account(&format!("{}", i)).unwrap();
tester.miner.set_author(addr.clone());
tester.miner.set_author(addr.clone(), None).unwrap();
assert_eq!(tester.io.handle_request_sync(req), Some(make_res(addr)));
}
@@ -377,7 +377,7 @@ fn rpc_eth_author() {
#[test]
fn rpc_eth_mining() {
let tester = EthTester::default();
tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap());
tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "eth_mining", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
@@ -498,7 +498,7 @@ fn rpc_eth_transaction_count_next_nonce() {
let tester = EthTester::new_with_options(EthClientOptions::with(|options| {
options.pending_nonce_from_queue = true;
}));
tester.miner.increment_last_nonce(1.into());
tester.miner.increment_nonce(&1.into());
let request1 = r#"{
"jsonrpc": "2.0",
@@ -553,7 +553,7 @@ fn rpc_eth_transaction_count_by_number_pending() {
"params": ["pending"],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x1","id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x0","id":1}"#;
assert_eq!(EthTester::default().io.handle_request_sync(request), Some(response.to_owned()));
}
@@ -835,7 +835,7 @@ fn rpc_eth_send_transaction() {
assert_eq!(tester.io.handle_request_sync(&request), Some(response));
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
tester.miner.increment_nonce(&address);
let t = Transaction {
nonce: U256::one(),
@@ -905,7 +905,7 @@ fn rpc_eth_sign_transaction() {
r#""value":"0x9184e72a""# +
r#"}},"id":1}"#;
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
tester.miner.increment_nonce(&address);
assert_eq!(tester.io.handle_request_sync(&request), Some(response));
}
@@ -1118,7 +1118,7 @@ fn rpc_get_work_returns_no_work_if_cant_mine() {
#[test]
fn rpc_get_work_returns_correct_work_package() {
let eth_tester = EthTester::default();
eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap());
eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x76c7bd86693aee93d1a80a408a09a0585b1a1292afcb56192f171d925ea18e2d","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000","0x1"],"id":1}"#;
@@ -1131,7 +1131,7 @@ fn rpc_get_work_should_not_return_block_number() {
let eth_tester = EthTester::new_with_options(EthClientOptions::with(|options| {
options.send_block_number_in_get_work = false;
}));
eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap());
eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x76c7bd86693aee93d1a80a408a09a0585b1a1292afcb56192f171d925ea18e2d","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000"],"id":1}"#;
@@ -1142,10 +1142,10 @@ fn rpc_get_work_should_not_return_block_number() {
#[test]
fn rpc_get_work_should_timeout() {
let eth_tester = EthTester::default();
eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap());
eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap();
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() - 1000; // Set latest block to 1000 seconds ago
eth_tester.client.set_latest_block_timestamp(timestamp);
let hash = eth_tester.miner.map_sealing_work(&*eth_tester.client, |b| b.hash()).unwrap();
let hash = eth_tester.miner.work_package(&*eth_tester.client).unwrap().0;
// Request without providing timeout. This should work since we're disabling timeout.
let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#;

View File

@@ -17,13 +17,13 @@
use std::sync::Arc;
use ethcore::account_provider::AccountProvider;
use ethcore::client::{TestBlockChainClient, Executed};
use ethcore::miner::LocalTransactionStatus;
use ethcore_logger::RotatingLogger;
use ethereum_types::{Address, U256, H256};
use ethstore::ethkey::{Generator, Random};
use sync::ManageNetwork;
use miner::pool::local_transactions::Status as LocalTransactionStatus;
use node_health::{self, NodeHealth};
use parity_reactor;
use ethereum_types::{Address, U256, H256};
use sync::ManageNetwork;
use jsonrpc_core::IoHandler;
use v1::{Parity, ParityClient};
@@ -455,7 +455,9 @@ fn rpc_parity_next_nonce() {
let address = Address::default();
let io1 = deps.default_client();
let deps = Dependencies::new();
deps.miner.last_nonces.write().insert(address.clone(), 2.into());
deps.miner.increment_nonce(&address);
deps.miner.increment_nonce(&address);
deps.miner.increment_nonce(&address);
let io2 = deps.default_client();
let request = r#"{
@@ -486,11 +488,20 @@ fn rpc_parity_transactions_stats() {
fn rpc_parity_local_transactions() {
let deps = Dependencies::new();
let io = deps.default_client();
deps.miner.local_transactions.lock().insert(10.into(), LocalTransactionStatus::Pending);
deps.miner.local_transactions.lock().insert(15.into(), LocalTransactionStatus::Future);
let tx = ::transaction::Transaction {
value: 5.into(),
gas: 3.into(),
gas_price: 2.into(),
action: ::transaction::Action::Create,
data: vec![1, 2, 3],
nonce: 0.into(),
}.fake_sign(3.into());
let tx = Arc::new(::miner::pool::VerifiedTransaction::from_pending_block_transaction(tx));
deps.miner.local_transactions.lock().insert(10.into(), LocalTransactionStatus::Pending(tx.clone()));
deps.miner.local_transactions.lock().insert(15.into(), LocalTransactionStatus::Pending(tx.clone()));
let request = r#"{"jsonrpc": "2.0", "method": "parity_localTransactions", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"0x000000000000000000000000000000000000000000000000000000000000000a":{"status":"pending"},"0x000000000000000000000000000000000000000000000000000000000000000f":{"status":"future"}},"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"0x000000000000000000000000000000000000000000000000000000000000000a":{"status":"pending"},"0x000000000000000000000000000000000000000000000000000000000000000f":{"status":"pending"}},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

View File

@@ -109,10 +109,9 @@ fn rpc_parity_set_min_gas_price() {
io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.minimal_gas_price(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
}
#[test]
@@ -129,7 +128,7 @@ fn rpc_parity_set_gas_floor_target() {
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.gas_floor_target(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
assert_eq!(miner.authoring_params().gas_range_target.0, U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
}
#[test]
@@ -146,7 +145,7 @@ fn rpc_parity_set_extra_data() {
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.extra_data(), "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap());
assert_eq!(miner.authoring_params().extra_data, "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap());
}
#[test]
@@ -162,7 +161,7 @@ fn rpc_parity_set_author() {
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
assert_eq!(miner.authoring_params().author, Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
}
#[test]
@@ -178,7 +177,7 @@ fn rpc_parity_set_engine_signer() {
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
assert_eq!(miner.authoring_params().author, Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
assert_eq!(*miner.password.read(), "password".to_string());
}
@@ -193,10 +192,9 @@ fn rpc_parity_set_transactions_limit() {
io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setTransactionsLimit", "params":[10240240], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.transactions_limit(), 10_240_240);
}
#[test]

View File

@@ -220,7 +220,7 @@ fn sign_and_send_test(method: &str) {
assert_eq!(tester.io.handle_request_sync(request.as_ref()), Some(response));
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
tester.miner.increment_nonce(&address);
let t = Transaction {
nonce: U256::one(),

View File

@@ -327,7 +327,7 @@ fn should_add_sign_transaction_to_the_queue() {
r#"}},"id":1}"#;
// then
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
tester.miner.increment_nonce(&address);
let promise = tester.io.handle_request(&request);
// the future must be polled at least once before request is queued.

View File

@@ -143,7 +143,13 @@ build_rpc_trait! {
#[rpc(name = "parity_pendingTransactions")]
fn pending_transactions(&self) -> Result<Vec<Transaction>>;
/// Returns all future transactions from transaction queue.
/// Returns all transactions from transaction queue.
///
/// Some of them might not be ready to be included in a block yet.
#[rpc(name = "parity_allTransactions")]
fn all_transactions(&self) -> Result<Vec<Transaction>>;
/// Returns all future transactions from transaction queue (deprecated)
#[rpc(name = "parity_futureTransactions")]
fn future_transactions(&self) -> Result<Vec<Transaction>>;

View File

@@ -14,12 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct;
use ethcore::miner;
use ethcore::{contract_address, CreateContractAddress};
use miner;
use transaction::{LocalizedTransaction, Action, PendingTransaction, SignedTransaction};
use v1::helpers::errors;
use v1::types::{Bytes, H160, H256, U256, H512, U64, TransactionCondition};
/// Transaction
@@ -248,17 +249,23 @@ impl Transaction {
impl LocalTransactionStatus {
/// Convert `LocalTransactionStatus` into RPC `LocalTransactionStatus`.
pub fn from(s: miner::LocalTransactionStatus, block_number: u64, eip86_transition: u64) -> Self {
use ethcore::miner::LocalTransactionStatus::*;
pub fn from(s: miner::pool::local_transactions::Status, block_number: u64, eip86_transition: u64) -> Self {
let convert = |tx: Arc<miner::pool::VerifiedTransaction>| {
Transaction::from_signed(tx.signed().clone(), block_number, eip86_transition)
};
use miner::pool::local_transactions::Status::*;
match s {
Pending => LocalTransactionStatus::Pending,
Future => LocalTransactionStatus::Future,
Mined(tx) => LocalTransactionStatus::Mined(Transaction::from_signed(tx, block_number, eip86_transition)),
Dropped(tx) => LocalTransactionStatus::Dropped(Transaction::from_signed(tx, block_number, eip86_transition)),
Rejected(tx, err) => LocalTransactionStatus::Rejected(Transaction::from_signed(tx, block_number, eip86_transition), errors::transaction_message(err)),
Replaced(tx, gas_price, hash) => LocalTransactionStatus::Replaced(Transaction::from_signed(tx, block_number, eip86_transition), gas_price.into(), hash.into()),
Invalid(tx) => LocalTransactionStatus::Invalid(Transaction::from_signed(tx, block_number, eip86_transition)),
Canceled(tx) => LocalTransactionStatus::Canceled(Transaction::from_pending(tx, block_number, eip86_transition)),
Pending(_) => LocalTransactionStatus::Pending,
Mined(tx) => LocalTransactionStatus::Mined(convert(tx)),
Dropped(tx) => LocalTransactionStatus::Dropped(convert(tx)),
Rejected(tx, reason) => LocalTransactionStatus::Rejected(convert(tx), reason),
Invalid(tx) => LocalTransactionStatus::Invalid(convert(tx)),
Canceled(tx) => LocalTransactionStatus::Canceled(convert(tx)),
Replaced { old, new } => LocalTransactionStatus::Replaced(
convert(old),
new.signed().gas_price.into(),
new.signed().hash().into(),
),
}
}
}