Merge branch 'master' into closing

This commit is contained in:
Tomasz Drwięga 2016-04-06 19:07:56 +02:00
commit 1f9eb97d0a
52 changed files with 690 additions and 228 deletions

20
Cargo.lock generated
View File

@ -2,7 +2,7 @@
name = "parity" name = "parity"
version = "1.1.0" version = "1.1.0"
dependencies = [ dependencies = [
"clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)",
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)",
@ -97,9 +97,10 @@ dependencies = [
[[package]] [[package]]
name = "clippy" name = "clippy"
version = "0.0.54" version = "0.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
@ -211,7 +212,7 @@ dependencies = [
name = "ethcore" name = "ethcore"
version = "1.1.0" version = "1.1.0"
dependencies = [ dependencies = [
"clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 1.1.0", "ethash 1.1.0",
@ -238,7 +239,7 @@ dependencies = [
name = "ethcore-rpc" name = "ethcore-rpc"
version = "1.1.0" version = "1.1.0"
dependencies = [ dependencies = [
"clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 1.1.0", "ethash 1.1.0",
"ethcore 1.1.0", "ethcore 1.1.0",
"ethcore-util 1.1.0", "ethcore-util 1.1.0",
@ -262,7 +263,7 @@ dependencies = [
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"bigint 0.1.0", "bigint 0.1.0",
"chrono 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -306,7 +307,7 @@ dependencies = [
name = "ethminer" name = "ethminer"
version = "1.1.0" version = "1.1.0"
dependencies = [ dependencies = [
"clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.1.0", "ethcore 1.1.0",
"ethcore-util 1.1.0", "ethcore-util 1.1.0",
@ -320,7 +321,7 @@ dependencies = [
name = "ethsync" name = "ethsync"
version = "1.1.0" version = "1.1.0"
dependencies = [ dependencies = [
"clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.1.0", "ethcore 1.1.0",
"ethcore-util 1.1.0", "ethcore-util 1.1.0",
@ -695,6 +696,11 @@ dependencies = [
"syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "quine-mc_cluskey"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.3.14" version = "0.3.14"

View File

@ -21,7 +21,7 @@ daemonize = "0.2"
num_cpus = "0.2" num_cpus = "0.2"
number_prefix = "0.2" number_prefix = "0.2"
rpassword = "0.1" rpassword = "0.1"
clippy = { version = "0.0.54", optional = true } clippy = { version = "0.0.61", optional = true}
ethcore = { path = "ethcore" } ethcore = { path = "ethcore" }
ethcore-util = { path = "util" } ethcore-util = { path = "util" }
ethsync = { path = "sync" } ethsync = { path = "sync" }

View File

@ -17,7 +17,7 @@ ethcore-util = { path = "../util" }
evmjit = { path = "../evmjit", optional = true } evmjit = { path = "../evmjit", optional = true }
ethash = { path = "../ethash" } ethash = { path = "../ethash" }
num_cpus = "0.2" num_cpus = "0.2"
clippy = { version = "0.0.54", optional = true } clippy = { version = "0.0.61", optional = true}
crossbeam = "0.1.5" crossbeam = "0.1.5"
lazy_static = "0.1" lazy_static = "0.1"
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }

View File

@ -154,7 +154,7 @@ impl ExecutedBlock {
} }
} }
/// Trait for a object that is_a `ExecutedBlock`. /// Trait for a object that is a `ExecutedBlock`.
pub trait IsBlock { pub trait IsBlock {
/// Get the block associated with this object. /// Get the block associated with this object.
fn block(&self) -> &ExecutedBlock; fn block(&self) -> &ExecutedBlock;
@ -192,7 +192,7 @@ pub struct OpenBlock<'x> {
last_hashes: LastHashes, last_hashes: LastHashes,
} }
/// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, /// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
/// and collected the uncles. /// and collected the uncles.
/// ///
/// There is no function available to push a transaction. /// There is no function available to push a transaction.
@ -204,7 +204,7 @@ pub struct ClosedBlock {
unclosed_state: State, unclosed_state: State,
} }
/// Just like ClosedBlock except that we can't reopen it and it's faster. /// Just like `ClosedBlock` except that we can't reopen it and it's faster.
/// ///
/// We actually store the post-`Engine::on_close_block` state, unlike in `ClosedBlock` where it's the pre. /// We actually store the post-`Engine::on_close_block` state, unlike in `ClosedBlock` where it's the pre.
#[derive(Clone)] #[derive(Clone)]
@ -216,14 +216,15 @@ pub struct LockedBlock {
/// A block that has a valid seal. /// A block that has a valid seal.
/// ///
/// The block's header has valid seal arguments. The block cannot be reversed into a ClosedBlock or OpenBlock. /// The block's header has valid seal arguments. The block cannot be reversed into a `ClosedBlock` or `OpenBlock`.
pub struct SealedBlock { pub struct SealedBlock {
block: ExecutedBlock, block: ExecutedBlock,
uncle_bytes: Bytes, uncle_bytes: Bytes,
} }
impl<'x> OpenBlock<'x> { impl<'x> OpenBlock<'x> {
/// Create a new OpenBlock ready for transaction pushing. #[cfg_attr(feature="dev", allow(too_many_arguments))]
/// Create a new `OpenBlock` ready for transaction pushing.
pub fn new(engine: &'x Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self { pub fn new(engine: &'x Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self {
let mut r = OpenBlock { let mut r = OpenBlock {
block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing), block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing),
@ -319,7 +320,7 @@ impl<'x> OpenBlock<'x> {
} }
} }
/// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. /// Turn this into a `ClosedBlock`. A `BlockChain` must be provided in order to figure out the uncles.
pub fn close(self) -> ClosedBlock { pub fn close(self) -> ClosedBlock {
let mut s = self; let mut s = self;
@ -454,6 +455,7 @@ impl IsBlock for SealedBlock {
} }
/// Enact the block given by block header, transactions and uncles /// Enact the block given by block header, transactions and uncles
#[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<LockedBlock, Error> { pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<LockedBlock, Error> {
{ {
if ::log::max_log_level() >= ::log::LogLevel::Trace { if ::log::max_log_level() >= ::log::LogLevel::Trace {

View File

@ -14,7 +14,7 @@
// 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/>.
//! A queue of blocks. Sits between network or other I/O and the BlockChain. //! A queue of blocks. Sits between network or other I/O and the `BlockChain`.
//! Sorts them ready for blockchain insertion. //! Sorts them ready for blockchain insertion.
use std::thread::{JoinHandle, self}; use std::thread::{JoinHandle, self};
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
@ -89,7 +89,7 @@ impl BlockQueueInfo {
} }
} }
/// A queue of blocks. Sits between network or other I/O and the BlockChain. /// A queue of blocks. Sits between network or other I/O and the `BlockChain`.
/// Sorts them ready for blockchain insertion. /// Sorts them ready for blockchain insertion.
pub struct BlockQueue { pub struct BlockQueue {
panic_handler: Arc<PanicHandler>, panic_handler: Arc<PanicHandler>,

View File

@ -427,6 +427,7 @@ impl BlockChain {
} }
} }
#[cfg_attr(feature="dev", allow(similar_names))]
/// Inserts the block into backing cache database. /// Inserts the block into backing cache database.
/// Expects the block to be valid and already verified. /// Expects the block to be valid and already verified.
/// If the block is already known, does nothing. /// If the block is already known, does nothing.
@ -855,6 +856,7 @@ impl BlockChain {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![cfg_attr(feature="dev", allow(similar_names))]
use std::str::FromStr; use std::str::FromStr;
use rustc_serialize::hex::FromHex; use rustc_serialize::hex::FromHex;
use util::hash::*; use util::hash::*;

View File

@ -87,6 +87,7 @@ impl Indexer {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![cfg_attr(feature="dev", allow(similar_names))]
use chainfilter::BloomIndex; use chainfilter::BloomIndex;
use chainfilter::indexer::Indexer; use chainfilter::indexer::Indexer;

View File

@ -23,7 +23,7 @@ use chainfilter::{BloomIndex, FilterDataSource, ChainFilter};
/// In memory cache for blooms. /// In memory cache for blooms.
/// ///
/// Stores all blooms in HashMap, which indexes them by `BloomIndex`. /// Stores all blooms in `HashMap`, which indexes them by `BloomIndex`.
pub struct MemoryCache { pub struct MemoryCache {
blooms: HashMap<BloomIndex, H2048>, blooms: HashMap<BloomIndex, H2048>,
} }

View File

@ -38,7 +38,7 @@ use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient}; use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient};
use env_info::EnvInfo; use env_info::EnvInfo;
use executive::{Executive, Executed, contract_address}; use executive::{Executive, Executed, TransactOptions, contract_address};
use receipt::LocalizedReceipt; use receipt::LocalizedReceipt;
pub use blockchain::CacheSize as BlockChainCacheSize; pub use blockchain::CacheSize as BlockChainCacheSize;
@ -418,7 +418,8 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
// give the sender max balance // give the sender max balance
state.sub_balance(&sender, &balance); state.sub_balance(&sender, &balance);
state.add_balance(&sender, &U256::max_value()); state.add_balance(&sender, &U256::max_value());
Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, false) let options = TransactOptions { tracing: false, check_nonce: false };
Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, options)
} }
// TODO [todr] Should be moved to miner crate eventually. // TODO [todr] Should be moved to miner crate eventually.

View File

@ -65,7 +65,7 @@ pub enum Error {
/// Evm result. /// Evm result.
/// ///
/// Returns gas_left if execution is successful, otherwise error. /// Returns `gas_left` if execution is successful, otherwise error.
pub type Result = result::Result<U256, Error>; pub type Result = result::Result<U256, Error>;
/// Evm interface. /// Evm interface.

View File

@ -36,6 +36,14 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
From::from(stream.out().sha3()) From::from(stream.out().sha3())
} }
/// Transaction execution options.
pub struct TransactOptions {
/// Enable call tracing.
pub tracing: bool,
/// Check transaction nonce before execution.
pub check_nonce: bool,
}
/// Transaction execution receipt. /// Transaction execution receipt.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Executed { pub struct Executed {
@ -110,7 +118,7 @@ impl<'a> Executive<'a> {
} }
/// This funtion should be used to execute transaction. /// This funtion should be used to execute transaction.
pub fn transact(&'a mut self, t: &SignedTransaction, tracing: bool) -> Result<Executed, Error> { pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, Error> {
let sender = try!(t.sender()); let sender = try!(t.sender());
let nonce = self.state.nonce(&sender); let nonce = self.state.nonce(&sender);
@ -124,8 +132,10 @@ impl<'a> Executive<'a> {
let init_gas = t.gas - base_gas_required; let init_gas = t.gas - base_gas_required;
// validate transaction nonce // validate transaction nonce
if t.nonce != nonce { if options.check_nonce {
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); if t.nonce != nonce {
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
}
} }
// validate if transaction fits into given block // validate if transaction fits into given block
@ -151,7 +161,7 @@ impl<'a> Executive<'a> {
self.state.inc_nonce(&sender); self.state.inc_nonce(&sender);
self.state.sub_balance(&sender, &U256::from(gas_cost)); self.state.sub_balance(&sender, &U256::from(gas_cost));
let mut substate = Substate::new(tracing); let mut substate = Substate::new(options.tracing);
let (gas_left, output) = match t.action { let (gas_left, output) = match t.action {
Action::Create => { Action::Create => {
@ -881,7 +891,8 @@ mod tests {
let executed = { let executed = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false).unwrap() let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts).unwrap()
}; };
assert_eq!(executed.gas, U256::from(100_000)); assert_eq!(executed.gas, U256::from(100_000));
@ -914,7 +925,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {
@ -945,7 +957,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {
@ -978,7 +991,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {
@ -1011,7 +1025,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {

View File

@ -16,7 +16,7 @@
use common::*; use common::*;
use engine::Engine; use engine::Engine;
use executive::Executive; use executive::{Executive, TransactOptions};
use account_db::*; use account_db::*;
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "json-tests")] #[cfg(feature = "json-tests")]
@ -220,7 +220,8 @@ impl State {
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult { pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult {
// let old = self.to_pod(); // let old = self.to_pod();
let e = try!(Executive::new(self, env_info, engine).transact(t, tracing)); let options = TransactOptions { tracing: tracing, check_nonce: true };
let e = try!(Executive::new(self, env_info, engine).transact(t, options));
// TODO uncomment once to_pod() works correctly. // TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));

View File

@ -55,7 +55,7 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
/// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash. /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
/// Still operates on a individual block /// Still operates on a individual block
/// Returns a PreverifiedBlock structure populated with transactions /// Returns a `PreverifiedBlock` structure populated with transactions
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreverifiedBlock, Error> { pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreverifiedBlock, Error> {
try!(engine.verify_block_unordered(&header, Some(&bytes))); try!(engine.verify_block_unordered(&header, Some(&bytes)));
for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) { for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
@ -331,6 +331,7 @@ mod tests {
} }
#[test] #[test]
#[cfg_attr(feature="dev", allow(similar_names))]
fn test_verify_block() { fn test_verify_block() {
// Test against morden // Test against morden
let mut good = Header::new(); let mut good = Header::new();

View File

@ -145,14 +145,20 @@ struct Dispatch {
return_type_ty: Option<P<Ty>>, return_type_ty: Option<P<Ty>>,
} }
fn implement_dispatch_arm_invoke( // This is the expanded version of this:
//
// let invoke_serialize_stmt = quote_stmt!(cx, {
// ::bincode::serde::serialize(& $output_type_id { payload: self. $function_name ($hand_param_a, $hand_param_b) }, ::bincode::SizeLimit::Infinite).unwrap()
// });
//
// But the above does not allow comma-separated expressions for arbitrary number
// of parameters ...$hand_param_a, $hand_param_b, ... $hand_param_n
fn implement_dispatch_arm_invoke_stmt(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatch: &Dispatch, dispatch: &Dispatch,
) -> P<ast::Expr> ) -> ast::Stmt
{ {
let deserialize_expr = quote_expr!(cx, ::bincode::serde::deserialize_from(r, ::bincode::SizeLimit::Infinite).expect("ipc deserialization error, aborting"));
let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str());
let function_name = builder.id(dispatch.function_name.as_str()); let function_name = builder.id(dispatch.function_name.as_str());
let output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str()); let output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str());
@ -161,63 +167,71 @@ fn implement_dispatch_arm_invoke(
quote_expr!(cx, input. $arg_ident) quote_expr!(cx, input. $arg_ident)
}).collect::<Vec<P<ast::Expr>>>(); }).collect::<Vec<P<ast::Expr>>>();
// This is the expanded version of this: let ext_cx = &*cx;
// ::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
// let invoke_serialize_stmt = quote_stmt!(cx, { ext_cx.parse_sess(),
// ::bincode::serde::serialize(& $output_type_id { payload: self. $function_name ($hand_param_a, $hand_param_b) }, ::bincode::SizeLimit::Infinite).unwrap() ext_cx.cfg(),
// }); {
// let _sp = ext_cx.call_site();
// But the above does not allow comma-separated expressions for arbitrary number let mut tt = ::std::vec::Vec::new();
// of parameters ...$hand_param_a, $hand_param_b, ... $hand_param_n tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
let invoke_serialize_stmt = { tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
let ext_cx = &*cx; tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName)));
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts( tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
ext_cx.parse_sess(), tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serde"), ::syntax::parse::token::ModName)));
ext_cx.cfg(), tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
{ tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain)));
let _sp = ext_cx.call_site(); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
let mut tt = ::std::vec::Vec::new(); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); tt.extend(::quasi::ToTokens::to_tokens(&output_type_id, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serde"), ::syntax::parse::token::ModName))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain))); tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
tt.extend(::quasi::ToTokens::to_tokens(&output_type_id, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
for arg_expr in input_args_exprs { for arg_expr in input_args_exprs {
tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter()); tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); }
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("SizeLimit"), ::syntax::parse::token::ModName))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Infinite"), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("SizeLimit"), ::syntax::parse::token::ModName)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Infinite"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
})) tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
tt
})).unwrap()
}
fn implement_dispatch_arm_invoke(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
dispatch: &Dispatch,
buffer: bool,
) -> P<ast::Expr>
{
let deserialize_expr = if buffer {
quote_expr!(cx, ::bincode::serde::deserialize(buf).expect("ipc deserialization error, aborting"))
} else {
quote_expr!(cx, ::bincode::serde::deserialize_from(r, ::bincode::SizeLimit::Infinite).expect("ipc deserialization error, aborting"))
}; };
let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str());
let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch);
quote_expr!(cx, { quote_expr!(cx, {
let input: $input_type_id = $deserialize_expr; let input: $input_type_id = $deserialize_expr;
$invoke_serialize_stmt $invoke_serialize_stmt
@ -225,14 +239,31 @@ fn implement_dispatch_arm_invoke(
} }
/// generates dispatch match for method id /// generates dispatch match for method id
fn implement_dispatch_arm(cx: &ExtCtxt, builder: &aster::AstBuilder, index: u32, dispatch: &Dispatch) fn implement_dispatch_arm(
-> ast::Arm cx: &ExtCtxt,
builder: &aster::AstBuilder,
index: u32,
dispatch: &Dispatch,
buffer: bool,
) -> ast::Arm
{ {
let index_ident = builder.id(format!("{}", index).as_str()); let index_ident = builder.id(format!("{}", index).as_str());
let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch); let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer);
quote_arm!(cx, $index_ident => { $invoke_expr } ) quote_arm!(cx, $index_ident => { $invoke_expr } )
} }
fn implement_dispatch_arms(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
dispatches: &[Dispatch],
buffer: bool,
) -> Vec<ast::Arm>
{
let mut index = -1;
dispatches.iter()
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer) }).collect()
}
/// generates client type for specified server type /// generates client type for specified server type
/// for say `Service` it generates `ServiceClient` /// for say `Service` it generates `ServiceClient`
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) { fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) {
@ -511,9 +542,9 @@ fn implement_interface(
dispatch_table.push(push_invoke_signature_aster(builder, &impl_item, signature, push)); dispatch_table.push(push_invoke_signature_aster(builder, &impl_item, signature, push));
} }
} }
let mut index = -1;
let dispatch_arms: Vec<_> = dispatch_table.iter() let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false);
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch) }).collect(); let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true);
Ok((quote_item!(cx, Ok((quote_item!(cx,
impl $impl_generics ::ipc::IpcInterface<$ty> for $ty $where_clause { impl $impl_generics ::ipc::IpcInterface<$ty> for $ty $where_clause {
@ -531,6 +562,14 @@ fn implement_interface(
_ => vec![] _ => vec![]
} }
} }
fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec<u8>
{
match method_num {
$dispatch_arms_buffered
_ => vec![]
}
}
} }
).unwrap(), dispatch_table)) ).unwrap(), dispatch_table))
} }

