Merge branch 'master' into ipc-nested-interfaces
This commit is contained in:
commit
d5b6f42965
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -375,7 +375,7 @@ dependencies = [
|
|||||||
"jsonrpc-core 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper)",
|
"jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-status 0.1.6 (git+https://github.com/tomusdrw/parity-status.git)",
|
"parity-status 0.1.7 (git+https://github.com/tomusdrw/parity-status.git)",
|
||||||
"parity-wallet 0.1.1 (git+https://github.com/tomusdrw/parity-wallet.git)",
|
"parity-wallet 0.1.1 (git+https://github.com/tomusdrw/parity-wallet.git)",
|
||||||
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
||||||
]
|
]
|
||||||
@ -591,7 +591,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-http-server"
|
name = "jsonrpc-http-server"
|
||||||
version = "5.0.1"
|
version = "5.0.1"
|
||||||
source = "git+https://github.com/debris/jsonrpc-http-server.git#239066b94660a1af24c8b2efc16e800f9c7cce18"
|
source = "git+https://github.com/debris/jsonrpc-http-server.git#e728f2e080799b7a62b0b5cf5fa9d4ad65cd8c96"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper 0.9.0-mio (git+https://github.com/hyperium/hyper?branch=mio)",
|
"hyper 0.9.0-mio (git+https://github.com/hyperium/hyper?branch=mio)",
|
||||||
"jsonrpc-core 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -715,7 +715,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nanomsg"
|
name = "nanomsg"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/ethcore/nanomsg.rs.git#26449b15f29b850bcf62a577f1ee3a56474a0bc9"
|
source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
@ -724,7 +724,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nanomsg-sys"
|
name = "nanomsg-sys"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/ethcore/nanomsg.rs.git#26449b15f29b850bcf62a577f1ee3a56474a0bc9"
|
source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -796,8 +796,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-status"
|
name = "parity-status"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "git+https://github.com/tomusdrw/parity-status.git#bbd45f5ccc6a0ccc9ed2c8b666b012844f9b89a8"
|
source = "git+https://github.com/tomusdrw/parity-status.git#5b7010eb7ecc38e80ab506902e083dc0dd48c43f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
||||||
]
|
]
|
||||||
|
@ -12,11 +12,9 @@ RUN apt-get -y update && \
|
|||||||
# install multirust
|
# install multirust
|
||||||
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
|
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
|
||||||
ENV RUST_TARGETS="arm-unknown-linux-gnueabihf"
|
ENV RUST_TARGETS="arm-unknown-linux-gnueabihf"
|
||||||
# multirust override beta
|
|
||||||
RUN multirust override beta
|
|
||||||
|
|
||||||
# multirust add arm--linux-gnuabhf toolchain
|
# multirust add arm--linux-gnuabhf toolchain
|
||||||
RUN multirust add-target beta arm-unknown-linux-gnueabihf
|
RUN multirust add-target stable arm-unknown-linux-gnueabihf
|
||||||
|
|
||||||
# show backtraces
|
# show backtraces
|
||||||
ENV RUST_BACKTRACE 1
|
ENV RUST_BACKTRACE 1
|
||||||
@ -41,7 +39,6 @@ RUN git clone https://github.com/ethcore/parity && \
|
|||||||
cat .cargo/config && \
|
cat .cargo/config && \
|
||||||
rustc -vV && \
|
rustc -vV && \
|
||||||
cargo -V && \
|
cargo -V && \
|
||||||
cargo update && \
|
|
||||||
cargo build --target arm-unknown-linux-gnueabihf --release --verbose && \
|
cargo build --target arm-unknown-linux-gnueabihf --release --verbose && \
|
||||||
ls /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
|
ls /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
|
||||||
file /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
|
file /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
|
||||||
|
@ -48,6 +48,8 @@ pub struct TestBlockChainClient {
|
|||||||
pub difficulty: RwLock<U256>,
|
pub difficulty: RwLock<U256>,
|
||||||
/// Balances.
|
/// Balances.
|
||||||
pub balances: RwLock<HashMap<Address, U256>>,
|
pub balances: RwLock<HashMap<Address, U256>>,
|
||||||
|
/// Nonces.
|
||||||
|
pub nonces: RwLock<HashMap<Address, U256>>,
|
||||||
/// Storage.
|
/// Storage.
|
||||||
pub storage: RwLock<HashMap<(Address, H256), H256>>,
|
pub storage: RwLock<HashMap<(Address, H256), H256>>,
|
||||||
/// Code.
|
/// Code.
|
||||||
@ -90,6 +92,7 @@ impl TestBlockChainClient {
|
|||||||
last_hash: RwLock::new(H256::new()),
|
last_hash: RwLock::new(H256::new()),
|
||||||
difficulty: RwLock::new(From::from(0)),
|
difficulty: RwLock::new(From::from(0)),
|
||||||
balances: RwLock::new(HashMap::new()),
|
balances: RwLock::new(HashMap::new()),
|
||||||
|
nonces: RwLock::new(HashMap::new()),
|
||||||
storage: RwLock::new(HashMap::new()),
|
storage: RwLock::new(HashMap::new()),
|
||||||
code: RwLock::new(HashMap::new()),
|
code: RwLock::new(HashMap::new()),
|
||||||
execution_result: RwLock::new(None),
|
execution_result: RwLock::new(None),
|
||||||
@ -116,6 +119,11 @@ impl TestBlockChainClient {
|
|||||||
self.balances.write().unwrap().insert(address, balance);
|
self.balances.write().unwrap().insert(address, balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set nonce of account `address` to `nonce`.
|
||||||
|
pub fn set_nonce(&self, address: Address, nonce: U256) {
|
||||||
|
self.nonces.write().unwrap().insert(address, nonce);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set `code` at `address`.
|
/// Set `code` at `address`.
|
||||||
pub fn set_code(&self, address: Address, code: Bytes) {
|
pub fn set_code(&self, address: Address, code: Bytes) {
|
||||||
self.code.write().unwrap().insert(address, code);
|
self.code.write().unwrap().insert(address, code);
|
||||||
@ -157,6 +165,8 @@ impl TestBlockChainClient {
|
|||||||
EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => {
|
EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => {
|
||||||
let mut txs = RlpStream::new_list(1);
|
let mut txs = RlpStream::new_list(1);
|
||||||
let keypair = KeyPair::create().unwrap();
|
let keypair = KeyPair::create().unwrap();
|
||||||
|
// Update nonces value
|
||||||
|
self.nonces.write().unwrap().insert(keypair.address(), U256::one());
|
||||||
let tx = Transaction {
|
let tx = Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
@ -222,8 +232,8 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nonce(&self, _address: &Address) -> U256 {
|
fn nonce(&self, address: &Address) -> U256 {
|
||||||
U256::zero()
|
self.nonces.read().unwrap().get(address).cloned().unwrap_or_else(U256::zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn code(&self, address: &Address) -> Option<Bytes> {
|
fn code(&self, address: &Address) -> Option<Bytes> {
|
||||||
|
@ -132,8 +132,11 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Returns highest transaction nonce for given address.
|
/// Returns highest transaction nonce for given address.
|
||||||
fn last_nonce(&self, address: &Address) -> Option<U256>;
|
fn last_nonce(&self, address: &Address) -> Option<U256>;
|
||||||
|
|
||||||
/// Suggested gas price
|
/// Suggested gas price.
|
||||||
fn sensible_gas_price(&self) -> U256 { x!(20000000000u64) }
|
fn sensible_gas_price(&self) -> U256 { x!(20000000000u64) }
|
||||||
|
|
||||||
|
/// Suggested gas limit.
|
||||||
|
fn sensible_gas_limit(&self) -> U256 { x!(21000) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mining status
|
/// Mining status
|
||||||
|
@ -133,13 +133,13 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut queue = self.transaction_queue.lock().unwrap();
|
let mut queue = self.transaction_queue.lock().unwrap();
|
||||||
queue.remove_all(
|
let fetch_account = |a: &Address| AccountDetails {
|
||||||
&invalid_transactions.into_iter().collect::<Vec<H256>>(),
|
nonce: chain.nonce(a),
|
||||||
|a: &Address| AccountDetails {
|
balance: chain.balance(a),
|
||||||
nonce: chain.nonce(a),
|
};
|
||||||
balance: chain.balance(a),
|
for hash in invalid_transactions.into_iter() {
|
||||||
}
|
queue.remove_invalid(&hash, &fetch_account);
|
||||||
);
|
}
|
||||||
if let Some(block) = b {
|
if let Some(block) = b {
|
||||||
if sealing_work.peek_last_ref().map_or(true, |pb| pb.block().fields().header.hash() != block.block().fields().header.hash()) {
|
if sealing_work.peek_last_ref().map_or(true, |pb| pb.block().fields().header.hash() != block.block().fields().header.hash()) {
|
||||||
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
|
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
|
||||||
@ -201,6 +201,10 @@ impl MinerService for Miner {
|
|||||||
*self.transaction_queue.lock().unwrap().minimal_gas_price() * x!(110) / x!(100)
|
*self.transaction_queue.lock().unwrap().minimal_gas_price() * x!(110) / x!(100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sensible_gas_limit(&self) -> U256 {
|
||||||
|
*self.gas_floor_target.read().unwrap() / x!(5)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the author that we will seal blocks as.
|
/// Get the author that we will seal blocks as.
|
||||||
fn author(&self) -> Address {
|
fn author(&self) -> Address {
|
||||||
*self.author.read().unwrap()
|
*self.author.read().unwrap()
|
||||||
@ -295,7 +299,7 @@ impl MinerService for Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
fn chain_new_blocks(&self, chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
||||||
fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec<SignedTransaction> {
|
fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec<SignedTransaction> {
|
||||||
let block = chain
|
let block = chain
|
||||||
.block(BlockId::Hash(*hash))
|
.block(BlockId::Hash(*hash))
|
||||||
@ -305,6 +309,11 @@ impl MinerService for Miner {
|
|||||||
block.transactions()
|
block.transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
|
||||||
|
// should be still available in the queue.
|
||||||
|
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
|
||||||
|
// are in those blocks
|
||||||
|
|
||||||
// First update gas limit in transaction queue
|
// First update gas limit in transaction queue
|
||||||
self.update_gas_limit(chain);
|
self.update_gas_limit(chain);
|
||||||
|
|
||||||
@ -326,29 +335,23 @@ impl MinerService for Miner {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...and after that remove old ones
|
// ...and at the end remove old ones
|
||||||
{
|
{
|
||||||
let in_chain = {
|
let in_chain = enacted
|
||||||
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()
|
.par_iter()
|
||||||
.map(|h: &H256| fetch_transactions(chain, h));
|
.map(|h: &H256| fetch_transactions(chain, h));
|
||||||
|
|
||||||
in_chain.for_each(|txs| {
|
in_chain.for_each(|mut txs| {
|
||||||
let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
|
|
||||||
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
transaction_queue.remove_all(&hashes, |a| AccountDetails {
|
|
||||||
nonce: chain.nonce(a),
|
let to_remove = txs.drain(..)
|
||||||
balance: chain.balance(a)
|
.map(|tx| {
|
||||||
});
|
tx.sender().expect("Transaction is in block, so sender has to be defined.")
|
||||||
|
})
|
||||||
|
.collect::<HashSet<Address>>();
|
||||||
|
for sender in to_remove.into_iter() {
|
||||||
|
transaction_queue.remove_all(sender, chain.nonce(&sender));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +65,8 @@
|
|||||||
//! assert_eq!(top[1], st2);
|
//! assert_eq!(top[1], st2);
|
||||||
//!
|
//!
|
||||||
//! // And when transaction is removed (but nonce haven't changed)
|
//! // And when transaction is removed (but nonce haven't changed)
|
||||||
//! // it will move invalid transactions to future
|
//! // it will move subsequent transactions to future
|
||||||
//! txq.remove(&st1.hash(), &default_nonce);
|
//! txq.remove_invalid(&st1.hash(), &default_nonce);
|
||||||
//! assert_eq!(txq.status().pending, 0);
|
//! assert_eq!(txq.status().pending, 0);
|
||||||
//! assert_eq!(txq.status().future, 1);
|
//! assert_eq!(txq.status().future, 1);
|
||||||
//! assert_eq!(txq.top_transactions().len(), 0);
|
//! assert_eq!(txq.top_transactions().len(), 0);
|
||||||
@ -76,11 +76,13 @@
|
|||||||
//! # Maintaing valid state
|
//! # Maintaing valid state
|
||||||
//!
|
//!
|
||||||
//! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling).
|
//! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling).
|
||||||
//! 2. Whenever transaction is removed:
|
//! 2. Whenever invalid transaction is removed:
|
||||||
//! - When it's removed from `future` - all `future` transactions heights are recalculated and then
|
//! - When it's removed from `future` - all `future` transactions heights are recalculated and then
|
||||||
//! we check if the transactions should go to `current` (comparing state nonce)
|
//! we check if the transactions should go to `current` (comparing state nonce)
|
||||||
//! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated.
|
//! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated.
|
||||||
//!
|
//! 3. `remove_all` is used to inform the queue about client (state) nonce changes.
|
||||||
|
//! - It removes all transactions (either from `current` or `future`) with nonce < client nonce
|
||||||
|
//! - It moves matching `future` transactions to `current`
|
||||||
|
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::cmp::{Ordering};
|
use std::cmp::{Ordering};
|
||||||
@ -398,22 +400,28 @@ impl TransactionQueue {
|
|||||||
self.import_tx(vtx, client_account.nonce).map_err(Error::Transaction)
|
self.import_tx(vtx, client_account.nonce).map_err(Error::Transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all transactions identified by hashes given in slice
|
/// Removes all transactions from particular sender up to (excluding) given client (state) nonce.
|
||||||
///
|
/// Client (State) Nonce = next valid nonce for this sender.
|
||||||
/// If gap is introduced marks subsequent transactions as future
|
pub fn remove_all(&mut self, sender: Address, client_nonce: U256) {
|
||||||
pub fn remove_all<T>(&mut self, transaction_hashes: &[H256], fetch_account: T)
|
// We will either move transaction to future or remove it completely
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
// so there will be no transactions from this sender in current
|
||||||
for hash in transaction_hashes {
|
self.last_nonces.remove(&sender);
|
||||||
self.remove(&hash, &fetch_account);
|
// First update height of transactions in future to avoid collisions
|
||||||
}
|
self.update_future(&sender, client_nonce);
|
||||||
|
// This should move all current transactions to future and remove old transactions
|
||||||
|
self.move_all_to_future(&sender, client_nonce);
|
||||||
|
// And now lets check if there is some batch of transactions in future
|
||||||
|
// that should be placed in current. It should also update last_nonces.
|
||||||
|
self.move_matching_future_to_current(sender, client_nonce, client_nonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes transaction identified by hashes from queue.
|
/// Removes invalid transaction identified by hash from queue.
|
||||||
|
/// Assumption is that this transaction nonce is not related to client nonce,
|
||||||
|
/// so transactions left in queue are processed according to client nonce.
|
||||||
///
|
///
|
||||||
/// 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_account: &T)
|
pub fn remove_invalid<T>(&mut self, transaction_hash: &H256, fetch_account: &T)
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
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
|
||||||
@ -425,7 +433,6 @@ impl TransactionQueue {
|
|||||||
let nonce = transaction.nonce();
|
let nonce = transaction.nonce();
|
||||||
let current_nonce = fetch_account(&sender).nonce;
|
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);
|
||||||
if order.is_some() {
|
if order.is_some() {
|
||||||
@ -465,7 +472,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);
|
trace!(target: "miner", "Removing 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);
|
||||||
}
|
}
|
||||||
@ -486,7 +493,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);
|
trace!(target: "miner", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
|
||||||
self.by_hash.remove(&order.hash);
|
self.by_hash.remove(&order.hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -665,9 +672,14 @@ mod test {
|
|||||||
new_unsigned_tx(U256::from(123)).sign(&keypair.secret())
|
new_unsigned_tx(U256::from(123)).sign(&keypair.secret())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn default_nonce_val() -> U256 {
|
||||||
|
U256::from(123)
|
||||||
|
}
|
||||||
|
|
||||||
fn default_nonce(_address: &Address) -> AccountDetails {
|
fn default_nonce(_address: &Address) -> AccountDetails {
|
||||||
AccountDetails {
|
AccountDetails {
|
||||||
nonce: U256::from(123),
|
nonce: default_nonce_val(),
|
||||||
balance: !U256::zero()
|
balance: !U256::zero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -965,8 +977,7 @@ mod test {
|
|||||||
// given
|
// given
|
||||||
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance:
|
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance:
|
||||||
!U256::zero() };
|
!U256::zero() };
|
||||||
let next2_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::from(2), balance:
|
let next2_nonce = default_nonce_val() + U256::from(3);
|
||||||
!U256::zero() };
|
|
||||||
|
|
||||||
let mut txq = TransactionQueue::new();
|
let mut txq = TransactionQueue::new();
|
||||||
|
|
||||||
@ -976,7 +987,7 @@ mod test {
|
|||||||
assert_eq!(txq.status().future, 2);
|
assert_eq!(txq.status().future, 2);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.remove(&tx.hash(), &next2_nonce);
|
txq.remove_all(tx.sender().unwrap(), next2_nonce);
|
||||||
// should remove both transactions since they are not valid
|
// should remove both transactions since they are not valid
|
||||||
|
|
||||||
// then
|
// then
|
||||||
@ -1019,8 +1030,8 @@ mod test {
|
|||||||
assert_eq!(txq2.status().future, 1);
|
assert_eq!(txq2.status().future, 1);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq2.remove(&tx.hash(), &default_nonce);
|
txq2.remove_all(tx.sender().unwrap(), tx.nonce + U256::one());
|
||||||
txq2.remove(&tx2.hash(), &default_nonce);
|
txq2.remove_all(tx2.sender().unwrap(), tx2.nonce + U256::one());
|
||||||
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
@ -1042,7 +1053,7 @@ mod test {
|
|||||||
assert_eq!(txq.status().pending, 3);
|
assert_eq!(txq.status().pending, 3);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.remove(&tx.hash(), &default_nonce);
|
txq.remove_invalid(&tx.hash(), &default_nonce);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
@ -1152,7 +1163,7 @@ mod test {
|
|||||||
assert_eq!(txq.status().pending, 2);
|
assert_eq!(txq.status().pending, 2);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.remove(&tx1.hash(), &default_nonce);
|
txq.remove_invalid(&tx1.hash(), &default_nonce);
|
||||||
assert_eq!(txq.status().pending, 0);
|
assert_eq!(txq.status().pending, 0);
|
||||||
assert_eq!(txq.status().future, 1);
|
assert_eq!(txq.status().future, 1);
|
||||||
txq.add(tx1.clone(), &default_nonce).unwrap();
|
txq.add(tx1.clone(), &default_nonce).unwrap();
|
||||||
@ -1166,8 +1177,6 @@ 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| 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();
|
||||||
@ -1178,7 +1187,8 @@ mod test {
|
|||||||
assert_eq!(txq.status().pending, 3);
|
assert_eq!(txq.status().pending, 3);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.remove(&tx.hash(), &next_nonce);
|
let sender = tx.sender().unwrap();
|
||||||
|
txq.remove_all(sender, default_nonce_val() + U256::one());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
@ -1254,7 +1264,7 @@ mod test {
|
|||||||
assert_eq!(txq.status().future, 2);
|
assert_eq!(txq.status().future, 2);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.remove(&tx1.hash(), &next_nonce);
|
txq.remove_invalid(&tx1.hash(), &next_nonce);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let stats = txq.status();
|
let stats = txq.status();
|
||||||
@ -1286,4 +1296,22 @@ mod test {
|
|||||||
// then
|
// then
|
||||||
assert_eq!(txq.last_nonce(&from), Some(nonce));
|
assert_eq!(txq.last_nonce(&from), Some(nonce));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_remove_old_transaction_even_if_newer_transaction_was_not_known() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::new();
|
||||||
|
let (tx1, tx2) = new_txs(U256::one());
|
||||||
|
let (nonce1, nonce2) = (tx1.nonce, tx2.nonce);
|
||||||
|
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
|
||||||
|
|
||||||
|
// Insert first transaction
|
||||||
|
txq.add(tx1, &details1).unwrap();
|
||||||
|
|
||||||
|
// when
|
||||||
|
txq.remove_all(tx2.sender().unwrap(), nonce2 + U256::one());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert!(txq.top_transactions().is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,20 +88,18 @@ impl Hypervisor {
|
|||||||
/// Does nothing when it is already started on module is inside the
|
/// Does nothing when it is already started on module is inside the
|
||||||
/// main binary
|
/// main binary
|
||||||
fn start_module(&self, module_id: IpcModuleId) {
|
fn start_module(&self, module_id: IpcModuleId) {
|
||||||
Self::match_module(&module_id).map(|binary_id|
|
Self::match_module(&module_id).map(|binary_id| {
|
||||||
{
|
let mut processes = self.processes.write().unwrap();
|
||||||
let mut processes = self.processes.write().unwrap();
|
{
|
||||||
{
|
if processes.get(binary_id).is_some() {
|
||||||
let process = processes.get(binary_id);
|
// already started for another module
|
||||||
if process.is_some() {
|
return;
|
||||||
// already started for another module
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let child = Command::new(binary_id).spawn().unwrap_or_else(
|
}
|
||||||
|e| panic!("Hypervisor cannot start binary: {}", e));
|
let child = Command::new(binary_id).spawn().unwrap_or_else(
|
||||||
processes.insert(binary_id, child);
|
|e| panic!("Hypervisor cannot start binary: {}", e));
|
||||||
});
|
processes.insert(binary_id, child);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports if all modules are checked in
|
/// Reports if all modules are checked in
|
||||||
|
@ -138,8 +138,7 @@ API and Console Options:
|
|||||||
--jsonrpc-interface IP Specify the hostname portion of the JSONRPC API
|
--jsonrpc-interface IP Specify the hostname portion of the JSONRPC API
|
||||||
server, IP should be an interface's IP address, or
|
server, IP should be an interface's IP address, or
|
||||||
all (all interfaces) or local [default: local].
|
all (all interfaces) or local [default: local].
|
||||||
--jsonrpc-cors URL Specify CORS header for JSON-RPC API responses
|
--jsonrpc-cors URL Specify CORS header for JSON-RPC API responses.
|
||||||
[default: null].
|
|
||||||
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC
|
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC
|
||||||
interface. APIS is a comma-delimited list of API
|
interface. APIS is a comma-delimited list of API
|
||||||
name. Possible name are web3, eth and net.
|
name. Possible name are web3, eth and net.
|
||||||
@ -247,7 +246,7 @@ struct Args {
|
|||||||
flag_jsonrpc: bool,
|
flag_jsonrpc: bool,
|
||||||
flag_jsonrpc_interface: String,
|
flag_jsonrpc_interface: String,
|
||||||
flag_jsonrpc_port: u16,
|
flag_jsonrpc_port: u16,
|
||||||
flag_jsonrpc_cors: String,
|
flag_jsonrpc_cors: Option<String>,
|
||||||
flag_jsonrpc_apis: String,
|
flag_jsonrpc_apis: String,
|
||||||
flag_webapp: bool,
|
flag_webapp: bool,
|
||||||
flag_webapp_port: u16,
|
flag_webapp_port: u16,
|
||||||
@ -312,7 +311,7 @@ fn setup_rpc_server(
|
|||||||
secret_store: Arc<AccountService>,
|
secret_store: Arc<AccountService>,
|
||||||
miner: Arc<Miner>,
|
miner: Arc<Miner>,
|
||||||
url: &SocketAddr,
|
url: &SocketAddr,
|
||||||
cors_domain: &str,
|
cors_domain: Option<String>,
|
||||||
apis: Vec<&str>,
|
apis: Vec<&str>,
|
||||||
) -> RpcServer {
|
) -> RpcServer {
|
||||||
use rpc::v1::*;
|
use rpc::v1::*;
|
||||||
@ -385,7 +384,7 @@ fn setup_rpc_server(
|
|||||||
_secret_store: Arc<AccountService>,
|
_secret_store: Arc<AccountService>,
|
||||||
_miner: Arc<Miner>,
|
_miner: Arc<Miner>,
|
||||||
_url: &str,
|
_url: &str,
|
||||||
_cors_domain: &str,
|
_cors_domain: Option<String>,
|
||||||
_apis: Vec<&str>,
|
_apis: Vec<&str>,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
die!("Your Parity version has been compiled without JSON-RPC support.")
|
die!("Your Parity version has been compiled without JSON-RPC support.")
|
||||||
@ -627,9 +626,9 @@ impl Configuration {
|
|||||||
let mut secret_store = SecretStore::new_in(Path::new(&self.keys_path()));
|
let mut secret_store = SecretStore::new_in(Path::new(&self.keys_path()));
|
||||||
if self.args.cmd_new {
|
if self.args.cmd_new {
|
||||||
println!("Please note that password is NOT RECOVERABLE.");
|
println!("Please note that password is NOT RECOVERABLE.");
|
||||||
println!("Type password: ");
|
print!("Type password: ");
|
||||||
let password = read_password().unwrap();
|
let password = read_password().unwrap();
|
||||||
println!("Repeat password: ");
|
print!("Repeat password: ");
|
||||||
let password_repeat = read_password().unwrap();
|
let password_repeat = read_password().unwrap();
|
||||||
if password != password_repeat {
|
if password != password_repeat {
|
||||||
println!("Passwords do not match!");
|
println!("Passwords do not match!");
|
||||||
@ -718,7 +717,7 @@ impl Configuration {
|
|||||||
self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port)
|
self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port)
|
||||||
);
|
);
|
||||||
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url));
|
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url));
|
||||||
let cors_domain = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors);
|
let cors_domain = self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone());
|
||||||
|
|
||||||
Some(setup_rpc_server(
|
Some(setup_rpc_server(
|
||||||
service.client(),
|
service.client(),
|
||||||
@ -726,7 +725,7 @@ impl Configuration {
|
|||||||
account_service.clone(),
|
account_service.clone(),
|
||||||
miner.clone(),
|
miner.clone(),
|
||||||
&addr,
|
&addr,
|
||||||
&cors_domain,
|
cors_domain,
|
||||||
apis.split(',').collect()
|
apis.split(',').collect()
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,8 +58,8 @@ impl RpcServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start server asynchronously and returns result with `Server` handle on success or an error.
|
/// Start server asynchronously and returns result with `Server` handle on success or an error.
|
||||||
pub fn start_http(&self, addr: &SocketAddr, cors_domain: &str) -> Result<Server, RpcServerError> {
|
pub fn start_http(&self, addr: &SocketAddr, cors_domain: Option<String>) -> Result<Server, RpcServerError> {
|
||||||
let cors_domain = cors_domain.to_owned();
|
let cors_domain = cors_domain.to_owned();
|
||||||
Server::start(addr, self.handler.clone(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain))
|
Server::start(addr, self.handler.clone(), cors_domain.map(jsonrpc_http_server::AccessControlAllowOrigin::Value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,14 +40,6 @@ use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
|
|||||||
use util::keys::store::AccountProvider;
|
use util::keys::store::AccountProvider;
|
||||||
use serde;
|
use serde;
|
||||||
|
|
||||||
fn default_gas() -> U256 {
|
|
||||||
U256::from(21_000)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_call_gas() -> U256 {
|
|
||||||
U256::from(50_000_000)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Eth rpc implementation.
|
/// Eth rpc implementation.
|
||||||
pub struct EthClient<C, S, A, M, EM = ExternalMiner>
|
pub struct EthClient<C, S, A, M, EM = ExternalMiner>
|
||||||
where C: BlockChainClient,
|
where C: BlockChainClient,
|
||||||
@ -180,7 +172,7 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
|||||||
Ok(EthTransaction {
|
Ok(EthTransaction {
|
||||||
nonce: request.nonce.unwrap_or_else(|| client.nonce(&from)),
|
nonce: request.nonce.unwrap_or_else(|| client.nonce(&from)),
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
gas: request.gas.unwrap_or_else(default_call_gas),
|
gas: request.gas.unwrap_or(U256::from(50_000_000)),
|
||||||
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
||||||
value: request.value.unwrap_or_else(U256::zero),
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
||||||
@ -498,7 +490,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
.map(|nonce| nonce + U256::one()))
|
.map(|nonce| nonce + U256::one()))
|
||||||
.unwrap_or_else(|| client.nonce(&request.from)),
|
.unwrap_or_else(|| client.nonce(&request.from)),
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
gas: request.gas.unwrap_or_else(default_gas),
|
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
||||||
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
||||||
value: request.value.unwrap_or_else(U256::zero),
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
data: request.data.map_or_else(Vec::new, |d| d.to_vec()),
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec()),
|
||||||
@ -524,6 +516,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, params: Params) -> Result<Value, Error> {
|
fn call(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
trace!(target: "jsonrpc", "call: {:?}", params);
|
||||||
from_params_discard_second(params).and_then(|(request, )| {
|
from_params_discard_second(params).and_then(|(request, )| {
|
||||||
let signed = try!(self.sign_call(request));
|
let signed = try!(self.sign_call(request));
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
|
@ -1694,21 +1694,34 @@ 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
|
// Add some balance to clients and reset nonces
|
||||||
for h in &[good_blocks[0], retracted_blocks[0]] {
|
for h in &[good_blocks[0], retracted_blocks[0]] {
|
||||||
let block = client.block(BlockId::Hash(*h)).unwrap();
|
let block = client.block(BlockId::Hash(*h)).unwrap();
|
||||||
let view = BlockView::new(&block);
|
let view = BlockView::new(&block);
|
||||||
client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000));
|
client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000));
|
||||||
|
client.set_nonce(view.transactions()[0].sender().unwrap(), U256::from(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
let mut io = TestIo::new(&mut client, &mut queue, None);
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks);
|
{
|
||||||
assert_eq!(sync.miner.status().transactions_in_future_queue, 0);
|
let mut queue = VecDeque::new();
|
||||||
assert_eq!(sync.miner.status().transactions_in_pending_queue, 1);
|
let mut io = TestIo::new(&mut client, &mut queue, None);
|
||||||
sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks);
|
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, 1);
|
||||||
|
}
|
||||||
|
// We need to update nonce status (because we say that the block has been imported)
|
||||||
|
for h in &[good_blocks[0]] {
|
||||||
|
let block = client.block(BlockId::Hash(*h)).unwrap();
|
||||||
|
let view = BlockView::new(&block);
|
||||||
|
client.set_nonce(view.transactions()[0].sender().unwrap(), U256::from(1));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut queue = VecDeque::new();
|
||||||
|
let mut io = TestIo::new(&mut client, &mut queue, None);
|
||||||
|
sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let status = sync.miner.status();
|
let status = sync.miner.status();
|
||||||
@ -1735,7 +1748,7 @@ mod tests {
|
|||||||
sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks);
|
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_future_queue, 0);
|
||||||
assert_eq!(sync.miner.status().transactions_in_pending_queue, 0);
|
assert_eq!(sync.miner.status().transactions_in_pending_queue, 0);
|
||||||
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();
|
||||||
|
@ -17,7 +17,7 @@ ethcore-rpc = { path = "../rpc" }
|
|||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" }
|
parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" }
|
||||||
# List of apps
|
# List of apps
|
||||||
parity-status = { git = "https://github.com/tomusdrw/parity-status.git", version = "0.1.5" }
|
parity-status = { git = "https://github.com/tomusdrw/parity-status.git", version = "0.1.7" }
|
||||||
parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true }
|
parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true }
|
||||||
clippy = { version = "0.0.63", optional = true}
|
clippy = { version = "0.0.63", optional = true}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user