Merge branch 'master' of github.com:ethcore/parity into ethrpc_test
This commit is contained in:
commit
a3f6d36018
64
.travis.yml
64
.travis.yml
@ -8,20 +8,43 @@ branches:
|
|||||||
- /^stable-.*$/
|
- /^stable-.*$/
|
||||||
- /^beta$/
|
- /^beta$/
|
||||||
- /^stable$/
|
- /^stable$/
|
||||||
|
git:
|
||||||
|
depth: 3
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: false
|
fast_finish: true
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- rust: nightly
|
- rust: nightly
|
||||||
include:
|
include:
|
||||||
- rust: stable
|
- rust: stable
|
||||||
env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
|
env: FEATURES="--features travis-beta" RUN_TESTS="true"
|
||||||
|
# - rust: beta
|
||||||
|
# env: FEATURES="--features travis-beta" RUN_TESTS="true"
|
||||||
|
- rust: stable
|
||||||
|
env: FEATURES="--features travis-beta" RUN_BUILD="true"
|
||||||
|
- rust: beta
|
||||||
|
env: FEATURES="--features travis-beta" RUN_BUILD="true"
|
||||||
|
- rust: stable
|
||||||
|
env: FEATURES="--features travis-beta" RUN_COVERAGE="true"
|
||||||
|
# - rust: nightly
|
||||||
|
# env: FEATURES="--features travis-nightly" RUN_BENCHES="true"
|
||||||
|
- rust: nightly
|
||||||
|
env: FEATURES="--features travis-nightly" RUN_TESTS="true"
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
# GH_TOKEN
|
||||||
|
- secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw=
|
||||||
|
- TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer"
|
||||||
|
- ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
|
||||||
|
- KCOV_FEATURES=""
|
||||||
|
- KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov"
|
||||||
|
- RUN_TESTS="false"
|
||||||
|
- RUN_COVERAGE="false"
|
||||||
|
- RUN_BUILD="false"
|
||||||
|
- RUN_BENCHES="false"
|
||||||
cache:
|
cache:
|
||||||
apt: true
|
apt: true
|
||||||
directories:
|
directories:
|
||||||
- target/debug/deps
|
- $TRAVIS_BUILD_DIR/target
|
||||||
- target/debug/build
|
|
||||||
- target/release/deps
|
|
||||||
- target/release/build
|
|
||||||
- $HOME/.cargo
|
- $HOME/.cargo
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
@ -29,22 +52,25 @@ addons:
|
|||||||
- libcurl4-openssl-dev
|
- libcurl4-openssl-dev
|
||||||
- libelf-dev
|
- libelf-dev
|
||||||
- libdw-dev
|
- libdw-dev
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cargo build --release --verbose ${FEATURES}
|
- if [ "$RUN_TESTS" = "true" ]; then cargo test --release --verbose ${FEATURES} ${TARGETS}; fi
|
||||||
- cargo test --release --verbose ${FEATURES} ${TARGETS}
|
- if [ "$RUN_BENCHES" = "true" ]; then cargo bench --no-run ${FEATURES} ${TARGETS}; fi
|
||||||
#- cargo bench --no-run ${FEATURES} ${TARGETS}
|
- if [ "$RUN_BUILD" = "true" ]; then cargo build --release --verbose ${FEATURES}; fi
|
||||||
- tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity
|
- if [ "$RUN_BUILD" = "true" ]; then tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity; fi
|
||||||
|
|
||||||
after_success: |
|
after_success: |
|
||||||
|
[ "$RUN_COVERAGE" = "true" ] &&
|
||||||
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
||||||
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
|
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
|
||||||
cargo test --no-run ${KCOV_FEATURES} ${TARGETS} &&
|
cargo test --no-run ${KCOV_FEATURES} ${TARGETS} &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* &&
|
$KCOV_CMD target/debug/deps/ethcore_util-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* &&
|
$KCOV_CMD target/debug/deps/ethash-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* &&
|
$KCOV_CMD target/debug/deps/ethcore-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* &&
|
$KCOV_CMD target/debug/deps/ethsync-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* &&
|
$KCOV_CMD target/debug/deps/ethcore_rpc-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethminer-* &&
|
$KCOV_CMD target/debug/deps/ethminer-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* &&
|
$KCOV_CMD target/debug/parity-* &&
|
||||||
[ $TRAVIS_BRANCH = master ] &&
|
[ $TRAVIS_BRANCH = master ] &&
|
||||||
[ $TRAVIS_PULL_REQUEST = false ] &&
|
[ $TRAVIS_PULL_REQUEST = false ] &&
|
||||||
[ $TRAVIS_RUST_VERSION = stable ] &&
|
[ $TRAVIS_RUST_VERSION = stable ] &&
|
||||||
@ -53,10 +79,6 @@ after_success: |
|
|||||||
pip install --user ghp-import &&
|
pip install --user ghp-import &&
|
||||||
/home/travis/.local/bin/ghp-import -n target/doc &&
|
/home/travis/.local/bin/ghp-import -n target/doc &&
|
||||||
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
||||||
env:
|
|
||||||
global:
|
|
||||||
# GH_TOKEN
|
|
||||||
- secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw=
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: releases
|
provider: releases
|
||||||
|
@ -70,7 +70,14 @@ pub enum TransactionError {
|
|||||||
/// Minimal expected gas price
|
/// Minimal expected gas price
|
||||||
minimal: U256,
|
minimal: U256,
|
||||||
/// Transaction gas price
|
/// Transaction gas price
|
||||||
got: U256
|
got: U256,
|
||||||
|
},
|
||||||
|
/// Sender doesn't have enough funds to pay for this transaction
|
||||||
|
InsufficientBalance {
|
||||||
|
/// Senders balance
|
||||||
|
balance: U256,
|
||||||
|
/// Transaction cost
|
||||||
|
cost: U256,
|
||||||
},
|
},
|
||||||
/// Transaction's gas limit (aka gas) is invalid.
|
/// Transaction's gas limit (aka gas) is invalid.
|
||||||
InvalidGasLimit(OutOfBounds<U256>),
|
InvalidGasLimit(OutOfBounds<U256>),
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
//!
|
//!
|
||||||
//! let miner: Miner = Miner::default();
|
//! let miner: Miner = Miner::default();
|
||||||
//! // get status
|
//! // get status
|
||||||
//! assert_eq!(miner.status().transaction_queue_pending, 0);
|
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
||||||
//!
|
//!
|
||||||
//! // Check block for sealing
|
//! // Check block for sealing
|
||||||
//! miner.prepare_sealing(client.deref());
|
//! miner.prepare_sealing(client.deref());
|
||||||
@ -62,11 +62,11 @@ extern crate rayon;
|
|||||||
mod miner;
|
mod miner;
|
||||||
mod transaction_queue;
|
mod transaction_queue;
|
||||||
|
|
||||||
pub use transaction_queue::TransactionQueue;
|
pub use transaction_queue::{TransactionQueue, AccountDetails};
|
||||||
pub use miner::{Miner};
|
pub use miner::{Miner};
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use util::{H256, U256, Address, Bytes};
|
use util::{H256, Address, Bytes};
|
||||||
use ethcore::client::{BlockChainClient};
|
use ethcore::client::{BlockChainClient};
|
||||||
use ethcore::block::{ClosedBlock};
|
use ethcore::block::{ClosedBlock};
|
||||||
use ethcore::error::{Error};
|
use ethcore::error::{Error};
|
||||||
@ -79,8 +79,8 @@ pub trait MinerService : Send + Sync {
|
|||||||
fn status(&self) -> MinerStatus;
|
fn status(&self) -> MinerStatus;
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_nonce: T) -> Result<(), Error>
|
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error>
|
||||||
where T: Fn(&Address) -> U256;
|
where T: Fn(&Address) -> AccountDetails;
|
||||||
|
|
||||||
/// Returns hashes of transactions currently in pending
|
/// Returns hashes of transactions currently in pending
|
||||||
fn pending_transactions_hashes(&self) -> Vec<H256>;
|
fn pending_transactions_hashes(&self) -> Vec<H256>;
|
||||||
@ -105,7 +105,9 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Mining status
|
/// Mining status
|
||||||
pub struct MinerStatus {
|
pub struct MinerStatus {
|
||||||
/// Number of transactions in queue with state `pending` (ready to be included in block)
|
/// Number of transactions in queue with state `pending` (ready to be included in block)
|
||||||
pub transaction_queue_pending: usize,
|
pub transactions_in_pending_queue: usize,
|
||||||
/// Number of transactions in queue with state `future` (not yet ready to be included in block)
|
/// Number of transactions in queue with state `future` (not yet ready to be included in block)
|
||||||
pub transaction_queue_future: usize,
|
pub transactions_in_future_queue: usize,
|
||||||
|
/// Number of transactions included in currently mined block
|
||||||
|
pub transactions_in_pending_block: usize,
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,15 @@ use rayon::prelude::*;
|
|||||||
use std::sync::{Mutex, RwLock, Arc};
|
use std::sync::{Mutex, RwLock, Arc};
|
||||||
use std::sync::atomic;
|
use std::sync::atomic;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use util::{H256, U256, Address, Bytes, Uint};
|
use util::{H256, U256, Address, Bytes, Uint};
|
||||||
use ethcore::views::{BlockView};
|
use ethcore::views::{BlockView};
|
||||||
use ethcore::client::{BlockChainClient, BlockId};
|
use ethcore::client::{BlockChainClient, BlockId};
|
||||||
use ethcore::block::{ClosedBlock};
|
use ethcore::block::{ClosedBlock, IsBlock};
|
||||||
use ethcore::error::{Error};
|
use ethcore::error::{Error};
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
use super::{MinerService, MinerStatus, TransactionQueue};
|
use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails};
|
||||||
|
|
||||||
/// Keeps track of transactions using priority queue and holds currently mined block.
|
/// Keeps track of transactions using priority queue and holds currently mined block.
|
||||||
pub struct Miner {
|
pub struct Miner {
|
||||||
@ -71,7 +72,7 @@ impl Miner {
|
|||||||
|
|
||||||
/// Get the extra_data that we will seal blocks wuth.
|
/// Get the extra_data that we will seal blocks wuth.
|
||||||
fn gas_floor_target(&self) -> U256 {
|
fn gas_floor_target(&self) -> U256 {
|
||||||
self.gas_floor_target.read().unwrap().clone()
|
*self.gas_floor_target.read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the author that we will seal blocks as.
|
/// Set the author that we will seal blocks as.
|
||||||
@ -104,16 +105,18 @@ impl MinerService for Miner {
|
|||||||
|
|
||||||
fn status(&self) -> MinerStatus {
|
fn status(&self) -> MinerStatus {
|
||||||
let status = self.transaction_queue.lock().unwrap().status();
|
let status = self.transaction_queue.lock().unwrap().status();
|
||||||
|
let block = self.sealing_block.lock().unwrap();
|
||||||
MinerStatus {
|
MinerStatus {
|
||||||
transaction_queue_pending: status.pending,
|
transactions_in_pending_queue: status.pending,
|
||||||
transaction_queue_future: status.future,
|
transactions_in_future_queue: status.future,
|
||||||
|
transactions_in_pending_block: block.as_ref().map_or(0, |b| b.transactions().len()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_nonce: T) -> Result<(), Error>
|
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error>
|
||||||
where T: Fn(&Address) -> U256 {
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
transaction_queue.add_all(transactions, fetch_nonce)
|
transaction_queue.add_all(transactions, fetch_account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions_hashes(&self) -> Vec<H256> {
|
fn pending_transactions_hashes(&self) -> Vec<H256> {
|
||||||
@ -174,28 +177,45 @@ impl MinerService for Miner {
|
|||||||
let block = BlockView::new(&block);
|
let block = BlockView::new(&block);
|
||||||
block.transactions()
|
block.transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let in_chain = vec![imported, enacted, invalid];
|
|
||||||
let in_chain = in_chain
|
|
||||||
.par_iter()
|
|
||||||
.flat_map(|h| h.par_iter().map(|h| fetch_transactions(chain, h)));
|
|
||||||
let out_of_chain = retracted
|
let out_of_chain = retracted
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|h| fetch_transactions(chain, h));
|
.map(|h| fetch_transactions(chain, h));
|
||||||
|
|
||||||
in_chain.for_each(|txs| {
|
|
||||||
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
|
||||||
let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
|
|
||||||
transaction_queue.remove_all(&hashes, |a| chain.nonce(a));
|
|
||||||
});
|
|
||||||
out_of_chain.for_each(|txs| {
|
out_of_chain.for_each(|txs| {
|
||||||
// populate sender
|
// populate sender
|
||||||
for tx in &txs {
|
for tx in &txs {
|
||||||
let _sender = tx.sender();
|
let _sender = tx.sender();
|
||||||
}
|
}
|
||||||
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
let _ = transaction_queue.add_all(txs, |a| chain.nonce(a));
|
let _ = transaction_queue.add_all(txs, |a| AccountDetails {
|
||||||
|
nonce: chain.nonce(a),
|
||||||
|
balance: chain.balance(a)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// First import all transactions and after that remove old ones
|
||||||
|
{
|
||||||
|
let in_chain = {
|
||||||
|
let mut in_chain = HashSet::new();
|
||||||
|
in_chain.extend(imported);
|
||||||
|
in_chain.extend(enacted);
|
||||||
|
in_chain.extend(invalid);
|
||||||
|
in_chain
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<H256>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
let in_chain = in_chain
|
||||||
|
.par_iter()
|
||||||
|
.map(|h: &H256| fetch_transactions(chain, h));
|
||||||
|
|
||||||
|
in_chain.for_each(|txs| {
|
||||||
|
let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
|
||||||
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
|
transaction_queue.remove_all(&hashes, |a| AccountDetails {
|
||||||
|
nonce: chain.nonce(a),
|
||||||
|
balance: chain.balance(a)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
//! use util::crypto::KeyPair;
|
//! use util::crypto::KeyPair;
|
||||||
//! use util::hash::Address;
|
//! use util::hash::Address;
|
||||||
//! use util::numbers::{Uint, U256};
|
//! use util::numbers::{Uint, U256};
|
||||||
//! use ethminer::TransactionQueue;
|
//! use ethminer::{TransactionQueue, AccountDetails};
|
||||||
//! use ethcore::transaction::*;
|
//! use ethcore::transaction::*;
|
||||||
//! use rustc_serialize::hex::FromHex;
|
//! use rustc_serialize::hex::FromHex;
|
||||||
//!
|
//!
|
||||||
@ -47,11 +47,14 @@
|
|||||||
//!
|
//!
|
||||||
//! let st1 = t1.sign(&key.secret());
|
//! let st1 = t1.sign(&key.secret());
|
||||||
//! let st2 = t2.sign(&key.secret());
|
//! let st2 = t2.sign(&key.secret());
|
||||||
//! let default_nonce = |_a: &Address| U256::from(10);
|
//! let default_nonce = |_a: &Address| AccountDetails {
|
||||||
|
//! nonce: U256::from(10),
|
||||||
|
//! balance: U256::from(1_000_000),
|
||||||
|
//! };
|
||||||
//!
|
//!
|
||||||
//! let mut txq = TransactionQueue::new();
|
//! let mut txq = TransactionQueue::new();
|
||||||
//! txq.add(st2.clone(), &default_nonce);
|
//! txq.add(st2.clone(), &default_nonce).unwrap();
|
||||||
//! txq.add(st1.clone(), &default_nonce);
|
//! txq.add(st1.clone(), &default_nonce).unwrap();
|
||||||
//!
|
//!
|
||||||
//! // Check status
|
//! // Check status
|
||||||
//! assert_eq!(txq.status().pending, 2);
|
//! assert_eq!(txq.status().pending, 2);
|
||||||
@ -232,8 +235,6 @@ impl TransactionSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will be used when rpc merged
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Current status of the queue
|
/// Current status of the queue
|
||||||
pub struct TransactionQueueStatus {
|
pub struct TransactionQueueStatus {
|
||||||
@ -243,6 +244,14 @@ pub struct TransactionQueueStatus {
|
|||||||
pub future: usize,
|
pub future: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Details of account
|
||||||
|
pub struct AccountDetails {
|
||||||
|
/// Most recent account nonce
|
||||||
|
pub nonce: U256,
|
||||||
|
/// Current account balance
|
||||||
|
pub balance: U256,
|
||||||
|
}
|
||||||
|
|
||||||
/// TransactionQueue implementation
|
/// TransactionQueue implementation
|
||||||
pub struct TransactionQueue {
|
pub struct TransactionQueue {
|
||||||
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
|
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
|
||||||
@ -308,49 +317,66 @@ impl TransactionQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds all signed transactions to queue to be verified and imported
|
/// Adds all signed transactions to queue to be verified and imported
|
||||||
pub fn add_all<T>(&mut self, txs: Vec<SignedTransaction>, fetch_nonce: T) -> Result<(), Error>
|
pub fn add_all<T>(&mut self, txs: Vec<SignedTransaction>, fetch_account: T) -> Result<(), Error>
|
||||||
where T: Fn(&Address) -> U256 {
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
for tx in txs.into_iter() {
|
for tx in txs.into_iter() {
|
||||||
try!(self.add(tx, &fetch_nonce));
|
try!(self.add(tx, &fetch_account));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add signed transaction to queue to be verified and imported
|
/// Add signed transaction to queue to be verified and imported
|
||||||
pub fn add<T>(&mut self, tx: SignedTransaction, fetch_nonce: &T) -> Result<(), Error>
|
pub fn add<T>(&mut self, tx: SignedTransaction, fetch_account: &T) -> Result<(), Error>
|
||||||
where T: Fn(&Address) -> U256 {
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
|
|
||||||
|
trace!(target: "miner", "Importing: {:?}", tx.hash());
|
||||||
|
|
||||||
if tx.gas_price < self.minimal_gas_price {
|
if tx.gas_price < self.minimal_gas_price {
|
||||||
trace!(target: "sync",
|
trace!(target: "miner",
|
||||||
"Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})",
|
"Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})",
|
||||||
tx.hash(), tx.gas_price, self.minimal_gas_price
|
tx.hash(), tx.gas_price, self.minimal_gas_price
|
||||||
);
|
);
|
||||||
|
|
||||||
return Err(Error::Transaction(TransactionError::InsufficientGasPrice{
|
return Err(Error::Transaction(TransactionError::InsufficientGasPrice{
|
||||||
minimal: self.minimal_gas_price,
|
minimal: self.minimal_gas_price,
|
||||||
got: tx.gas_price
|
got: tx.gas_price,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.import_tx(try!(VerifiedTransaction::new(tx)), fetch_nonce);
|
|
||||||
|
let vtx = try!(VerifiedTransaction::new(tx));
|
||||||
|
let account = fetch_account(&vtx.sender());
|
||||||
|
|
||||||
|
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
|
||||||
|
if account.balance < cost {
|
||||||
|
trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})",
|
||||||
|
vtx.hash(), account.balance, cost);
|
||||||
|
return Err(Error::Transaction(TransactionError::InsufficientBalance {
|
||||||
|
cost: cost,
|
||||||
|
balance: account.balance
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.import_tx(vtx, account.nonce);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all transactions identified by hashes given in slice
|
/// Removes all transactions identified by hashes given in slice
|
||||||
///
|
///
|
||||||
/// If gap is introduced marks subsequent transactions as future
|
/// If gap is introduced marks subsequent transactions as future
|
||||||
pub fn remove_all<T>(&mut self, transaction_hashes: &[H256], fetch_nonce: T)
|
pub fn remove_all<T>(&mut self, transaction_hashes: &[H256], fetch_account: T)
|
||||||
where T: Fn(&Address) -> U256 {
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
for hash in transaction_hashes {
|
for hash in transaction_hashes {
|
||||||
self.remove(&hash, &fetch_nonce);
|
self.remove(&hash, &fetch_account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes transaction identified by hashes from queue.
|
/// Removes transaction identified by hashes from queue.
|
||||||
///
|
///
|
||||||
/// If gap is introduced marks subsequent transactions as future
|
/// If gap is introduced marks subsequent transactions as future
|
||||||
pub fn remove<T>(&mut self, transaction_hash: &H256, fetch_nonce: &T)
|
pub fn remove<T>(&mut self, transaction_hash: &H256, fetch_account: &T)
|
||||||
where T: Fn(&Address) -> U256 {
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
|
|
||||||
let transaction = self.by_hash.remove(transaction_hash);
|
let transaction = self.by_hash.remove(transaction_hash);
|
||||||
if transaction.is_none() {
|
if transaction.is_none() {
|
||||||
// We don't know this transaction
|
// We don't know this transaction
|
||||||
@ -360,7 +386,8 @@ impl TransactionQueue {
|
|||||||
let transaction = transaction.unwrap();
|
let transaction = transaction.unwrap();
|
||||||
let sender = transaction.sender();
|
let sender = transaction.sender();
|
||||||
let nonce = transaction.nonce();
|
let nonce = transaction.nonce();
|
||||||
let current_nonce = fetch_nonce(&sender);
|
let current_nonce = fetch_account(&sender).nonce;
|
||||||
|
|
||||||
|
|
||||||
// Remove from future
|
// Remove from future
|
||||||
let order = self.future.drop(&sender, &nonce);
|
let order = self.future.drop(&sender, &nonce);
|
||||||
@ -401,6 +428,7 @@ impl TransactionQueue {
|
|||||||
if k >= current_nonce {
|
if k >= current_nonce {
|
||||||
self.future.insert(*sender, k, order.update_height(k, current_nonce));
|
self.future.insert(*sender, k, order.update_height(k, current_nonce));
|
||||||
} else {
|
} else {
|
||||||
|
trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
|
||||||
// Remove the transaction completely
|
// Remove the transaction completely
|
||||||
self.by_hash.remove(&order.hash);
|
self.by_hash.remove(&order.hash);
|
||||||
}
|
}
|
||||||
@ -421,6 +449,7 @@ impl TransactionQueue {
|
|||||||
if k >= current_nonce {
|
if k >= current_nonce {
|
||||||
self.future.insert(*sender, k, order.update_height(k, current_nonce));
|
self.future.insert(*sender, k, order.update_height(k, current_nonce));
|
||||||
} else {
|
} else {
|
||||||
|
trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
|
||||||
self.by_hash.remove(&order.hash);
|
self.by_hash.remove(&order.hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -486,19 +515,18 @@ impl TransactionQueue {
|
|||||||
///
|
///
|
||||||
/// It ignores transactions that has already been imported (same `hash`) and replaces the transaction
|
/// It ignores transactions that has already been imported (same `hash`) and replaces the transaction
|
||||||
/// iff `(address, nonce)` is the same but `gas_price` is higher.
|
/// iff `(address, nonce)` is the same but `gas_price` is higher.
|
||||||
fn import_tx<T>(&mut self, tx: VerifiedTransaction, fetch_nonce: &T)
|
fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) {
|
||||||
where T: Fn(&Address) -> U256 {
|
|
||||||
|
|
||||||
if self.by_hash.get(&tx.hash()).is_some() {
|
if self.by_hash.get(&tx.hash()).is_some() {
|
||||||
// Transaction is already imported.
|
// Transaction is already imported.
|
||||||
trace!(target: "sync", "Dropping already imported transaction with hash: {:?}", tx.hash());
|
trace!(target: "miner", "Dropping already imported transaction: {:?}", tx.hash());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let address = tx.sender();
|
let address = tx.sender();
|
||||||
let nonce = tx.nonce();
|
let nonce = tx.nonce();
|
||||||
|
|
||||||
let state_nonce = fetch_nonce(&address);
|
|
||||||
let next_nonce = self.last_nonces
|
let next_nonce = self.last_nonces
|
||||||
.get(&address)
|
.get(&address)
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -512,7 +540,7 @@ impl TransactionQueue {
|
|||||||
return;
|
return;
|
||||||
} else if nonce < state_nonce {
|
} else if nonce < state_nonce {
|
||||||
// Droping transaction
|
// Droping transaction
|
||||||
trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce);
|
trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,6 +549,8 @@ impl TransactionQueue {
|
|||||||
// But maybe there are some more items waiting in future?
|
// But maybe there are some more items waiting in future?
|
||||||
self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce);
|
self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce);
|
||||||
self.current.enforce_limit(&mut self.by_hash);
|
self.current.enforce_limit(&mut self.by_hash);
|
||||||
|
|
||||||
|
trace!(target: "miner", "status: {:?}", self.status());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces transaction in given set (could be `future` or `current`).
|
/// Replaces transaction in given set (could be `future` or `current`).
|
||||||
@ -579,8 +609,11 @@ mod test {
|
|||||||
new_unsigned_tx(U256::from(123)).sign(&keypair.secret())
|
new_unsigned_tx(U256::from(123)).sign(&keypair.secret())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_nonce(_address: &Address) -> U256 {
|
fn default_nonce(_address: &Address) -> AccountDetails {
|
||||||
U256::from(123)
|
AccountDetails {
|
||||||
|
nonce: U256::from(123),
|
||||||
|
balance: !U256::zero()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) {
|
fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) {
|
||||||
@ -649,6 +682,25 @@ mod test {
|
|||||||
assert_eq!(stats.pending, 1);
|
assert_eq!(stats.pending, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_drop_transactions_from_senders_without_balance() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::new();
|
||||||
|
let tx = new_tx();
|
||||||
|
let account = |a: &Address| AccountDetails {
|
||||||
|
nonce: default_nonce(a).nonce,
|
||||||
|
balance: U256::one()
|
||||||
|
};
|
||||||
|
|
||||||
|
// when
|
||||||
|
txq.add(tx, &account).unwrap_err();
|
||||||
|
|
||||||
|
// then
|
||||||
|
let stats = txq.status();
|
||||||
|
assert_eq!(stats.pending, 0);
|
||||||
|
assert_eq!(stats.future, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_import_transaction_below_min_gas_price_threshold() {
|
fn should_not_import_transaction_below_min_gas_price_threshold() {
|
||||||
// given
|
// given
|
||||||
@ -749,8 +801,10 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_correctly_update_futures_when_removing() {
|
fn should_correctly_update_futures_when_removing() {
|
||||||
// given
|
// given
|
||||||
let prev_nonce = |a: &Address| default_nonce(a) - U256::one();
|
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance:
|
||||||
let next2_nonce = |a: &Address| default_nonce(a) + U256::from(2);
|
!U256::zero() };
|
||||||
|
let next2_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::from(2), balance:
|
||||||
|
!U256::zero() };
|
||||||
|
|
||||||
let mut txq = TransactionQueue::new();
|
let mut txq = TransactionQueue::new();
|
||||||
|
|
||||||
@ -895,7 +949,7 @@ mod test {
|
|||||||
let mut txq = TransactionQueue::new();
|
let mut txq = TransactionQueue::new();
|
||||||
let tx = new_tx();
|
let tx = new_tx();
|
||||||
let last_nonce = tx.nonce + U256::one();
|
let last_nonce = tx.nonce + U256::one();
|
||||||
let fetch_last_nonce = |_a: &Address| last_nonce;
|
let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() };
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.add(tx, &fetch_last_nonce).unwrap();
|
txq.add(tx, &fetch_last_nonce).unwrap();
|
||||||
@ -909,7 +963,8 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_insert_same_transaction_twice() {
|
fn should_not_insert_same_transaction_twice() {
|
||||||
// given
|
// given
|
||||||
let nonce = |a: &Address| default_nonce(a) + U256::one();
|
let nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce + U256::one(),
|
||||||
|
balance: !U256::zero() };
|
||||||
let mut txq = TransactionQueue::new();
|
let mut txq = TransactionQueue::new();
|
||||||
let (_tx1, tx2) = new_txs(U256::from(1));
|
let (_tx1, tx2) = new_txs(U256::from(1));
|
||||||
txq.add(tx2.clone(), &default_nonce).unwrap();
|
txq.add(tx2.clone(), &default_nonce).unwrap();
|
||||||
@ -949,7 +1004,8 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_move_to_future_if_state_nonce_is_higher() {
|
fn should_not_move_to_future_if_state_nonce_is_higher() {
|
||||||
// given
|
// given
|
||||||
let next_nonce = |a: &Address| default_nonce(a) + U256::one();
|
let next_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce + U256::one(), balance:
|
||||||
|
!U256::zero() };
|
||||||
let mut txq = TransactionQueue::new();
|
let mut txq = TransactionQueue::new();
|
||||||
let (tx, tx2) = new_txs(U256::from(1));
|
let (tx, tx2) = new_txs(U256::from(1));
|
||||||
let tx3 = new_tx();
|
let tx3 = new_tx();
|
||||||
@ -1024,8 +1080,10 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_recalculate_height_when_removing_from_future() {
|
fn should_recalculate_height_when_removing_from_future() {
|
||||||
// given
|
// given
|
||||||
let previous_nonce = |a: &Address| default_nonce(a) - U256::one();
|
let previous_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance:
|
||||||
let next_nonce = |a: &Address| default_nonce(a) + U256::one();
|
!U256::zero() };
|
||||||
|
let next_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::one(), balance:
|
||||||
|
!U256::zero() };
|
||||||
let mut txq = TransactionQueue::new();
|
let mut txq = TransactionQueue::new();
|
||||||
let (tx1, tx2) = new_txs(U256::one());
|
let (tx1, tx2) = new_txs(U256::one());
|
||||||
txq.add(tx1.clone(), &previous_nonce).unwrap();
|
txq.add(tx1.clone(), &previous_nonce).unwrap();
|
||||||
|
@ -19,7 +19,7 @@ use std::collections::HashSet;
|
|||||||
use std::sync::{Arc, Weak, Mutex};
|
use std::sync::{Arc, Weak, Mutex};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use ethsync::{SyncProvider, SyncState};
|
use ethsync::{SyncProvider, SyncState};
|
||||||
use ethminer::{MinerService};
|
use ethminer::{MinerService, AccountDetails};
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::*;
|
||||||
use util::numbers::*;
|
use util::numbers::*;
|
||||||
use util::sha3::*;
|
use util::sha3::*;
|
||||||
@ -236,7 +236,9 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
fn block_transaction_count_by_number(&self, params: Params) -> Result<Value, Error> {
|
fn block_transaction_count_by_number(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(BlockNumber,)>(params)
|
from_params::<(BlockNumber,)>(params)
|
||||||
.and_then(|(block_number,)| match block_number {
|
.and_then(|(block_number,)| match block_number {
|
||||||
BlockNumber::Pending => to_value(&U256::from(take_weak!(self.miner).status().transaction_queue_pending)),
|
BlockNumber::Pending => to_value(
|
||||||
|
&U256::from(take_weak!(self.miner).status().transactions_in_pending_block)
|
||||||
|
),
|
||||||
_ => to_value(&take_weak!(self.client).block(block_number.into())
|
_ => to_value(&take_weak!(self.client).block(block_number.into())
|
||||||
.map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count())))
|
.map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count())))
|
||||||
})
|
})
|
||||||
@ -321,6 +323,15 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
fn work(&self, params: Params) -> Result<Value, Error> {
|
fn work(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => {
|
Params::None => {
|
||||||
|
let client = take_weak!(self.client);
|
||||||
|
// check if we're still syncing and return empty strings int that case
|
||||||
|
{
|
||||||
|
let sync = take_weak!(self.sync);
|
||||||
|
if sync.status().state != SyncState::Idle && client.queue_info().is_empty() {
|
||||||
|
return to_value(&(String::new(), String::new(), String::new()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let miner = take_weak!(self.miner);
|
let miner = take_weak!(self.miner);
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
let u = miner.sealing_block(client.deref()).lock().unwrap();
|
let u = miner.sealing_block(client.deref()).lock().unwrap();
|
||||||
@ -331,7 +342,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
let seed_hash = Ethash::get_seedhash(b.block().header().number());
|
let seed_hash = Ethash::get_seedhash(b.block().header().number());
|
||||||
to_value(&(pow_hash, seed_hash, target))
|
to_value(&(pow_hash, seed_hash, target))
|
||||||
}
|
}
|
||||||
_ => Err(Error::invalid_params())
|
_ => Err(Error::internal_error())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => Err(Error::invalid_params())
|
_ => Err(Error::invalid_params())
|
||||||
@ -370,7 +381,10 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
let signed_transaction = transaction.sign(&secret);
|
let signed_transaction = transaction.sign(&secret);
|
||||||
let hash = signed_transaction.hash();
|
let hash = signed_transaction.hash();
|
||||||
|
|
||||||
let import = miner.import_transactions(vec![signed_transaction], |a: &Address| client.nonce(a));
|
let import = miner.import_transactions(vec![signed_transaction], |a: &Address| AccountDetails {
|
||||||
|
nonce: client.nonce(a),
|
||||||
|
balance: client.balance(a),
|
||||||
|
});
|
||||||
match import {
|
match import {
|
||||||
Ok(_) => to_value(&hash),
|
Ok(_) => to_value(&hash),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -43,12 +43,12 @@ fn sync_provider() -> Arc<TestSyncProvider> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn miner_service() -> Arc<TestMinerService> {
|
fn miner_service() -> Arc<TestMinerService> {
|
||||||
Arc::new(TestMinerService)
|
Arc::new(TestMinerService::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EthTester {
|
struct EthTester {
|
||||||
client: Arc<TestBlockChainClient>,
|
pub client: Arc<TestBlockChainClient>,
|
||||||
_sync: Arc<TestSyncProvider>,
|
pub sync: Arc<TestSyncProvider>,
|
||||||
_accounts_provider: Arc<TestAccountProvider>,
|
_accounts_provider: Arc<TestAccountProvider>,
|
||||||
_miner: Arc<TestMinerService>,
|
_miner: Arc<TestMinerService>,
|
||||||
hashrates: Arc<RwLock<HashMap<H256, U256>>>,
|
hashrates: Arc<RwLock<HashMap<H256, U256>>>,
|
||||||
@ -68,7 +68,7 @@ impl Default for EthTester {
|
|||||||
io.add_delegate(eth);
|
io.add_delegate(eth);
|
||||||
EthTester {
|
EthTester {
|
||||||
client: client,
|
client: client,
|
||||||
_sync: sync,
|
sync: sync,
|
||||||
_accounts_provider: ap,
|
_accounts_provider: ap,
|
||||||
_miner: miner,
|
_miner: miner,
|
||||||
io: io,
|
io: io,
|
||||||
@ -242,6 +242,20 @@ fn rpc_eth_transaction_count_by_number() {
|
|||||||
assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
|
assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_eth_transaction_count_by_number_pending() {
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_getBlockTransactionCountByNumber",
|
||||||
|
"params": ["pending"],
|
||||||
|
"id": 1
|
||||||
|
}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":"0x01","id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_eth_uncle_count_by_block_hash() {
|
fn rpc_eth_uncle_count_by_block_hash() {
|
||||||
let request = r#"{
|
let request = r#"{
|
||||||
@ -346,5 +360,25 @@ fn rpc_eth_compile_serpent() {
|
|||||||
assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
|
assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn returns_no_work_if_cant_mine() {
|
||||||
|
let eth_tester = EthTester::default();
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":["","",""],"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(eth_tester.io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn returns_error_if_can_mine_and_no_closed_block() {
|
||||||
|
use ethsync::{SyncState};
|
||||||
|
|
||||||
|
let eth_tester = EthTester::default();
|
||||||
|
eth_tester.sync.status.write().unwrap().state = SyncState::Idle;
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(eth_tester.io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
@ -14,23 +14,42 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use util::{Address, H256, U256, Bytes};
|
use util::{Address, H256, Bytes};
|
||||||
use util::standard::*;
|
use util::standard::*;
|
||||||
use ethcore::error::Error;
|
use ethcore::error::Error;
|
||||||
use ethcore::client::BlockChainClient;
|
use ethcore::client::BlockChainClient;
|
||||||
use ethcore::block::ClosedBlock;
|
use ethcore::block::ClosedBlock;
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
use ethminer::{MinerService, MinerStatus};
|
use ethminer::{MinerService, MinerStatus, AccountDetails};
|
||||||
|
|
||||||
pub struct TestMinerService;
|
pub struct TestMinerService {
|
||||||
|
pub imported_transactions: RwLock<Vec<H256>>,
|
||||||
|
pub latest_closed_block: Mutex<Option<ClosedBlock>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TestMinerService {
|
||||||
|
fn default() -> TestMinerService {
|
||||||
|
TestMinerService {
|
||||||
|
imported_transactions: RwLock::new(Vec::new()),
|
||||||
|
latest_closed_block: Mutex::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MinerService for TestMinerService {
|
impl MinerService for TestMinerService {
|
||||||
|
|
||||||
/// Returns miner's status.
|
/// Returns miner's status.
|
||||||
fn status(&self) -> MinerStatus { unimplemented!(); }
|
fn status(&self) -> MinerStatus {
|
||||||
|
MinerStatus {
|
||||||
|
transactions_in_pending_queue: 0,
|
||||||
|
transactions_in_future_queue: 0,
|
||||||
|
transactions_in_pending_block: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_transactions<T>(&self, _transactions: Vec<SignedTransaction>, _fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256 { unimplemented!(); }
|
fn import_transactions<T>(&self, _transactions: Vec<SignedTransaction>, _fetch_account: T) -> Result<(), Error>
|
||||||
|
where T: Fn(&Address) -> AccountDetails { unimplemented!(); }
|
||||||
|
|
||||||
/// Returns hashes of transactions currently in pending
|
/// Returns hashes of transactions currently in pending
|
||||||
fn pending_transactions_hashes(&self) -> Vec<H256> { unimplemented!(); }
|
fn pending_transactions_hashes(&self) -> Vec<H256> { unimplemented!(); }
|
||||||
@ -45,7 +64,9 @@ impl MinerService for TestMinerService {
|
|||||||
fn prepare_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); }
|
fn prepare_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); }
|
||||||
|
|
||||||
/// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock.
|
/// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock.
|
||||||
fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex<Option<ClosedBlock>> { unimplemented!(); }
|
fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex<Option<ClosedBlock>> {
|
||||||
|
&self.latest_closed_block
|
||||||
|
}
|
||||||
|
|
||||||
/// Submit `seal` as a valid solution for the header of `pow_hash`.
|
/// 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.
|
/// Will check the seal, but not actually insert the block into the chain.
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethsync::{SyncProvider, SyncStatus, SyncState};
|
use ethsync::{SyncProvider, SyncStatus, SyncState};
|
||||||
|
use std::sync::{RwLock};
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub protocol_version: u8,
|
pub protocol_version: u8,
|
||||||
@ -22,13 +23,13 @@ pub struct Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestSyncProvider {
|
pub struct TestSyncProvider {
|
||||||
status: SyncStatus,
|
pub status: RwLock<SyncStatus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestSyncProvider {
|
impl TestSyncProvider {
|
||||||
pub fn new(config: Config) -> Self {
|
pub fn new(config: Config) -> Self {
|
||||||
TestSyncProvider {
|
TestSyncProvider {
|
||||||
status: SyncStatus {
|
status: RwLock::new(SyncStatus {
|
||||||
state: SyncState::NotSynced,
|
state: SyncState::NotSynced,
|
||||||
protocol_version: config.protocol_version,
|
protocol_version: config.protocol_version,
|
||||||
start_block_number: 0,
|
start_block_number: 0,
|
||||||
@ -39,14 +40,14 @@ impl TestSyncProvider {
|
|||||||
num_peers: config.num_peers,
|
num_peers: config.num_peers,
|
||||||
num_active_peers: 0,
|
num_active_peers: 0,
|
||||||
mem_used: 0,
|
mem_used: 0,
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyncProvider for TestSyncProvider {
|
impl SyncProvider for TestSyncProvider {
|
||||||
fn status(&self) -> SyncStatus {
|
fn status(&self) -> SyncStatus {
|
||||||
self.status.clone()
|
self.status.read().unwrap().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ use range_collection::{RangeCollection, ToUsize, FromUsize};
|
|||||||
use ethcore::error::*;
|
use ethcore::error::*;
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
use ethcore::block::Block;
|
use ethcore::block::Block;
|
||||||
use ethminer::{Miner, MinerService};
|
use ethminer::{Miner, MinerService, AccountDetails};
|
||||||
use io::SyncIo;
|
use io::SyncIo;
|
||||||
use time;
|
use time;
|
||||||
use super::SyncConfig;
|
use super::SyncConfig;
|
||||||
@ -937,6 +937,11 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
/// Called when peer sends us new transactions
|
/// Called when peer sends us new transactions
|
||||||
fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
|
// accepting transactions once only fully synced
|
||||||
|
if !io.is_chain_queue_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let item_count = r.item_count();
|
let item_count = r.item_count();
|
||||||
trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count);
|
trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count);
|
||||||
|
|
||||||
@ -946,8 +951,11 @@ impl ChainSync {
|
|||||||
transactions.push(tx);
|
transactions.push(tx);
|
||||||
}
|
}
|
||||||
let chain = io.chain();
|
let chain = io.chain();
|
||||||
let fetch_nonce = |a: &Address| chain.nonce(a);
|
let fetch_account = |a: &Address| AccountDetails {
|
||||||
let _ = self.miner.import_transactions(transactions, fetch_nonce);
|
nonce: chain.nonce(a),
|
||||||
|
balance: chain.balance(a),
|
||||||
|
};
|
||||||
|
let _ = self.miner.import_transactions(transactions, fetch_account);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,10 +1287,12 @@ impl ChainSync {
|
|||||||
|
|
||||||
/// called when block is imported to chain, updates transactions queue and propagates the blocks
|
/// called when block is imported to chain, updates transactions queue and propagates the blocks
|
||||||
pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
||||||
|
if io.is_chain_queue_empty() {
|
||||||
// Notify miner
|
// Notify miner
|
||||||
self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted);
|
self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted);
|
||||||
// Propagate latests blocks
|
// Propagate latests blocks
|
||||||
self.propagate_latest_blocks(io);
|
self.propagate_latest_blocks(io);
|
||||||
|
}
|
||||||
// TODO [todr] propagate transactions?
|
// TODO [todr] propagate transactions?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1298,6 +1308,7 @@ mod tests {
|
|||||||
use ::SyncConfig;
|
use ::SyncConfig;
|
||||||
use util::*;
|
use util::*;
|
||||||
use super::{PeerInfo, PeerAsking};
|
use super::{PeerInfo, PeerAsking};
|
||||||
|
use ethcore::views::BlockView;
|
||||||
use ethcore::header::*;
|
use ethcore::header::*;
|
||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use ethminer::{Miner, MinerService};
|
use ethminer::{Miner, MinerService};
|
||||||
@ -1628,19 +1639,53 @@ mod tests {
|
|||||||
let good_blocks = vec![client.block_hash_delta_minus(2)];
|
let good_blocks = vec![client.block_hash_delta_minus(2)];
|
||||||
let retracted_blocks = vec![client.block_hash_delta_minus(1)];
|
let retracted_blocks = vec![client.block_hash_delta_minus(1)];
|
||||||
|
|
||||||
|
// Add some balance to clients
|
||||||
|
for h in vec![good_blocks[0], retracted_blocks[0]] {
|
||||||
|
let block = client.block(BlockId::Hash(h)).unwrap();
|
||||||
|
let view = BlockView::new(&block);
|
||||||
|
client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
let mut io = TestIo::new(&mut client, &mut queue, None);
|
let mut io = TestIo::new(&mut client, &mut queue, None);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks);
|
sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks);
|
||||||
assert_eq!(sync.miner.status().transaction_queue_future, 0);
|
assert_eq!(sync.miner.status().transactions_in_future_queue, 0);
|
||||||
assert_eq!(sync.miner.status().transaction_queue_pending, 1);
|
assert_eq!(sync.miner.status().transactions_in_pending_queue, 1);
|
||||||
sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks);
|
sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let status = sync.miner.status();
|
let status = sync.miner.status();
|
||||||
assert_eq!(status.transaction_queue_pending, 1);
|
assert_eq!(status.transactions_in_pending_queue, 1);
|
||||||
assert_eq!(status.transaction_queue_future, 0);
|
assert_eq!(status.transactions_in_future_queue, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_not_add_transactions_to_queue_if_not_synced() {
|
||||||
|
// given
|
||||||
|
let mut client = TestBlockChainClient::new();
|
||||||
|
client.add_blocks(98, EachBlockWith::Uncle);
|
||||||
|
client.add_blocks(1, EachBlockWith::UncleAndTransaction);
|
||||||
|
client.add_blocks(1, EachBlockWith::Transaction);
|
||||||
|
let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5));
|
||||||
|
|
||||||
|
let good_blocks = vec![client.block_hash_delta_minus(2)];
|
||||||
|
let retracted_blocks = vec![client.block_hash_delta_minus(1)];
|
||||||
|
|
||||||
|
let mut queue = VecDeque::new();
|
||||||
|
let mut io = TestIo::new(&mut client, &mut queue, None);
|
||||||
|
|
||||||
|
// when
|
||||||
|
sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks);
|
||||||
|
assert_eq!(sync.miner.status().transactions_in_future_queue, 0);
|
||||||
|
assert_eq!(sync.miner.status().transactions_in_pending_queue, 0);
|
||||||
|
sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks);
|
||||||
|
|
||||||
|
// then
|
||||||
|
let status = sync.miner.status();
|
||||||
|
assert_eq!(status.transactions_in_pending_queue, 0);
|
||||||
|
assert_eq!(status.transactions_in_future_queue, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -37,6 +37,10 @@ pub trait SyncIo {
|
|||||||
fn peer_info(&self, peer_id: PeerId) -> String {
|
fn peer_info(&self, peer_id: PeerId) -> String {
|
||||||
peer_id.to_string()
|
peer_id.to_string()
|
||||||
}
|
}
|
||||||
|
/// Returns if the chain block queue empty
|
||||||
|
fn is_chain_queue_empty(&self) -> bool {
|
||||||
|
self.chain().queue_info().is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps `NetworkContext` and the blockchain client
|
/// Wraps `NetworkContext` and the blockchain client
|
||||||
|
@ -173,7 +173,7 @@ impl NetworkProtocolHandler<SyncMessage> for EthSync {
|
|||||||
SyncMessage::NewChainHead => {
|
SyncMessage::NewChainHead => {
|
||||||
let mut sync_io = NetSyncIo::new(io, self.chain.deref());
|
let mut sync_io = NetSyncIo::new(io, self.chain.deref());
|
||||||
self.sync.write().unwrap().chain_new_head(&mut sync_io);
|
self.sync.write().unwrap().chain_new_head(&mut sync_io);
|
||||||
}
|
},
|
||||||
_ => {/* Ignore other messages */},
|
_ => {/* Ignore other messages */},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user