12
ipc/nano/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "ethcore-ipc-nano"
version = "1.1.0"
authors = ["Nikolay Volf <nikolay@ethcore.io>"]
license = "GPL-3.0"
[features]
[dependencies]
"ethcore-ipc" = { path = "../rpc" }
nanomsg = "0.5.0"
log = "0.3"

214
ipc/nano/src/lib.rs Normal file
View File

@ -0,0 +1,214 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! IPC over nanomsg transport
extern crate ethcore_ipc as ipc;
extern crate nanomsg;
#[macro_use] extern crate log;
pub use ipc::*;
use std::sync::*;
use nanomsg::{Socket, Protocol, Error, Endpoint, PollRequest, PollFd, PollInOut};
const POLL_TIMEOUT: isize = 100;
pub struct Worker<S> where S: IpcInterface<S> {
service: Arc<S>,
sockets: Vec<(Socket, Endpoint)>,
polls: Vec<PollFd>,
buf: Vec<u8>,
}
#[derive(Debug)]
pub enum SocketError {
DuplexLink
}
impl<S> Worker<S> where S: IpcInterface<S> {
pub fn new(service: Arc<S>) -> Worker<S> {
Worker::<S> {
service: service.clone(),
sockets: Vec::new(),
polls: Vec::new(),
buf: Vec::new(),
}
}
pub fn poll(&mut self) {
let mut request = PollRequest::new(&mut self.polls[..]);
let _result_guard = Socket::poll(&mut request, POLL_TIMEOUT);
for (fd_index, fd) in request.get_fds().iter().enumerate() {
if fd.can_read() {
let (ref mut socket, _) = self.sockets[fd_index];
unsafe { self.buf.set_len(0); }
match socket.nb_read_to_end(&mut self.buf) {
Ok(method_sign_len) => {
if method_sign_len >= 2 {
// method_num
let method_num = self.buf[1] as u16 * 256 + self.buf[0] as u16;
// payload
let payload = &self.buf[2..];
// dispatching for ipc interface
let result = self.service.dispatch_buf(method_num, payload);
if let Err(e) = socket.nb_write(&result) {
warn!(target: "ipc", "Failed to write response: {:?}", e);
}
}
else {
warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len);
}
},
Err(Error::TryAgain) => {
},
Err(x) => {
warn!(target: "ipc", "Error polling connections {:?}", x);
panic!();
}
}
}
}
}
fn rebuild_poll_request(&mut self) {
self.polls = self.sockets.iter()
.map(|&(ref socket, _)| socket.new_pollfd(PollInOut::In))
.collect::<Vec<PollFd>>();
}
pub fn add_duplex(&mut self, addr: &str) -> Result<(), SocketError> {
let mut socket = try!(Socket::new(Protocol::Pair).map_err(|e| {
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
SocketError::DuplexLink
}));
let endpoint = try!(socket.bind(addr).map_err(|e| {
warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e);
SocketError::DuplexLink
}));
self.sockets.push((socket, endpoint));
self.rebuild_poll_request();
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::Worker;
use ipc::*;
use std::io::{Read, Write};
use std::sync::{Arc, RwLock};
use nanomsg::{Socket, Protocol, Endpoint};
struct TestInvoke {
method_num: u16,
params: Vec<u8>,
}
struct DummyService {
methods_stack: RwLock<Vec<TestInvoke>>,
}
impl DummyService {
fn new() -> DummyService {
DummyService { methods_stack: RwLock::new(Vec::new()) }
}
}
impl IpcInterface<DummyService> for DummyService {
fn dispatch<R>(&self, _r: &mut R) -> Vec<u8> where R: Read {
vec![]
}
fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec<u8> {
self.methods_stack.write().unwrap().push(
TestInvoke {
method_num: method_num,
params: buf.to_vec(),
});
vec![]
}
}
fn dummy_write(addr: &str, buf: &[u8]) -> (Socket, Endpoint) {
let mut socket = Socket::new(Protocol::Pair).unwrap();
let endpoint = socket.connect(addr).unwrap();
//thread::sleep_ms(10);
socket.write(buf).unwrap();
(socket, endpoint)
}
#[test]
fn can_create_worker() {
let worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
assert_eq!(0, worker.sockets.len());
}
#[test]
fn can_add_duplex_socket_to_worker() {
let mut worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
worker.add_duplex("ipc:///tmp/parity-test10.ipc").unwrap();
assert_eq!(1, worker.sockets.len());
}
#[test]
fn worker_can_poll_empty() {
let service = Arc::new(DummyService::new());
let mut worker = Worker::<DummyService>::new(service.clone());
worker.add_duplex("ipc:///tmp/parity-test20.ipc").unwrap();
worker.poll();
assert_eq!(0, service.methods_stack.read().unwrap().len());
}
#[test]
fn worker_can_poll() {
let url = "ipc:///tmp/parity-test30.ipc";
let mut worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
worker.add_duplex(url).unwrap();
let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]);
worker.poll();
assert_eq!(1, worker.service.methods_stack.read().unwrap().len());
assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num);
assert_eq!([7, 7, 6, 6], worker.service.methods_stack.read().unwrap()[0].params[..]);
}
#[test]
fn worker_can_poll_long() {
let url = "ipc:///tmp/parity-test40.ipc";
let mut worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
worker.add_duplex(url).unwrap();
let message = [0u8; 1024*1024];
let (_socket, _endpoint) = dummy_write(url, &message);
worker.poll();
assert_eq!(1, worker.service.methods_stack.read().unwrap().len());
assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num);
assert_eq!(vec![0u8; 1024*1024-2], worker.service.methods_stack.read().unwrap()[0].params);
}
}

View File

@ -21,8 +21,12 @@ use std::marker::Sync;
use std::sync::atomic::*; use std::sync::atomic::*;
pub trait IpcInterface<T> { pub trait IpcInterface<T> {
/// reads the message from io, dispatches the call and returns result /// reads the message from io, dispatches the call and returns serialized result
fn dispatch<R>(&self, r: &mut R) -> Vec<u8> where R: Read; fn dispatch<R>(&self, r: &mut R) -> Vec<u8> where R: Read;
/// deserialize the payload from buffer, dispatches invoke and returns serialized result
/// (for non-blocking io)
fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec<u8>;
} }
/// serializes method invocation (method_num and parameters) to the stream specified by `w` /// serializes method invocation (method_num and parameters) to the stream specified by `w`

View File

@ -10,7 +10,7 @@ rustc-serialize = "0.3"
serde = "0.7.0" serde = "0.7.0"
serde_json = "0.7.0" serde_json = "0.7.0"
serde_macros = { version = "0.7.0", optional = true } serde_macros = { version = "0.7.0", optional = true }
clippy = { version = "0.0.54", optional = true } clippy = { version = "0.0.61", optional = true}
[build-dependencies] [build-dependencies]
serde_codegen = { version = "0.7.0", optional = true } serde_codegen = { version = "0.7.0", optional = true }

View File

@ -17,7 +17,7 @@ log = "0.3"
env_logger = "0.3" env_logger = "0.3"
rustc-serialize = "0.3" rustc-serialize = "0.3"
rayon = "0.3.1" rayon = "0.3.1"
clippy = { version = "0.0.54", optional = true } clippy = { version = "0.0.61", optional = true}
[features] [features]
default = [] default = []

View File

@ -108,6 +108,9 @@ pub trait MinerService : Send + Sync {
/// Query pending transactions for hash /// Query pending transactions for hash
fn transaction(&self, hash: &H256) -> Option<SignedTransaction>; fn transaction(&self, hash: &H256) -> Option<SignedTransaction>;
/// Returns highest transaction nonce for given address.
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) }
} }

View File

@ -94,6 +94,7 @@ impl Miner {
} }
/// Prepares new block for sealing including top transactions from queue. /// Prepares new block for sealing including top transactions from queue.
#[cfg_attr(feature="dev", allow(match_same_arms))]
fn prepare_sealing(&self, chain: &BlockChainClient) { fn prepare_sealing(&self, chain: &BlockChainClient) {
trace!(target: "miner", "prepare_sealing: entering"); trace!(target: "miner", "prepare_sealing: entering");
let transactions = self.transaction_queue.lock().unwrap().top_transactions(); let transactions = self.transaction_queue.lock().unwrap().top_transactions();
@ -164,7 +165,7 @@ impl Miner {
} }
); );
if let Some(block) = b { if let Some(block) = b {
if sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash() != block.block().fields().header.hash()).unwrap_or(true) { 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());
sealing_work.push(block); sealing_work.push(block);
} }
@ -200,7 +201,7 @@ impl MinerService for Miner {
fn sensible_gas_price(&self) -> U256 { fn sensible_gas_price(&self) -> U256 {
// 10% above our minimum. // 10% above our minimum.
self.transaction_queue.lock().unwrap().minimal_gas_price().clone() * x!(110) / x!(100) *self.transaction_queue.lock().unwrap().minimal_gas_price() * x!(110) / x!(100)
} }
fn author(&self) -> Address { fn author(&self) -> Address {
@ -227,6 +228,10 @@ impl MinerService for Miner {
queue.find(hash) queue.find(hash)
} }
fn last_nonce(&self, address: &Address) -> Option<U256> {
self.transaction_queue.lock().unwrap().last_nonce(address)
}
fn update_sealing(&self, chain: &BlockChainClient) { fn update_sealing(&self, chain: &BlockChainClient) {
if self.sealing_enabled.load(atomic::Ordering::Relaxed) { if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
let current_no = chain.chain_info().best_block_number; let current_no = chain.chain_info().best_block_number;

View File

@ -18,7 +18,7 @@
//! Transaction Queue //! Transaction Queue
//! //!
//! TransactionQueue keeps track of all transactions seen by the node (received from other peers) and own transactions //! `TransactionQueue` keeps track of all transactions seen by the node (received from other peers) and own transactions
//! and orders them by priority. Top priority transactions are those with low nonce height (difference between //! and orders them by priority. Top priority transactions are those with low nonce height (difference between
//! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used //! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used
//! for comparison (higher gas price = higher priority). //! for comparison (higher gas price = higher priority).
@ -179,7 +179,7 @@ impl VerifiedTransaction {
/// Holds transactions accessible by (address, nonce) and by priority /// Holds transactions accessible by (address, nonce) and by priority
/// ///
/// TransactionSet keeps number of entries below limit, but it doesn't /// `TransactionSet` keeps number of entries below limit, but it doesn't
/// automatically happen during `insert/remove` operations. /// automatically happen during `insert/remove` operations.
/// You have to call `enforce_limit` to remove lowest priority transactions from set. /// You have to call `enforce_limit` to remove lowest priority transactions from set.
struct TransactionSet { struct TransactionSet {
@ -262,7 +262,7 @@ pub struct AccountDetails {
/// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue. /// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue.
const GAS_LIMIT_HYSTERESIS: usize = 10; // % const GAS_LIMIT_HYSTERESIS: usize = 10; // %
/// 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)
minimal_gas_price: U256, minimal_gas_price: U256,
@ -523,6 +523,11 @@ impl TransactionQueue {
self.last_nonces.clear(); self.last_nonces.clear();
} }
/// Returns highest transaction nonce for given address.
pub fn last_nonce(&self, address: &Address) -> Option<U256> {
self.last_nonces.get(address).cloned()
}
/// Checks if there are any transactions in `future` that should actually be promoted to `current` /// Checks if there are any transactions in `future` that should actually be promoted to `current`
/// (because nonce matches). /// (because nonce matches).
fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) {
@ -1255,4 +1260,29 @@ mod test {
assert_eq!(stats.future, 0); assert_eq!(stats.future, 0);
assert_eq!(stats.pending, 1); assert_eq!(stats.pending, 1);
} }
#[test]
fn should_return_none_when_transaction_from_given_address_does_not_exist() {
// given
let mut txq = TransactionQueue::new();
// then
assert_eq!(txq.last_nonce(&Address::default()), None);
}
#[test]
fn should_return_correct_nonce_when_transactions_from_given_address_exist() {
// given
let mut txq = TransactionQueue::new();
let tx = new_tx();
let from = tx.sender().unwrap();
let nonce = tx.nonce;
let details = |a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
// when
txq.add(tx, &details).unwrap();
// then
assert_eq!(txq.last_nonce(&from), Some(nonce));
}
} }

View File

@ -19,6 +19,7 @@
#![warn(missing_docs)] #![warn(missing_docs)]
#![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", feature(plugin))]
#![cfg_attr(feature="dev", plugin(clippy))] #![cfg_attr(feature="dev", plugin(clippy))]
#![cfg_attr(feature="dev", allow(useless_format))]
extern crate docopt; extern crate docopt;
extern crate num_cpus; extern crate num_cpus;
extern crate rustc_serialize; extern crate rustc_serialize;
@ -82,7 +83,7 @@ Parity. Ethereum Client.
Usage: Usage:
parity daemon <pid-file> [options] parity daemon <pid-file> [options]
parity account (new | list) parity account (new | list) [options]
parity [options] parity [options]
Protocol Options: Protocol Options:
@ -93,7 +94,7 @@ Protocol Options:
-d --db-path PATH Specify the database & configuration directory path -d --db-path PATH Specify the database & configuration directory path
[default: $HOME/.parity]. [default: $HOME/.parity].
--keys-path PATH Specify the path for JSON key files to be found --keys-path PATH Specify the path for JSON key files to be found
[default: $HOME/.web3/keys]. [default: $HOME/.parity/keys].
--identity NAME Specify your node's name. --identity NAME Specify your node's name.
Account Options: Account Options:
@ -357,9 +358,9 @@ impl Configuration {
die!("{}: Invalid basic transaction price given in USD. Must be a decimal number.", self.args.flag_usd_per_tx) die!("{}: Invalid basic transaction price given in USD. Must be a decimal number.", self.args.flag_usd_per_tx)
}); });
let usd_per_eth = match self.args.flag_usd_per_eth.as_str() { let usd_per_eth = match self.args.flag_usd_per_eth.as_str() {
"etherscan" => price_info::PriceInfo::get().map(|x| x.ethusd).unwrap_or_else(|| { "etherscan" => price_info::PriceInfo::get().map_or_else(|| {
die!("Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth.") die!("Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth.")
}), }, |x| x.ethusd),
x => FromStr::from_str(x).unwrap_or_else(|_| die!("{}: Invalid ether price given in USD. Must be a decimal number.", x)) x => FromStr::from_str(x).unwrap_or_else(|_| die!("{}: Invalid ether price given in USD. Must be a decimal number.", x))
}; };
let wei_per_usd: f32 = 1.0e18 / usd_per_eth; let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
@ -379,7 +380,7 @@ impl Configuration {
} }
} }
fn _keys_path(&self) -> String { fn keys_path(&self) -> String {
self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap())
} }
@ -417,7 +418,6 @@ impl Configuration {
} }
} }
#[cfg_attr(feature="dev", allow(useless_format))]
fn net_addresses(&self) -> (Option<SocketAddr>, Option<SocketAddr>) { fn net_addresses(&self) -> (Option<SocketAddr>, Option<SocketAddr>) {
let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), self.args.flag_port)); let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), self.args.flag_port));
let public_address = if self.args.flag_nat.starts_with("extip:") { let public_address = if self.args.flag_nat.starts_with("extip:") {
@ -446,7 +446,6 @@ impl Configuration {
ret ret
} }
#[cfg_attr(feature="dev", allow(useless_format))]
fn client_config(&self) -> ClientConfig { fn client_config(&self) -> ClientConfig {
let mut client_config = ClientConfig::default(); let mut client_config = ClientConfig::default();
match self.args.flag_cache { match self.args.flag_cache {
@ -501,7 +500,7 @@ impl Configuration {
fn execute_account_cli(&self) { fn execute_account_cli(&self) {
use util::keys::store::SecretStore; use util::keys::store::SecretStore;
use rpassword::read_password; use rpassword::read_password;
let mut secret_store = SecretStore::new(); 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: "); println!("Type password: ");
@ -535,7 +534,7 @@ impl Configuration {
.into_iter() .into_iter()
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
let account_service = AccountService::new(); let account_service = AccountService::new_in(Path::new(&self.keys_path()));
for d in &self.args.flag_unlock { for d in &self.args.flag_unlock {
let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| { let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| {
die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d) die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d)
@ -547,7 +546,6 @@ impl Configuration {
account_service account_service
} }
#[cfg_attr(feature="dev", allow(useless_format))]
fn execute_client(&self) { fn execute_client(&self) {
// Setup panic handler // Setup panic handler
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();

View File

@ -19,8 +19,8 @@ impl PriceInfo {
.and_then(|mut s| s.read_to_string(&mut body).ok()) .and_then(|mut s| s.read_to_string(&mut body).ok())
.and_then(|_| Json::from_str(&body).ok()) .and_then(|_| Json::from_str(&body).ok())
.and_then(|json| json.find_path(&["result", "ethusd"]) .and_then(|json| json.find_path(&["result", "ethusd"])
.and_then(|obj| match obj { .and_then(|obj| match *obj {
&Json::String(ref s) => Some(PriceInfo { Json::String(ref s) => Some(PriceInfo {
ethusd: FromStr::from_str(&s).unwrap() ethusd: FromStr::from_str(&s).unwrap()
}), }),
_ => None _ => None

View File

@ -22,7 +22,7 @@ ethminer = { path = "../miner" }
rustc-serialize = "0.3" rustc-serialize = "0.3"
transient-hashmap = "0.1" transient-hashmap = "0.1"
serde_macros = { version = "0.7.0", optional = true } serde_macros = { version = "0.7.0", optional = true }
clippy = { version = "0.0.54", optional = true } clippy = { version = "0.0.61", optional = true}
[build-dependencies] [build-dependencies]
serde_codegen = { version = "0.7.0", optional = true } serde_codegen = { version = "0.7.0", optional = true }

View File

@ -43,6 +43,10 @@ fn default_gas() -> U256 {
U256::from(21_000) 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,
@ -175,7 +179,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_gas), gas: request.gas.unwrap_or_else(default_call_gas),
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())
@ -186,9 +190,13 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
let hash = signed_transaction.hash(); let hash = signed_transaction.hash();
let import = { let import = {
let miner = take_weak!(self.miner);
let client = take_weak!(self.client); let client = take_weak!(self.client);
take_weak!(self.miner).import_transactions(vec![signed_transaction], |a: &Address| AccountDetails { take_weak!(self.miner).import_transactions(vec![signed_transaction], |a: &Address| AccountDetails {
nonce: client.nonce(a), nonce: miner
.last_nonce(a)
.map(|nonce| nonce + U256::one())
.unwrap_or_else(|| client.nonce(a)),
balance: client.balance(a), balance: client.balance(a),
}) })
}; };
@ -484,7 +492,11 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
let client = take_weak!(self.client); let client = take_weak!(self.client);
let miner = take_weak!(self.miner); let miner = take_weak!(self.miner);
EthTransaction { EthTransaction {
nonce: request.nonce.unwrap_or_else(|| client.nonce(&request.from)), nonce: request.nonce
.or_else(|| miner
.last_nonce(&request.from)
.map(|nonce| nonce + U256::one()))
.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(default_gas),
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()), gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),

View File

@ -49,7 +49,7 @@ impl<A> Personal for PersonalClient<A> where A: AccountProvider + 'static {
|(pass, )| { |(pass, )| {
let store = take_weak!(self.accounts); let store = take_weak!(self.accounts);
match store.new_account(&pass) { match store.new_account(&pass) {
Ok(address) => Ok(Value::String(format!("0x{:?}", address))), Ok(address) => to_value(&address),
Err(_) => Err(Error::internal_error()) Err(_) => Err(Error::internal_error())
} }
} }

View File

@ -23,6 +23,7 @@ use util::numbers::{Uint, U256};
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId}; use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId};
use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::log_entry::{LocalizedLogEntry, LogEntry};
use ethcore::receipt::LocalizedReceipt; use ethcore::receipt::LocalizedReceipt;
use ethcore::transaction::{Transaction, Action};
use v1::{Eth, EthClient}; use v1::{Eth, EthClient};
use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner};
@ -52,7 +53,7 @@ fn miner_service() -> Arc<TestMinerService> {
struct EthTester { struct EthTester {
pub client: Arc<TestBlockChainClient>, pub client: Arc<TestBlockChainClient>,
pub sync: Arc<TestSyncProvider>, pub sync: Arc<TestSyncProvider>,
_accounts_provider: Arc<TestAccountProvider>, pub accounts_provider: Arc<TestAccountProvider>,
miner: Arc<TestMinerService>, miner: Arc<TestMinerService>,
hashrates: Arc<RwLock<HashMap<H256, U256>>>, hashrates: Arc<RwLock<HashMap<H256, U256>>>,
pub io: IoHandler, pub io: IoHandler,
@ -72,7 +73,7 @@ impl Default for EthTester {
EthTester { EthTester {
client: client, client: client,
sync: sync, sync: sync,
_accounts_provider: ap, accounts_provider: ap,
miner: miner, miner: miner,
io: io, io: io,
hashrates: hashrates, hashrates: hashrates,
@ -453,9 +454,53 @@ fn rpc_eth_estimate_gas_default_block() {
} }
#[test] #[test]
#[ignore]
fn rpc_eth_send_transaction() { fn rpc_eth_send_transaction() {
unimplemented!() let account = TestAccount::new("123");
let address = account.address();
let secret = account.secret.clone();
let tester = EthTester::default();
tester.accounts_provider.accounts.write().unwrap().insert(address.clone(), account);
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_sendTransaction",
"params": [{
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a"
}],
"id": 1
}"#;
let t = Transaction {
nonce: U256::zero(),
gas_price: U256::from(0x9184e72a000u64),
gas: U256::from(0x76c0),
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
value: U256::from(0x9184e72au64),
data: vec![]
}.sign(&secret);
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
tester.miner.last_nonces.write().unwrap().insert(address.clone(), U256::zero());
let t = Transaction {
nonce: U256::one(),
gas_price: U256::from(0x9184e72a000u64),
gas: U256::from(0x76c0),
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
value: U256::from(0x9184e72au64),
data: vec![]
}.sign(&secret);
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
} }
#[test] #[test]

View File

@ -20,7 +20,7 @@ use std::sync::RwLock;
use std::collections::HashMap; use std::collections::HashMap;
use std::io; use std::io;
use util::hash::{Address, H256, FixedHash}; use util::hash::{Address, H256, FixedHash};
use util::crypto::{Secret, Signature}; use util::crypto::{Secret, Signature, KeyPair};
use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError}; use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError};
/// Account mock. /// Account mock.
@ -30,23 +30,31 @@ pub struct TestAccount {
pub unlocked: bool, pub unlocked: bool,
/// Account's password. /// Account's password.
pub password: String, pub password: String,
/// Account's secret.
pub secret: Secret,
} }
impl TestAccount { impl TestAccount {
/// Creates new test account. /// Creates new test account.
pub fn new(password: &str) -> Self { pub fn new(password: &str) -> Self {
let pair = KeyPair::create().unwrap();
TestAccount { TestAccount {
unlocked: false, unlocked: false,
password: password.to_owned(), password: password.to_owned(),
secret: pair.secret().clone()
} }
} }
/// Returns account address.
pub fn address(&self) -> Address {
KeyPair::from_secret(self.secret.clone()).unwrap().address()
}
} }
/// Test account provider. /// Test account provider.
pub struct TestAccountProvider { pub struct TestAccountProvider {
accounts: RwLock<HashMap<Address, TestAccount>>, /// Test provider accounts.
/// Added accounts passwords. pub accounts: RwLock<HashMap<Address, TestAccount>>,
pub adds: RwLock<Vec<String>>,
} }
impl TestAccountProvider { impl TestAccountProvider {
@ -54,7 +62,6 @@ impl TestAccountProvider {
pub fn new(accounts: HashMap<Address, TestAccount>) -> Self { pub fn new(accounts: HashMap<Address, TestAccount>) -> Self {
TestAccountProvider { TestAccountProvider {
accounts: RwLock::new(accounts), accounts: RwLock::new(accounts),
adds: RwLock::new(vec![]),
} }
} }
} }
@ -76,14 +83,20 @@ impl AccountProvider for TestAccountProvider {
} }
fn new_account(&self, pass: &str) -> Result<Address, io::Error> { fn new_account(&self, pass: &str) -> Result<Address, io::Error> {
let mut adds = self.adds.write().unwrap(); let account = TestAccount::new(pass);
let address = Address::from(adds.len() as u64 + 2); let address = KeyPair::from_secret(account.secret.clone()).unwrap().address();
adds.push(pass.to_owned()); self.accounts.write().unwrap().insert(address.clone(), account);
Ok(address) Ok(address)
} }
fn account_secret(&self, _account: &Address) -> Result<Secret, SigningError> { fn account_secret(&self, address: &Address) -> Result<Secret, SigningError> {
Ok(Secret::random()) // todo: consider checking if account is unlock. some test may need alteration then.
self.accounts
.read()
.unwrap()
.get(address)
.ok_or(SigningError::NoAccount)
.map(|acc| acc.secret.clone())
} }
fn sign(&self, _account: &Address, _message: &H256) -> Result<Signature, SigningError> { fn sign(&self, _account: &Address, _message: &H256) -> Result<Signature, SigningError> {

View File

@ -16,7 +16,7 @@
//! Test implementation of miner service. //! Test implementation of miner service.
use util::{Address, H256, Bytes}; use util::{Address, H256, Bytes, U256};
use util::standard::*; use util::standard::*;
use ethcore::error::Error; use ethcore::error::Error;
use ethcore::client::BlockChainClient; use ethcore::client::BlockChainClient;
@ -27,19 +27,22 @@ use ethminer::{MinerService, MinerStatus, AccountDetails};
/// Test miner service. /// Test miner service.
pub struct TestMinerService { pub struct TestMinerService {
/// Imported transactions. /// Imported transactions.
pub imported_transactions: RwLock<Vec<H256>>, pub imported_transactions: Mutex<Vec<SignedTransaction>>,
/// Latest closed block. /// Latest closed block.
pub latest_closed_block: Mutex<Option<ClosedBlock>>, pub latest_closed_block: Mutex<Option<ClosedBlock>>,
/// Pre-existed pending transactions /// Pre-existed pending transactions
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>, pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
/// Last nonces.
pub last_nonces: RwLock<HashMap<Address, U256>>,
} }
impl Default for TestMinerService { impl Default for TestMinerService {
fn default() -> TestMinerService { fn default() -> TestMinerService {
TestMinerService { TestMinerService {
imported_transactions: RwLock::new(Vec::new()), imported_transactions: Mutex::new(Vec::new()),
latest_closed_block: Mutex::new(None), latest_closed_block: Mutex::new(None),
pending_transactions: Mutex::new(HashMap::new()), pending_transactions: Mutex::new(HashMap::new()),
last_nonces: RwLock::new(HashMap::new()),
} }
} }
} }
@ -56,28 +59,52 @@ impl MinerService for TestMinerService {
} }
/// Imports transactions to transaction queue. /// Imports transactions to transaction queue.
fn import_transactions<T>(&self, _transactions: Vec<SignedTransaction>, _fetch_account: T) -> Vec<Result<(), Error>> fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, _fetch_account: T) -> Vec<Result<(), Error>>
where T: Fn(&Address) -> AccountDetails { unimplemented!(); } where T: Fn(&Address) -> AccountDetails {
// lets assume that all txs are valid
self.imported_transactions.lock().unwrap().extend_from_slice(&transactions);
transactions
.iter()
.map(|_| Ok(()))
.collect()
}
/// Returns hashes of transactions currently in pending /// Returns hashes of transactions currently in pending
fn pending_transactions_hashes(&self) -> Vec<H256> { vec![] } fn pending_transactions_hashes(&self) -> Vec<H256> {
vec![]
}
/// Removes all transactions from the queue and restart mining operation. /// Removes all transactions from the queue and restart mining operation.
fn clear_and_reset(&self, _chain: &BlockChainClient) { unimplemented!(); } fn clear_and_reset(&self, _chain: &BlockChainClient) {
unimplemented!();
}
/// Called when blocks are imported to chain, updates transactions queue. /// Called when blocks are imported to chain, updates transactions queue.
fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); } fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
unimplemented!();
}
/// New chain head event. Restart mining operation. /// New chain head event. Restart mining operation.
fn update_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } fn update_sealing(&self, _chain: &BlockChainClient) {
unimplemented!();
}
fn map_sealing_work<F, T>(&self, _chain: &BlockChainClient, _f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T { unimplemented!(); } fn map_sealing_work<F, T>(&self, _chain: &BlockChainClient, _f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
unimplemented!();
}
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> { fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
self.pending_transactions.lock().unwrap().get(hash).and_then(|tx_ref| Some(tx_ref.clone())) self.pending_transactions.lock().unwrap().get(hash).cloned()
}
fn last_nonce(&self, address: &Address) -> Option<U256> {
self.last_nonces.read().unwrap().get(address).cloned()
} }
/// 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.
fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> { unimplemented!(); } fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
unimplemented!();
}
} }

View File

@ -22,8 +22,7 @@ use util::numbers::*;
use std::collections::*; use std::collections::*;
fn accounts_provider() -> Arc<TestAccountProvider> { fn accounts_provider() -> Arc<TestAccountProvider> {
let mut accounts = HashMap::new(); let accounts = HashMap::new();
accounts.insert(Address::from(1), TestAccount::new("test"));
let ap = TestAccountProvider::new(accounts); let ap = TestAccountProvider::new(accounts);
Arc::new(ap) Arc::new(ap)
} }
@ -38,7 +37,11 @@ fn setup() -> (Arc<TestAccountProvider>, IoHandler) {
#[test] #[test]
fn accounts() { fn accounts() {
let (_test_provider, io) = setup(); let (test_provider, io) = setup();
test_provider.accounts
.write()
.unwrap()
.insert(Address::from(1), TestAccount::new("test"));
let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#;
@ -49,11 +52,22 @@ fn accounts() {
#[test] #[test]
fn new_account() { fn new_account() {
let (_test_provider, io) = setup(); let (test_provider, io) = setup();
let request = r#"{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["pass"], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["pass"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000002","id":1}"#;
assert_eq!(io.handle_request(request), Some(response.to_owned())); let res = io.handle_request(request);
let accounts = test_provider.accounts.read().unwrap();
assert_eq!(accounts.len(), 1);
let address = accounts
.keys()
.nth(0)
.cloned()
.unwrap();
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"","id":1}"#;
assert_eq!(res, Some(response));
} }

View File

@ -10,7 +10,7 @@ authors = ["Ethcore <admin@ethcore.io"]
[dependencies] [dependencies]
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" } ethcore = { path = "../ethcore" }
clippy = { version = "0.0.54", optional = true } clippy = { version = "0.0.61", optional = true}
ethminer = { path = "../miner" } ethminer = { path = "../miner" }
log = "0.3" log = "0.3"
env_logger = "0.3" env_logger = "0.3"

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
/// ///
/// BlockChain synchronization strategy. /// `BlockChain` synchronization strategy.
/// Syncs to peers and keeps up to date. /// Syncs to peers and keeps up to date.
/// This implementation uses ethereum protocol v63 /// This implementation uses ethereum protocol v63
/// ///
@ -127,7 +127,7 @@ pub struct SyncStatus {
pub protocol_version: u8, pub protocol_version: u8,
/// The underlying p2p network version. /// The underlying p2p network version.
pub network_id: U256, pub network_id: U256,
/// BlockChain height for the moment the sync started. /// `BlockChain` height for the moment the sync started.
pub start_block_number: BlockNumber, pub start_block_number: BlockNumber,
/// Last fully downloaded and imported block number (if any). /// Last fully downloaded and imported block number (if any).
pub last_imported_block_number: Option<BlockNumber>, pub last_imported_block_number: Option<BlockNumber>,
@ -1292,12 +1292,12 @@ impl ChainSync {
fn propagate_new_transactions(&mut self, io: &mut SyncIo) -> usize { fn propagate_new_transactions(&mut self, io: &mut SyncIo) -> usize {
// Early out of nobody to send to. // Early out of nobody to send to.
if self.peers.len() == 0 { if self.peers.is_empty() {
return 0; return 0;
} }
let mut packet = RlpStream::new_list(self.transactions_to_send.len()); let mut packet = RlpStream::new_list(self.transactions_to_send.len());
for tx in self.transactions_to_send.iter() { for tx in &self.transactions_to_send {
packet.append_raw(tx, 1); packet.append_raw(tx, 1);
} }
self.transactions_to_send.clear(); self.transactions_to_send.clear();
@ -1312,7 +1312,7 @@ impl ChainSync {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// taking at max of MAX_PEERS_PROPAGATION // taking at max of MAX_PEERS_PROPAGATION
lucky_peers.iter().map(|&id| id.clone()).take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::<Vec<PeerId>>() lucky_peers.iter().cloned().take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::<Vec<PeerId>>()
}; };
let sent = lucky_peers.len(); let sent = lucky_peers.len();
@ -1701,8 +1701,8 @@ mod tests {
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
for h in vec![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));
} }

View File

@ -27,7 +27,7 @@ crossbeam = "0.2"
slab = "0.1" slab = "0.1"
sha3 = { path = "sha3" } sha3 = { path = "sha3" }
serde = "0.7.0" serde = "0.7.0"
clippy = { version = "0.0.54", optional = true } clippy = { version = "0.0.61", optional = true}
json-tests = { path = "json-tests" } json-tests = { path = "json-tests" }
igd = "0.4.2" igd = "0.4.2"
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }

View File

@ -157,6 +157,7 @@ impl KeyPair {
} }
/// EC functions /// EC functions
#[cfg_attr(feature="dev", allow(similar_names))]
pub mod ec { pub mod ec {
use numbers::*; use numbers::*;
use standard::*; use standard::*;
@ -193,6 +194,7 @@ pub mod ec {
} }
Ok(signature) Ok(signature)
} }
/// Verify signature. /// Verify signature.
pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result<bool, CryptoError> { pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result<bool, CryptoError> {
use secp256k1::*; use secp256k1::*;
@ -233,6 +235,7 @@ pub mod ec {
} }
/// ECDH functions /// ECDH functions
#[cfg_attr(feature="dev", allow(similar_names))]
pub mod ecdh { pub mod ecdh {
use crypto::*; use crypto::*;
use crypto::{self}; use crypto::{self};
@ -254,6 +257,7 @@ pub mod ecdh {
} }
/// ECIES function /// ECIES function
#[cfg_attr(feature="dev", allow(similar_names))]
pub mod ecies { pub mod ecies {
use hash::*; use hash::*;
use bytes::*; use bytes::*;

View File

@ -392,7 +392,7 @@ macro_rules! impl_hash {
} }
} }
/// BitOr on references /// `BitOr` on references
impl<'a> BitOr for &'a $from { impl<'a> BitOr for &'a $from {
type Output = $from; type Output = $from;
@ -408,7 +408,7 @@ macro_rules! impl_hash {
} }
} }
/// Moving BitOr /// Moving `BitOr`
impl BitOr for $from { impl BitOr for $from {
type Output = $from; type Output = $from;
@ -417,7 +417,7 @@ macro_rules! impl_hash {
} }
} }
/// BitAnd on references /// `BitAnd` on references
impl <'a> BitAnd for &'a $from { impl <'a> BitAnd for &'a $from {
type Output = $from; type Output = $from;
@ -433,7 +433,7 @@ macro_rules! impl_hash {
} }
} }
/// Moving BitAnd /// Moving `BitAnd`
impl BitAnd for $from { impl BitAnd for $from {
type Output = $from; type Output = $from;
@ -442,7 +442,7 @@ macro_rules! impl_hash {
} }
} }
/// BitXor on references /// `BitXor` on references
impl <'a> BitXor for &'a $from { impl <'a> BitXor for &'a $from {
type Output = $from; type Output = $from;
@ -458,7 +458,7 @@ macro_rules! impl_hash {
} }
} }
/// Moving BitXor /// Moving `BitXor`
impl BitXor for $from { impl BitXor for $from {
type Output = $from; type Output = $from;

View File

@ -14,7 +14,7 @@
// 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/>.
//! Disk-backed HashDB implementation. //! Disk-backed `HashDB` implementation.
use common::*; use common::*;
use rlp::*; use rlp::*;
@ -25,11 +25,11 @@ use kvdb::{Database, DBTransaction, DatabaseConfig};
#[cfg(test)] #[cfg(test)]
use std::env; use std::env;
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics. /// and latent-removal semantics.
/// ///
/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to
/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect
/// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before
/// the removals actually take effect. /// the removals actually take effect.
pub struct ArchiveDB { pub struct ArchiveDB {
@ -176,6 +176,7 @@ impl JournalDB for ArchiveDB {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![cfg_attr(feature="dev", allow(blacklisted_name))] #![cfg_attr(feature="dev", allow(blacklisted_name))]
#![cfg_attr(feature="dev", allow(similar_names))]
use common::*; use common::*;
use super::*; use super::*;

View File

@ -14,7 +14,7 @@
// 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/>.
//! Disk-backed HashDB implementation. //! Disk-backed `HashDB` implementation.
use common::*; use common::*;
use rlp::*; use rlp::*;
@ -53,11 +53,11 @@ enum RemoveFrom {
Archive, Archive,
} }
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics. /// and latent-removal semantics.
/// ///
/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to
/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect
/// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before
/// the removals actually take effect. /// the removals actually take effect.
pub struct EarlyMergeDB { pub struct EarlyMergeDB {
@ -528,6 +528,7 @@ impl JournalDB for EarlyMergeDB {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![cfg_attr(feature="dev", allow(blacklisted_name))] #![cfg_attr(feature="dev", allow(blacklisted_name))]
#![cfg_attr(feature="dev", allow(similar_names))]
use common::*; use common::*;
use super::*; use super::*;

View File

@ -14,7 +14,7 @@
// 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/>.
//! JournalDB interface and implementation. //! `JournalDB` interface and implementation.
use common::*; use common::*;
@ -25,7 +25,7 @@ mod earlymergedb;
mod overlayrecentdb; mod overlayrecentdb;
mod refcounteddb; mod refcounteddb;
/// Export the JournalDB trait. /// Export the `JournalDB` trait.
pub use self::traits::JournalDB; pub use self::traits::JournalDB;
/// A journal database algorithm. /// A journal database algorithm.
@ -70,7 +70,7 @@ impl fmt::Display for Algorithm {
} }
} }
/// Create a new JournalDB trait object. /// Create a new `JournalDB` trait object.
pub fn new(path: &str, algorithm: Algorithm) -> Box<JournalDB> { pub fn new(path: &str, algorithm: Algorithm) -> Box<JournalDB> {
match algorithm { match algorithm {
Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)), Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)),

View File

@ -14,7 +14,7 @@
// 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/>.
//! JournalDB over in-memory overlay //! `JournalDB` over in-memory overlay
use common::*; use common::*;
use rlp::*; use rlp::*;
@ -25,11 +25,11 @@ use kvdb::{Database, DBTransaction, DatabaseConfig};
use std::env; use std::env;
use super::JournalDB; use super::JournalDB;
/// Implementation of the JournalDB trait for a disk-backed database with a memory overlay /// Implementation of the `JournalDB` trait for a disk-backed database with a memory overlay
/// and, possibly, latent-removal semantics. /// and, possibly, latent-removal semantics.
/// ///
/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to
/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect
/// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before
/// the removals actually take effect. /// the removals actually take effect.
/// ///
@ -359,6 +359,7 @@ impl HashDB for OverlayRecentDB {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![cfg_attr(feature="dev", allow(blacklisted_name))] #![cfg_attr(feature="dev", allow(blacklisted_name))]
#![cfg_attr(feature="dev", allow(similar_names))]
use common::*; use common::*;
use super::*; use super::*;

View File

@ -14,7 +14,7 @@
// 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/>.
//! Disk-backed, ref-counted JournalDB implementation. //! Disk-backed, ref-counted `JournalDB` implementation.
use common::*; use common::*;
use rlp::*; use rlp::*;
@ -25,11 +25,11 @@ use kvdb::{Database, DBTransaction, DatabaseConfig};
#[cfg(test)] #[cfg(test)]
use std::env; use std::env;
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics. /// and latent-removal semantics.
/// ///
/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to
/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect
/// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before
/// the removals actually take effect. /// the removals actually take effect.
pub struct RefCountedDB { pub struct RefCountedDB {
@ -195,6 +195,7 @@ impl JournalDB for RefCountedDB {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![cfg_attr(feature="dev", allow(blacklisted_name))] #![cfg_attr(feature="dev", allow(blacklisted_name))]
#![cfg_attr(feature="dev", allow(similar_names))]
use common::*; use common::*;
use super::*; use super::*;

View File

@ -14,12 +14,12 @@
// 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/>.
//! Disk-backed HashDB implementation. //! Disk-backed `HashDB` implementation.
use common::*; use common::*;
use hashdb::*; use hashdb::*;
/// A HashDB which can manage a short-term journal potentially containing many forks of mutually /// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually
/// exclusive actions. /// exclusive actions.
pub trait JournalDB : HashDB + Send + Sync { pub trait JournalDB : HashDB + Send + Sync {
/// Return a copy of ourself, in a box. /// Return a copy of ourself, in a box.

View File

@ -326,7 +326,7 @@ fn uuid_from_string(s: &str) -> Result<Uuid, UtilError> {
#[derive(Clone)] #[derive(Clone)]
/// Stored key file struct with encrypted message (cipher_text) /// Stored key file struct with encrypted message (`cipher_text`)
/// also contains password derivation function settings (PBKDF2/Scrypt) /// also contains password derivation function settings (PBKDF2/Scrypt)
pub struct KeyFileContent { pub struct KeyFileContent {
version: KeyFileVersion, version: KeyFileVersion,
@ -369,9 +369,9 @@ enum KeyFileParseError {
} }
impl KeyFileContent { impl KeyFileContent {
/// New stored key file struct with encrypted message (cipher_text) /// New stored key file struct with encrypted message (`cipher_text`)
/// also contains password derivation function settings (PBKDF2/Scrypt) /// also contains password derivation function settings (PBKDF2/Scrypt)
/// to decrypt cipher_text given the password is provided. /// to decrypt `cipher_text` given the password is provided.
pub fn new(crypto: KeyFileCrypto) -> KeyFileContent { pub fn new(crypto: KeyFileCrypto) -> KeyFileContent {
KeyFileContent { KeyFileContent {
id: new_uuid(), id: new_uuid(),

View File

@ -128,7 +128,7 @@ impl Default for AccountService {
} }
impl AccountService { impl AccountService {
/// New account service with the default location /// New account service with the keys store in default location
pub fn new() -> Self { pub fn new() -> Self {
let secret_store = RwLock::new(SecretStore::new()); let secret_store = RwLock::new(SecretStore::new());
secret_store.write().unwrap().try_import_existing(); secret_store.write().unwrap().try_import_existing();
@ -137,6 +137,15 @@ impl AccountService {
} }
} }
/// New account service with the keys store in specific location
pub fn new_in(path: &Path) -> Self {
let secret_store = RwLock::new(SecretStore::new_in(path));
secret_store.write().unwrap().try_import_existing();
AccountService {
secret_store: secret_store
}
}
#[cfg(test)] #[cfg(test)]
fn new_test(temp: &::devtools::RandomTempPath) -> Self { fn new_test(temp: &::devtools::RandomTempPath) -> Self {
let secret_store = RwLock::new(SecretStore::new_test(temp)); let secret_store = RwLock::new(SecretStore::new_test(temp));

View File

@ -14,7 +14,7 @@
// 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/>.
//! Key-Value store abstraction with RocksDB backend. //! Key-Value store abstraction with `RocksDB` backend.
use std::default::Default; use std::default::Default;
use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBVector, DBIterator, use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBVector, DBIterator,

View File

@ -14,7 +14,7 @@
// 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/>.
//! Reference-counted memory-based HashDB implementation. //! Reference-counted memory-based `HashDB` implementation.
use hash::*; use hash::*;
use bytes::*; use bytes::*;
@ -27,7 +27,7 @@ use std::collections::HashMap;
use std::default::Default; use std::default::Default;
#[derive(Debug,Clone)] #[derive(Debug,Clone)]
/// Reference-counted memory-based HashDB implementation. /// Reference-counted memory-based `HashDB` implementation.
/// ///
/// Use `new()` to create a new database. Insert items with `insert()`, remove items /// Use `new()` to create a new database. Insert items with `insert()`, remove items
/// with `remove()`, check for existence with `containce()` and lookup a hash to derive /// with `remove()`, check for existence with `containce()` and lookup a hash to derive

View File

@ -223,7 +223,7 @@ pub enum WriteStatus {
Complete Complete
} }
/// RLPx packet /// `RLPx` packet
pub struct Packet { pub struct Packet {
pub protocol: u16, pub protocol: u16,
pub data: Bytes, pub data: Bytes,
@ -237,7 +237,7 @@ enum EncryptedConnectionState {
Payload, Payload,
} }
/// Connection implementing RLPx framing /// Connection implementing `RLPx` framing
/// https://github.com/ethereum/devp2p/blob/master/rlpx.md#framing /// https://github.com/ethereum/devp2p/blob/master/rlpx.md#framing
pub struct EncryptedConnection { pub struct EncryptedConnection {
/// Underlying tcp connection /// Underlying tcp connection

View File

@ -48,7 +48,7 @@ enum HandshakeState {
StartSession, StartSession,
} }
/// RLPx protocol handhake. See https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake /// `RLPx` protocol handhake. See https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake
pub struct Handshake { pub struct Handshake {
/// Remote node public key /// Remote node public key
pub id: NodeId, pub id: NodeId,
@ -66,7 +66,7 @@ pub struct Handshake {
pub remote_ephemeral: Public, pub remote_ephemeral: Public,
/// Remote connection nonce. /// Remote connection nonce.
pub remote_nonce: H256, pub remote_nonce: H256,
/// Remote RLPx protocol version. /// Remote `RLPx` protocol version.
pub remote_version: u64, pub remote_version: u64,
/// A copy of received encryped auth packet /// A copy of received encryped auth packet
pub auth_cipher: Bytes, pub auth_cipher: Bytes,

View File

@ -14,7 +14,7 @@
// 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/>.
//! Disk-backed HashDB implementation. //! Disk-backed `HashDB` implementation.
use error::*; use error::*;
use hash::*; use hash::*;
@ -28,7 +28,7 @@ use std::env;
use std::collections::HashMap; use std::collections::HashMap;
use kvdb::{Database, DBTransaction}; use kvdb::{Database, DBTransaction};
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay. /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay.
/// ///
/// The operations `insert()` and `remove()` take place on the memory overlay; batches of /// The operations `insert()` and `remove()` take place on the memory overlay; batches of
/// such operations may be flushed to the disk-backed DB with `commit()` or discarded with /// such operations may be flushed to the disk-backed DB with `commit()` or discarded with

View File

@ -153,7 +153,7 @@ impl <T>ToBytes for T where T: FixedHash {
fn to_bytes_len(&self) -> usize { self.bytes().len() } fn to_bytes_len(&self) -> usize { self.bytes().len() }
} }
/// Error returned when FromBytes conversation goes wrong /// Error returned when `FromBytes` conversation goes wrong
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum FromBytesError { pub enum FromBytesError {
/// Expected more RLP data /// Expected more RLP data
@ -174,7 +174,7 @@ impl fmt::Display for FromBytesError {
} }
} }
/// Alias for the result of FromBytes trait /// Alias for the result of `FromBytes` trait
pub type FromBytesResult<T> = Result<T, FromBytesError>; pub type FromBytesResult<T> = Result<T, FromBytesError>;
/// Converts to given type from its bytes representation /// Converts to given type from its bytes representation

View File

@ -23,7 +23,7 @@ use super::trietraits::*;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// ///
/// Use it as a `Trie` trait object. You can use `raw()` to get the backing TrieDB object. /// Use it as a `Trie` trait object. You can use `raw()` to get the backing `TrieDB` object.
pub struct SecTrieDB<'db> { pub struct SecTrieDB<'db> {
raw: TrieDB<'db> raw: TrieDB<'db>
} }
@ -36,12 +36,12 @@ impl<'db> SecTrieDB<'db> {
SecTrieDB { raw: TrieDB::new(db, root) } SecTrieDB { raw: TrieDB::new(db, root) }
} }
/// Get a reference to the underlying raw TrieDB struct. /// Get a reference to the underlying raw `TrieDB` struct.
pub fn raw(&self) -> &TrieDB { pub fn raw(&self) -> &TrieDB {
&self.raw &self.raw
} }
/// Get a mutable reference to the underlying raw TrieDB struct. /// Get a mutable reference to the underlying raw `TrieDB` struct.
pub fn raw_mut(&mut self) -> &TrieDB { pub fn raw_mut(&mut self) -> &TrieDB {
&mut self.raw &mut self.raw
} }

View File

@ -23,7 +23,7 @@ use super::trietraits::*;
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// ///
/// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing TrieDBMut object. /// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing `TrieDBMut` object.
pub struct SecTrieDBMut<'db> { pub struct SecTrieDBMut<'db> {
raw: TrieDBMut<'db> raw: TrieDBMut<'db>
} }