Merge branch 'vmtracing' into diffing

This commit is contained in:
Gav Wood 2016-06-02 12:28:09 +02:00
commit bc5c3da2af
93 changed files with 2826 additions and 1597 deletions

View File

@ -33,7 +33,7 @@ env:
global: global:
# GH_TOKEN # GH_TOKEN
- secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw=
- TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethjson -p ethcore-dapps -p ethcore-signer" - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethjson -p ethcore-dapps -p ethcore-signer"
- ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
- KCOV_FEATURES="" - KCOV_FEATURES=""
- KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov" - KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov"
@ -72,7 +72,6 @@ after_success: |
$KCOV_CMD target/debug/deps/ethcore_rpc-* && $KCOV_CMD target/debug/deps/ethcore_rpc-* &&
$KCOV_CMD target/debug/deps/ethcore_dapps-* && $KCOV_CMD target/debug/deps/ethcore_dapps-* &&
$KCOV_CMD target/debug/deps/ethcore_signer-* && $KCOV_CMD target/debug/deps/ethcore_signer-* &&
$KCOV_CMD target/debug/deps/ethminer-* &&
$KCOV_CMD target/debug/deps/ethjson-* && $KCOV_CMD target/debug/deps/ethjson-* &&
$KCOV_CMD target/debug/parity-* && $KCOV_CMD target/debug/parity-* &&
[ $TRAVIS_BRANCH = master ] && [ $TRAVIS_BRANCH = master ] &&

23
Cargo.lock generated
View File

@ -17,7 +17,6 @@ dependencies = [
"ethcore-rpc 1.2.0", "ethcore-rpc 1.2.0",
"ethcore-signer 1.2.0", "ethcore-signer 1.2.0",
"ethcore-util 1.2.0", "ethcore-util 1.2.0",
"ethminer 1.2.0",
"ethsync 1.2.0", "ethsync 1.2.0",
"fdlimit 0.1.0", "fdlimit 0.1.0",
"hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -255,6 +254,7 @@ dependencies = [
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -334,7 +334,6 @@ dependencies = [
"ethcore-devtools 1.2.0", "ethcore-devtools 1.2.0",
"ethcore-util 1.2.0", "ethcore-util 1.2.0",
"ethjson 0.1.0", "ethjson 0.1.0",
"ethminer 1.2.0",
"ethsync 1.2.0", "ethsync 1.2.0",
"json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)", "json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)",
"jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -358,12 +357,7 @@ dependencies = [
"ethcore-util 1.2.0", "ethcore-util 1.2.0",
"jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ws 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -415,20 +409,6 @@ dependencies = [
"syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "ethminer"
version = "1.2.0"
dependencies = [
"clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.2.0",
"ethcore-util 1.2.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "ethsync" name = "ethsync"
version = "1.2.0" version = "1.2.0"
@ -437,7 +417,6 @@ dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.2.0", "ethcore 1.2.0",
"ethcore-util 1.2.0", "ethcore-util 1.2.0",
"ethminer 1.2.0",
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -27,7 +27,6 @@ clippy = { version = "0.0.69", optional = true}
ethcore = { path = "ethcore" } ethcore = { path = "ethcore" }
ethcore-util = { path = "util" } ethcore-util = { path = "util" }
ethsync = { path = "sync" } ethsync = { path = "sync" }
ethminer = { path = "miner" }
ethcore-devtools = { path = "devtools" } ethcore-devtools = { path = "devtools" }
ethcore-rpc = { path = "rpc", optional = true } ethcore-rpc = { path = "rpc", optional = true }
ethcore-signer = { path = "signer", optional = true } ethcore-signer = { path = "signer", optional = true }
@ -46,7 +45,7 @@ default-features = false
default = ["rpc", "dapps", "ethcore-signer"] default = ["rpc", "dapps", "ethcore-signer"]
rpc = ["ethcore-rpc"] rpc = ["ethcore-rpc"]
dapps = ["ethcore-dapps"] dapps = ["ethcore-dapps"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev", dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev",
"ethcore-dapps/dev", "ethcore-signer/dev"] "ethcore-dapps/dev", "ethcore-signer/dev"]
travis-beta = ["ethcore/json-tests"] travis-beta = ["ethcore/json-tests"]
travis-nightly = ["ethcore/json-tests", "dev"] travis-nightly = ["ethcore/json-tests", "dev"]

View File

@ -1,4 +1,5 @@
# ethcore # [Parity](https://ethcore.io/parity.html)
### Fast, light, and robust Ethereum implementation
[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/trogdoro/xiki][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url] [![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/trogdoro/xiki][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url]
@ -11,30 +12,64 @@
[license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg [license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg
[license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html [license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html
[Documentation](http://ethcore.github.io/parity/ethcore/index.html) [Internal Documentation](http://ethcore.github.io/parity/ethcore/index.html)
### Building from source ----
First (if you don't already have it) get multirust: ## About Parity
Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and
cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs.
By default, Parity will run a JSONRPC server on `127.0.0.1:8545`. This is fully configurable and supports a number
of RPC APIs.
Parity also runs a server for running decentralized apps, or "Dapps", on `http://127.0.0.1:8080`.
This includes a few useful Dapps, including Ethereum Wallet, Maker OTC, and a node status page.
In a near-future release, it will be easy to install Dapps and use them through this web interface.
If you run into an issue while using parity, feel free to file one in this repository
or hop on our [gitter chat room]([gitter-url]) to ask a question. We are glad to help!
Parity's current release is 1.1. You can download it at https://ethcore.io/parity.html or follow the instructions
below to build from source.
----
## Building from source
Parity is fully compatible with Stable Rust.
We recommend installing Rust through [multirust](https://github.com/brson/multirust). If you don't already have multirust, you can install it like this:
- Linux: - Linux:
```bash ```bash
curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sh $ curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sh
``` ```
- OSX with Homebrew: - OSX with Homebrew:
```bash ```bash
brew update && brew install multirust $ brew update && brew install multirust
multirust default stable $ multirust default stable
``` ```
Then, download and build Parity: Then, download and build Parity:
```bash ```bash
# download Parity code # download Parity code
git clone https://github.com/ethcore/parity $ git clone https://github.com/ethcore/parity
cd parity $ cd parity
# build in release mode # build in release mode
cargo build --release $ cargo build --release
``` ```
This will produce an executable in the `target/release` subdirectory.
Either run `cd target/release`, or copy `target/release/parity` to another location.
To get started, just run
```bash
$ parity
```
and parity will begin syncing the Ethereum blockchain.

View File

@ -38,11 +38,16 @@ pub fn utils() -> Box<Endpoint> {
pub fn all_endpoints() -> Endpoints { pub fn all_endpoints() -> Endpoints {
let mut pages = Endpoints::new(); let mut pages = Endpoints::new();
pages.insert("proxy".to_owned(), ProxyPac::boxed()); pages.insert("proxy".into(), ProxyPac::boxed());
// Home page needs to be safe embed
// because we use Cross-Origin LocalStorage.
// TODO [ToDr] Account naming should be moved to parity.
pages.insert("home".into(), Box::new(
PageEndpoint::new_safe_to_embed(parity_dapps_builtins::App::default())
));
insert::<parity_dapps_status::App>(&mut pages, "status"); insert::<parity_dapps_status::App>(&mut pages, "status");
insert::<parity_dapps_status::App>(&mut pages, "parity"); insert::<parity_dapps_status::App>(&mut pages, "parity");
insert::<parity_dapps_builtins::App>(&mut pages, "home");
wallet_page(&mut pages); wallet_page(&mut pages);
daodapp_page(&mut pages); daodapp_page(&mut pages);

View File

@ -21,7 +21,7 @@ use hyper::{header, server, Decoder, Encoder, Next};
use hyper::net::HttpStream; use hyper::net::HttpStream;
use std::io::Write; use std::io::Write;
use std::collections::HashMap; use std::collections::BTreeMap;
#[derive(Debug, PartialEq, Default, Clone)] #[derive(Debug, PartialEq, Default, Clone)]
pub struct EndpointPath { pub struct EndpointPath {
@ -45,7 +45,7 @@ pub trait Endpoint : Send + Sync {
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream>>; fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream>>;
} }
pub type Endpoints = HashMap<String, Box<Endpoint>>; pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
pub type Handler = server::Handler<HttpStream>; pub type Handler = server::Handler<HttpStream>;
pub struct ContentHandler { pub struct ContentHandler {

View File

@ -52,6 +52,7 @@ extern crate serde_json;
extern crate jsonrpc_core; extern crate jsonrpc_core;
extern crate jsonrpc_http_server; extern crate jsonrpc_http_server;
extern crate parity_dapps; extern crate parity_dapps;
extern crate ethcore_rpc;
mod endpoint; mod endpoint;
mod apps; mod apps;
@ -66,6 +67,7 @@ use std::net::SocketAddr;
use std::collections::HashMap; use std::collections::HashMap;
use jsonrpc_core::{IoHandler, IoDelegate}; use jsonrpc_core::{IoHandler, IoDelegate};
use router::auth::{Authorization, NoAuth, HttpBasicAuth}; use router::auth::{Authorization, NoAuth, HttpBasicAuth};
use ethcore_rpc::Extendable;
static DAPPS_DOMAIN : &'static str = ".parity"; static DAPPS_DOMAIN : &'static str = ".parity";
@ -74,6 +76,12 @@ pub struct ServerBuilder {
handler: Arc<IoHandler>, handler: Arc<IoHandler>,
} }
impl Extendable for ServerBuilder {
fn add_delegate<D: Send + Sync + 'static>(&self, delegate: IoDelegate<D>) {
self.handler.add_delegate(delegate);
}
}
impl ServerBuilder { impl ServerBuilder {
/// Construct new dapps server /// Construct new dapps server
pub fn new() -> Self { pub fn new() -> Self {
@ -82,11 +90,6 @@ impl ServerBuilder {
} }
} }
/// Add io delegate.
pub fn add_delegate<D>(&self, delegate: IoDelegate<D>) where D: Send + Sync + 'static {
self.handler.add_delegate(delegate);
}
/// Asynchronously start server with no authentication, /// Asynchronously start server with no authentication,
/// returns result with `Server` handle on success or an error. /// returns result with `Server` handle on success or an error.
pub fn start_unsecure_http(&self, addr: &SocketAddr) -> Result<Server, ServerError> { pub fn start_unsecure_http(&self, addr: &SocketAddr) -> Result<Server, ServerError> {

View File

@ -30,6 +30,8 @@ pub struct PageEndpoint<T : WebApp + 'static> {
pub app: Arc<T>, pub app: Arc<T>,
/// Prefix to strip from the path (when `None` deducted from `app_id`) /// Prefix to strip from the path (when `None` deducted from `app_id`)
pub prefix: Option<String>, pub prefix: Option<String>,
/// Safe to be loaded in frame by other origin. (use wisely!)
safe_to_embed: bool,
} }
impl<T: WebApp + 'static> PageEndpoint<T> { impl<T: WebApp + 'static> PageEndpoint<T> {
@ -37,6 +39,7 @@ impl<T: WebApp + 'static> PageEndpoint<T> {
PageEndpoint { PageEndpoint {
app: Arc::new(app), app: Arc::new(app),
prefix: None, prefix: None,
safe_to_embed: false,
} }
} }
@ -44,6 +47,18 @@ impl<T: WebApp + 'static> PageEndpoint<T> {
PageEndpoint { PageEndpoint {
app: Arc::new(app), app: Arc::new(app),
prefix: Some(prefix), prefix: Some(prefix),
safe_to_embed: false,
}
}
/// Creates new `PageEndpoint` which can be safely used in iframe
/// even from different origin. It might be dangerous (clickjacking).
/// Use wisely!
pub fn new_safe_to_embed(app: T) -> Self {
PageEndpoint {
app: Arc::new(app),
prefix: None,
safe_to_embed: true,
} }
} }
} }
@ -61,6 +76,7 @@ impl<T: WebApp> Endpoint for PageEndpoint<T> {
path: path, path: path,
file: None, file: None,
write_pos: 0, write_pos: 0,
safe_to_embed: self.safe_to_embed,
}) })
} }
} }
@ -83,6 +99,7 @@ struct PageHandler<T: WebApp + 'static> {
path: EndpointPath, path: EndpointPath,
file: Option<String>, file: Option<String>,
write_pos: usize, write_pos: usize,
safe_to_embed: bool,
} }
impl<T: WebApp + 'static> PageHandler<T> { impl<T: WebApp + 'static> PageHandler<T> {
@ -128,6 +145,9 @@ impl<T: WebApp + 'static> server::Handler<HttpStream> for PageHandler<T> {
if let Some(f) = self.file.as_ref().and_then(|f| self.app.file(f)) { if let Some(f) = self.file.as_ref().and_then(|f| self.app.file(f)) {
res.set_status(StatusCode::Ok); res.set_status(StatusCode::Ok);
res.headers_mut().set(header::ContentType(f.content_type.parse().unwrap())); res.headers_mut().set(header::ContentType(f.content_type.parse().unwrap()));
if !self.safe_to_embed {
res.headers_mut().set_raw("X-Frame-Options", vec![b"SAMEORIGIN".to_vec()]);
}
Next::write() Next::write()
} else { } else {
res.set_status(StatusCode::NotFound); res.set_status(StatusCode::NotFound);
@ -192,6 +212,7 @@ fn should_extract_path_with_appid() {
}, },
file: None, file: None,
write_pos: 0, write_pos: 0,
safe_to_embed: true,
}; };
// when // when

View File

@ -8,17 +8,19 @@ authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs" build = "build.rs"
[build-dependencies] [build-dependencies]
syntex = "*" syntex = "0.32"
ethcore-ipc-codegen = { path = "../ipc/codegen" } ethcore-ipc-codegen = { path = "../ipc/codegen" }
[dependencies] [dependencies]
ethcore-util = { path = "../util" }
clippy = { version = "0.0.67", optional = true} clippy = { version = "0.0.67", optional = true}
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
ethcore-ipc = { path = "../ipc/rpc" } ethcore-ipc = { path = "../ipc/rpc" }
rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" } rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" }
semver = "0.2" semver = "0.2"
ethcore-ipc-nano = { path = "../ipc/nano" } ethcore-ipc-nano = { path = "../ipc/nano" }
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
crossbeam = "0.2"
ethcore-util = { path = "../util" }
[features] [features]
dev = ["clippy"] dev = ["clippy"]

View File

@ -18,15 +18,13 @@
use traits::*; use traits::*;
use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBIterator, use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBIterator,
IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction}; IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction};
use std::collections::BTreeMap; use std::sync::{RwLock, Arc};
use std::sync::{RwLock};
use std::convert::From; use std::convert::From;
use ipc::IpcConfig; use ipc::IpcConfig;
use std::ops::*;
use std::mem; use std::mem;
use ipc::binary::BinaryConvertError; use ipc::binary::BinaryConvertError;
use std::collections::VecDeque; use std::collections::{VecDeque, HashMap, BTreeMap};
impl From<String> for Error { impl From<String> for Error {
fn from(s: String) -> Error { fn from(s: String) -> Error {
@ -34,20 +32,136 @@ impl From<String> for Error {
} }
} }
enum WriteCacheEntry {
Remove,
Write(Vec<u8>),
}
pub struct WriteCache {
entries: HashMap<Vec<u8>, WriteCacheEntry>,
preferred_len: usize,
}
const FLUSH_BATCH_SIZE: usize = 4096;
impl WriteCache {
fn new(cache_len: usize) -> WriteCache {
WriteCache {
entries: HashMap::new(),
preferred_len: cache_len,
}
}
fn write(&mut self, key: Vec<u8>, val: Vec<u8>) {
self.entries.insert(key, WriteCacheEntry::Write(val));
}
fn remove(&mut self, key: Vec<u8>) {
self.entries.insert(key, WriteCacheEntry::Remove);
}
fn get(&self, key: &Vec<u8>) -> Option<Vec<u8>> {
self.entries.get(key).and_then(
|vec_ref| match vec_ref {
&WriteCacheEntry::Write(ref val) => Some(val.clone()),
&WriteCacheEntry::Remove => None
})
}
/// WriteCache should be locked for this
fn flush(&mut self, db: &DB, amount: usize) -> Result<(), Error> {
let batch = WriteBatch::new();
let mut removed_so_far = 0;
while removed_so_far < amount {
if self.entries.len() == 0 { break; }
let removed_key = {
let (key, cache_entry) = self.entries.iter().nth(0)
.expect("if entries.len == 0, we should have break in the loop, still we got here somehow");
match *cache_entry {
WriteCacheEntry::Write(ref val) => {
try!(batch.put(&key, val));
},
WriteCacheEntry::Remove => {
try!(batch.delete(&key));
},
}
key.clone()
};
self.entries.remove(&removed_key);
removed_so_far = removed_so_far + 1;
}
if removed_so_far > 0 {
try!(db.write(batch));
}
Ok(())
}
/// flushes until cache is empty
fn flush_all(&mut self, db: &DB) -> Result<(), Error> {
while !self.is_empty() { try!(self.flush(db, FLUSH_BATCH_SIZE)); }
Ok(())
}
fn is_empty(&self) -> bool {
self.entries.is_empty()
}
fn try_shrink(&mut self, db: &DB) -> Result<(), Error> {
if self.entries.len() > self.preferred_len {
try!(self.flush(db, FLUSH_BATCH_SIZE));
}
Ok(())
}
}
pub struct Database { pub struct Database {
db: RwLock<Option<DB>>, db: RwLock<Option<DB>>,
transactions: RwLock<BTreeMap<TransactionHandle, WriteBatch>>, /// Iterators - dont't use between threads!
iterators: RwLock<BTreeMap<IteratorHandle, DBIterator>>, iterators: RwLock<BTreeMap<IteratorHandle, DBIterator>>,
write_cache: RwLock<WriteCache>,
} }
unsafe impl Send for Database {}
unsafe impl Sync for Database {}
impl Database { impl Database {
pub fn new() -> Database { pub fn new() -> Database {
Database { Database {
db: RwLock::new(None), db: RwLock::new(None),
transactions: RwLock::new(BTreeMap::new()),
iterators: RwLock::new(BTreeMap::new()), iterators: RwLock::new(BTreeMap::new()),
write_cache: RwLock::new(WriteCache::new(DEFAULT_CACHE_LEN)),
} }
} }
pub fn flush(&self) -> Result<(), Error> {
let mut cache_lock = self.write_cache.write().unwrap();
let db_lock = self.db.read().unwrap();
if db_lock.is_none() { return Ok(()); }
let db = db_lock.as_ref().unwrap();
try!(cache_lock.try_shrink(&db));
Ok(())
}
pub fn flush_all(&self) -> Result<(), Error> {
let mut cache_lock = self.write_cache.write().unwrap();
let db_lock = self.db.read().unwrap();
if db_lock.is_none() { return Ok(()); }
let db = db_lock.as_ref().expect("we should have exited with Ok(()) on the previous step");
try!(cache_lock.flush_all(&db));
Ok(())
}
}
impl Drop for Database {
fn drop(&mut self) {
self.flush().unwrap();
}
} }
#[derive(Ipc)] #[derive(Ipc)]
@ -72,51 +186,64 @@ impl DatabaseService for Database {
Ok(()) Ok(())
} }
/// Opens database in the specified path with the default config
fn open_default(&self, path: String) -> Result<(), Error> {
self.open(DatabaseConfig::default(), path)
}
fn close(&self) -> Result<(), Error> { fn close(&self) -> Result<(), Error> {
try!(self.flush_all());
let mut db = self.db.write().unwrap(); let mut db = self.db.write().unwrap();
if db.is_none() { return Err(Error::IsClosed); } if db.is_none() { return Err(Error::IsClosed); }
// TODO: wait for transactions to expire/close here?
if self.transactions.read().unwrap().len() > 0 { return Err(Error::UncommitedTransactions); }
*db = None; *db = None;
Ok(()) Ok(())
} }
fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> {
let db_lock = self.db.read().unwrap(); let mut cache_lock = self.write_cache.write().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed)); cache_lock.write(key.to_vec(), value.to_vec());
try!(db.put(key, value));
Ok(()) Ok(())
} }
fn delete(&self, key: &[u8]) -> Result<(), Error> { fn delete(&self, key: &[u8]) -> Result<(), Error> {
let db_lock = self.db.read().unwrap(); let mut cache_lock = self.write_cache.write().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed)); cache_lock.remove(key.to_vec());
try!(db.delete(key));
Ok(()) Ok(())
} }
fn write(&self, handle: TransactionHandle) -> Result<(), Error> { fn write(&self, transaction: DBTransaction) -> Result<(), Error> {
let db_lock = self.db.read().unwrap(); let mut cache_lock = self.write_cache.write().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
let mut transactions = self.transactions.write().unwrap(); let mut writes = transaction.writes.borrow_mut();
let batch = try!( for kv in writes.drain(..) {
transactions.remove(&handle).ok_or(Error::TransactionUnknown) cache_lock.write(kv.key, kv.value);
); }
try!(db.write(batch));
let mut removes = transaction.removes.borrow_mut();
for k in removes.drain(..) {
cache_lock.remove(k);
}
Ok(()) Ok(())
} }
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> { fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
{
let key_vec = key.to_vec();
let cache_hit = self.write_cache.read().unwrap().get(&key_vec);
if cache_hit.is_some() {
return Ok(Some(cache_hit.expect("cache_hit.is_some() = true, still there is none somehow here")))
}
}
let db_lock = self.db.read().unwrap(); let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed)); let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
match try!(db.get(key)) { match try!(db.get(key)) {
Some(db_vec) => Ok(Some(db_vec.to_vec())), Some(db_vec) => {
Ok(Some(db_vec.to_vec()))
},
None => Ok(None), None => Ok(None),
} }
} }
@ -166,37 +293,35 @@ impl DatabaseService for Database {
}) })
} }
fn transaction_put(&self, transaction: TransactionHandle, key: &[u8], value: &[u8]) -> Result<(), Error> fn dispose_iter(&self, handle: IteratorHandle) -> Result<(), Error> {
{ let mut iterators = self.iterators.write().unwrap();
let mut transactions = self.transactions.write().unwrap(); iterators.remove(&handle);
let batch = try!(
transactions.get_mut(&transaction).ok_or(Error::TransactionUnknown)
);
try!(batch.put(&key, &value));
Ok(()) Ok(())
} }
fn transaction_delete(&self, transaction: TransactionHandle, key: &[u8]) -> Result<(), Error> {
let mut transactions = self.transactions.write().unwrap();
let batch = try!(
transactions.get_mut(&transaction).ok_or(Error::TransactionUnknown)
);
try!(batch.delete(&key));
Ok(())
}
fn new_transaction(&self) -> TransactionHandle {
let mut transactions = self.transactions.write().unwrap();
let next_transaction = transactions.keys().last().unwrap_or(&0) + 1;
transactions.insert(next_transaction, WriteBatch::new());
next_transaction
}
} }
// TODO : put proper at compile-time // TODO : put proper at compile-time
impl IpcConfig for Database {} impl IpcConfig for Database {}
/// Database iterator
pub struct DatabaseIterator {
client: Arc<DatabaseClient<::nanomsg::Socket>>,
handle: IteratorHandle,
}
impl Iterator for DatabaseIterator {
type Item = (Vec<u8>, Vec<u8>);
fn next(&mut self) -> Option<Self::Item> {
self.client.iter_next(self.handle).and_then(|kv| Some((kv.key, kv.value)))
}
}
impl Drop for DatabaseIterator {
fn drop(&mut self) {
self.client.dispose_iter(self.handle).unwrap();
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
@ -215,7 +340,7 @@ mod test {
fn can_be_open_empty() { fn can_be_open_empty() {
let db = Database::new(); let db = Database::new();
let path = RandomTempPath::create_dir(); let path = RandomTempPath::create_dir();
db.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap(); db.open_default(path.as_str().to_owned()).unwrap();
assert!(db.is_empty().is_ok()); assert!(db.is_empty().is_ok());
} }
@ -224,9 +349,10 @@ mod test {
fn can_store_key() { fn can_store_key() {
let db = Database::new(); let db = Database::new();
let path = RandomTempPath::create_dir(); let path = RandomTempPath::create_dir();
db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap(); db.open_default(path.as_str().to_owned()).unwrap();
db.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); db.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
db.flush_all().unwrap();
assert!(!db.is_empty().unwrap()); assert!(!db.is_empty().unwrap());
} }
@ -234,15 +360,37 @@ mod test {
fn can_retrieve() { fn can_retrieve() {
let db = Database::new(); let db = Database::new();
let path = RandomTempPath::create_dir(); let path = RandomTempPath::create_dir();
db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap(); db.open_default(path.as_str().to_owned()).unwrap();
db.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); db.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
db.close().unwrap(); db.close().unwrap();
db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap(); db.open_default(path.as_str().to_owned()).unwrap();
assert_eq!(db.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec()); assert_eq!(db.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
} }
} }
#[cfg(test)]
mod write_cache_tests {
use super::Database;
use traits::*;
use devtools::*;
#[test]
fn cache_write_flush() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open_default(path.as_str().to_owned()).unwrap();
db.put("100500".as_bytes(), "1".as_bytes()).unwrap();
db.delete("100500".as_bytes()).unwrap();
db.flush_all().unwrap();
let val = db.get("100500".as_bytes()).unwrap();
assert!(val.is_none());
}
}
#[cfg(test)] #[cfg(test)]
mod client_tests { mod client_tests {
use super::{DatabaseClient, Database}; use super::{DatabaseClient, Database};
@ -251,6 +399,8 @@ mod client_tests {
use nanoipc; use nanoipc;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool}; use std::sync::atomic::{Ordering, AtomicBool};
use crossbeam;
use run_worker;
fn init_worker(addr: &str) -> nanoipc::Worker<Database> { fn init_worker(addr: &str) -> nanoipc::Worker<Database> {
let mut worker = nanoipc::Worker::<Database>::new(&Arc::new(Database::new())); let mut worker = nanoipc::Worker::<Database>::new(&Arc::new(Database::new()));
@ -268,7 +418,7 @@ mod client_tests {
::std::thread::spawn(move || { ::std::thread::spawn(move || {
let mut worker = init_worker(url); let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) { while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll(); worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed); c_worker_is_ready.store(true, Ordering::Relaxed);
} }
@ -295,7 +445,7 @@ mod client_tests {
::std::thread::spawn(move || { ::std::thread::spawn(move || {
let mut worker = init_worker(url); let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) { while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll(); worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed); c_worker_is_ready.store(true, Ordering::Relaxed);
} }
@ -304,7 +454,7 @@ mod client_tests {
while !worker_is_ready.load(Ordering::Relaxed) { } while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap(); let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap(); client.open_default(path.as_str().to_owned()).unwrap();
assert!(client.is_empty().unwrap()); assert!(client.is_empty().unwrap());
worker_should_exit.store(true, Ordering::Relaxed); worker_should_exit.store(true, Ordering::Relaxed);
} }
@ -314,27 +464,16 @@ mod client_tests {
let url = "ipc:///tmp/parity-db-ipc-test-30.ipc"; let url = "ipc:///tmp/parity-db-ipc-test-30.ipc";
let path = RandomTempPath::create_dir(); let path = RandomTempPath::create_dir();
let worker_should_exit = Arc::new(AtomicBool::new(false)); crossbeam::scope(move |scope| {
let worker_is_ready = Arc::new(AtomicBool::new(false)); let stop = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone(); run_worker(scope, stop.clone(), url);
let c_worker_is_ready = worker_is_ready.clone(); let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
client.close().unwrap();
::std::thread::spawn(move || { stop.store(true, Ordering::Relaxed);
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
}); });
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
client.close().unwrap();
worker_should_exit.store(true, Ordering::Relaxed);
} }
#[test] #[test]
@ -342,29 +481,93 @@ mod client_tests {
let url = "ipc:///tmp/parity-db-ipc-test-40.ipc"; let url = "ipc:///tmp/parity-db-ipc-test-40.ipc";
let path = RandomTempPath::create_dir(); let path = RandomTempPath::create_dir();
let worker_should_exit = Arc::new(AtomicBool::new(false)); crossbeam::scope(move |scope| {
let worker_is_ready = Arc::new(AtomicBool::new(false)); let stop = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone(); run_worker(scope, stop.clone(), url);
let c_worker_is_ready = worker_is_ready.clone(); let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
::std::thread::spawn(move || { client.open_default(path.as_str().to_owned()).unwrap();
let mut worker = init_worker(url); client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
while !c_worker_should_exit.load(Ordering::Relaxed) { client.close().unwrap();
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed); client.open_default(path.as_str().to_owned()).unwrap();
assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
stop.store(true, Ordering::Relaxed);
});
}
#[test]
fn can_read_empty() {
let url = "ipc:///tmp/parity-db-ipc-test-45.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(move |scope| {
let stop = Arc::new(AtomicBool::new(false));
run_worker(scope, stop.clone(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
assert!(client.get("xxx".as_bytes()).unwrap().is_none());
stop.store(true, Ordering::Relaxed);
});
}
#[test]
fn can_commit_client_transaction() {
let url = "ipc:///tmp/parity-db-ipc-test-60.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(move |scope| {
let stop = Arc::new(AtomicBool::new(false));
run_worker(scope, stop.clone(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
let transaction = DBTransaction::new();
transaction.put("xxx".as_bytes(), "1".as_bytes());
client.write(transaction).unwrap();
client.close().unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
stop.store(true, Ordering::Relaxed);
});
}
#[test]
fn key_write_read_ipc() {
let url = "ipc:///tmp/parity-db-ipc-test-70.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(|scope| {
let stop = StopGuard::new();
run_worker(&scope, stop.share(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
let mut batch = Vec::new();
for _ in 0..100 {
batch.push((random_str(256).as_bytes().to_vec(), random_str(256).as_bytes().to_vec()));
batch.push((random_str(256).as_bytes().to_vec(), random_str(2048).as_bytes().to_vec()));
batch.push((random_str(2048).as_bytes().to_vec(), random_str(2048).as_bytes().to_vec()));
batch.push((random_str(2048).as_bytes().to_vec(), random_str(256).as_bytes().to_vec()));
}
for &(ref k, ref v) in batch.iter() {
client.put(k, v).unwrap();
}
client.close().unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
for &(ref k, ref v) in batch.iter() {
assert_eq!(v, &client.get(k).unwrap().unwrap());
} }
}); });
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
client.close().unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
worker_should_exit.store(true, Ordering::Relaxed);
} }
} }

View File

@ -19,7 +19,71 @@ extern crate rocksdb;
extern crate ethcore_devtools as devtools; extern crate ethcore_devtools as devtools;
extern crate semver; extern crate semver;
extern crate ethcore_ipc_nano as nanoipc; extern crate ethcore_ipc_nano as nanoipc;
extern crate nanomsg;
extern crate crossbeam;
extern crate ethcore_util as util; extern crate ethcore_util as util;
pub mod database; pub mod database;
pub mod traits; pub mod traits;
pub use traits::{DatabaseService, DBTransaction, Error};
pub use database::{Database, DatabaseClient, DatabaseIterator};
use std::sync::Arc;
use std::sync::atomic::*;
use std::path::PathBuf;
pub type DatabaseNanoClient = DatabaseClient<::nanomsg::Socket>;
pub type DatabaseConnection = nanoipc::GuardedSocket<DatabaseNanoClient>;
#[derive(Debug)]
pub enum ServiceError {
Io(std::io::Error),
Socket(nanoipc::SocketError),
}
impl std::convert::From<std::io::Error> for ServiceError {
fn from(io_error: std::io::Error) -> ServiceError { ServiceError::Io(io_error) }
}
impl std::convert::From<nanoipc::SocketError> for ServiceError {
fn from(socket_error: nanoipc::SocketError) -> ServiceError { ServiceError::Socket(socket_error) }
}
pub fn blocks_service_url(db_path: &str) -> Result<String, std::io::Error> {
let mut path = PathBuf::from(db_path);
try!(::std::fs::create_dir_all(db_path));
path.push("blocks.ipc");
Ok(format!("ipc://{}", path.to_str().unwrap()))
}
pub fn extras_service_url(db_path: &str) -> Result<String, ::std::io::Error> {
let mut path = PathBuf::from(db_path);
try!(::std::fs::create_dir_all(db_path));
path.push("extras.ipc");
Ok(format!("ipc://{}", path.to_str().unwrap()))
}
pub fn blocks_client(db_path: &str) -> Result<DatabaseConnection, ServiceError> {
let url = try!(blocks_service_url(db_path));
let client = try!(nanoipc::init_client::<DatabaseClient<_>>(&url));
Ok(client)
}
pub fn extras_client(db_path: &str) -> Result<DatabaseConnection, ServiceError> {
let url = try!(extras_service_url(db_path));
let client = try!(nanoipc::init_client::<DatabaseClient<_>>(&url));
Ok(client)
}
// for tests
pub fn run_worker(scope: &crossbeam::Scope, stop: Arc<AtomicBool>, socket_path: &str) {
let socket_path = socket_path.to_owned();
scope.spawn(move || {
let mut worker = nanoipc::Worker::new(&Arc::new(Database::new()));
worker.add_reqrep(&socket_path).unwrap();
while !stop.load(Ordering::Relaxed) {
worker.poll();
}
});
}

View File

View File

@ -1,21 +1,38 @@
// 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/>.
//! Ethcore database trait //! Ethcore database trait
use ipc::BinaryConvertable;
use std::mem; use std::mem;
use ipc::binary::BinaryConvertError; use ipc::binary::BinaryConvertError;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::cell::RefCell;
pub type TransactionHandle = u32;
pub type IteratorHandle = u32; pub type IteratorHandle = u32;
pub const DEFAULT_CACHE_LEN: usize = 12288;
#[derive(Binary)] #[derive(Binary)]
pub struct KeyValue { pub struct KeyValue {
pub key: Vec<u8>, pub key: Vec<u8>,
pub value: Vec<u8>, pub value: Vec<u8>,
} }
#[derive(Debug, Binary)] #[derive(Debug, Binary)]
pub enum Error { pub enum Error {
AlreadyOpen, AlreadyOpen,
IsClosed, IsClosed,
RocksDb(String), RocksDb(String),
@ -28,13 +45,36 @@ pub enum Error {
#[derive(Binary)] #[derive(Binary)]
pub struct DatabaseConfig { pub struct DatabaseConfig {
/// Optional prefix size in bytes. Allows lookup by partial key. /// Optional prefix size in bytes. Allows lookup by partial key.
pub prefix_size: Option<usize> pub prefix_size: Option<usize>,
/// write cache length
pub cache: usize,
} }
pub trait DatabaseService { impl Default for DatabaseConfig {
fn default() -> DatabaseConfig {
DatabaseConfig {
prefix_size: None,
cache: DEFAULT_CACHE_LEN,
}
}
}
impl DatabaseConfig {
fn with_prefix(prefix: usize) -> DatabaseConfig {
DatabaseConfig {
prefix_size: Some(prefix),
cache: DEFAULT_CACHE_LEN,
}
}
}
pub trait DatabaseService : Sized {
/// Opens database in the specified path /// Opens database in the specified path
fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error>; fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error>;
/// Opens database in the specified path with the default config
fn open_default(&self, path: String) -> Result<(), Error>;
/// Closes database /// Closes database
fn close(&self) -> Result<(), Error>; fn close(&self) -> Result<(), Error>;
@ -44,18 +84,6 @@ pub trait DatabaseService {
/// Delete value by key. /// Delete value by key.
fn delete(&self, key: &[u8]) -> Result<(), Error>; fn delete(&self, key: &[u8]) -> Result<(), Error>;
/// Insert a key-value pair in the transaction. Any existing value value will be overwritten.
fn transaction_put(&self, transaction: TransactionHandle, key: &[u8], value: &[u8]) -> Result<(), Error>;
/// Delete value by key using transaction
fn transaction_delete(&self, transaction: TransactionHandle, key: &[u8]) -> Result<(), Error>;
/// Commit transaction to database.
fn write(&self, tr: TransactionHandle) -> Result<(), Error>;
/// Initiate new transaction on database
fn new_transaction(&self) -> TransactionHandle;
/// Get value by key. /// Get value by key.
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error>; fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error>;
@ -70,4 +98,35 @@ pub trait DatabaseService {
/// Next key-value for the the given iterator /// Next key-value for the the given iterator
fn iter_next(&self, iterator: IteratorHandle) -> Option<KeyValue>; fn iter_next(&self, iterator: IteratorHandle) -> Option<KeyValue>;
/// Dispose iteration that is no longer needed
fn dispose_iter(&self, handle: IteratorHandle) -> Result<(), Error>;
/// Write client transaction
fn write(&self, transaction: DBTransaction) -> Result<(), Error>;
}
#[derive(Binary)]
pub struct DBTransaction {
pub writes: RefCell<Vec<KeyValue>>,
pub removes: RefCell<Vec<Vec<u8>>>,
}
impl DBTransaction {
pub fn new() -> DBTransaction {
DBTransaction {
writes: RefCell::new(Vec::new()),
removes: RefCell::new(Vec::new()),
}
}
pub fn put(&self, key: &[u8], value: &[u8]) {
let mut brw = self.writes.borrow_mut();
brw.push(KeyValue { key: key.to_vec(), value: value.to_vec() });
}
pub fn delete(&self, key: &[u8]) {
let mut brw = self.removes.borrow_mut();
brw.push(key.to_vec());
}
} }

View File

@ -29,6 +29,7 @@ ethcore-devtools = { path = "../devtools" }
ethjson = { path = "../json" } ethjson = { path = "../json" }
bloomchain = "0.1" bloomchain = "0.1"
"ethcore-ipc" = { path = "../ipc/rpc" } "ethcore-ipc" = { path = "../ipc/rpc" }
rayon = "0.3.1"
[features] [features]
jit = ["evmjit"] jit = ["evmjit"]

View File

@ -34,18 +34,8 @@
"gasLimit": "0x2fefd8" "gasLimit": "0x2fefd8"
}, },
"nodes": [ "nodes": [
"enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303",
"enode://7ee7195bfac561ec938a72cd84cd1a5d2b334415263feddc325b20b5010446fc6c361297d13decab4039028fa659c1e27cca1396574b87cc7b29eea2985e97fe@108.61.197.28:30303",
"enode://933c5d5470b77537e7d9c1ee686132b5032dd3e2a096d2f64d2004df4ce9fca4ad6da5e358edcc8f81e65f047e40045600181f5fb35066e771025f6cca8e7952@46.101.114.191:30303",
"enode://ad4028ba28783d5bf58f512cb4e24a8ce980d768177c4974e1140b16b925132c947349db9ca3646752891b382dafc839a0c0716c3764c1ed9d424f09d13d01cf@148.251.220.116:30303",
"enode://c54ddaacddc7029683c80edae91015520eb2712176fbe6fdb7a5a074659270638f1266cba1731681c7cb785bceb02ca8d8b23024e3ec736fc5579f2042be97ae@54.175.255.230:30303",
"enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303",
"enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303", "enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303",
"enode://e941c58fed2709d792f552f408d2162c3d0a5597d22d1da617a9c9e6181f3251056a96adb45ae22eba70119355227298dc7e6dff805b092bae7da2f8564de422@85.25.217.23:30303", "enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303"
"enode://f4b73c9d11a780293ff0ca7afa12c67797afdc33a4797a7c2ecc5b87e455b32a8b9e9804f2004072bac38350bf82d52521d1a09590d2079705fc8357aef2bf9c@71.202.223.50:56603",
"enode://1173eea53e0cb2b8da92423e44cf4cbafbc8ea16c1558cf06e18dfc5a2fc9b140cc802a4362b4c773fb1442541e6f2a225b200bb4c1f6b347e7510a50fa4873f@104.41.138.167:30300",
"enode://1aad341327808738ad34655611f1b13293c4155dde36c8e3788128829f15cc6db2da9435f29520553d4efc134aadc50115690194ac3af519aac7a388b524811e@109.188.125.2:30303",
"enode://237dddd9a5f80c721eed6f3fe6bb87884a2c2b222b8f4b10fbad5e3a632b16d16ee885b11063a2de006a98f1f194d5a07844e8885c870b1da64fe41e55e05c3d@37.194.194.121:30303"
], ],
"accounts": { "accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },

View File

@ -259,7 +259,7 @@ mod tests {
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
let rlp = { let rlp = {
let mut a = Account::new_contract(x!(69), x!(0)); let mut a = Account::new_contract(69.into(), 0.into());
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.commit_storage(&mut db); a.commit_storage(&mut db);
a.init_code(vec![]); a.init_code(vec![]);
@ -279,7 +279,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
let rlp = { let rlp = {
let mut a = Account::new_contract(x!(69), x!(0)); let mut a = Account::new_contract(69.into(), 0.into());
a.init_code(vec![0x55, 0x44, 0xffu8]); a.init_code(vec![0x55, 0x44, 0xffu8]);
a.commit_code(&mut db); a.commit_code(&mut db);
a.rlp() a.rlp()
@ -294,10 +294,10 @@ mod tests {
#[test] #[test]
fn commit_storage() { fn commit_storage() {
let mut a = Account::new_contract(x!(69), x!(0)); let mut a = Account::new_contract(69.into(), 0.into());
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(x!(0), x!(0x1234)); a.set_storage(0.into(), 0x1234.into());
assert_eq!(a.storage_root(), None); assert_eq!(a.storage_root(), None);
a.commit_storage(&mut db); a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
@ -305,21 +305,21 @@ mod tests {
#[test] #[test]
fn commit_remove_commit_storage() { fn commit_remove_commit_storage() {
let mut a = Account::new_contract(x!(69), x!(0)); let mut a = Account::new_contract(69.into(), 0.into());
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(x!(0), x!(0x1234)); a.set_storage(0.into(), 0x1234.into());
a.commit_storage(&mut db); a.commit_storage(&mut db);
a.set_storage(x!(1), x!(0x1234)); a.set_storage(1.into(), 0x1234.into());
a.commit_storage(&mut db); a.commit_storage(&mut db);
a.set_storage(x!(1), x!(0)); a.set_storage(1.into(), 0.into());
a.commit_storage(&mut db); a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
} }
#[test] #[test]
fn commit_code() { fn commit_code() {
let mut a = Account::new_contract(x!(69), x!(0)); let mut a = Account::new_contract(69.into(), 0.into());
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]); a.init_code(vec![0x55, 0x44, 0xffu8]);

View File

@ -20,7 +20,7 @@ impl<'db> AccountDB<'db> {
pub fn new(db: &'db HashDB, address: &Address) -> AccountDB<'db> { pub fn new(db: &'db HashDB, address: &Address) -> AccountDB<'db> {
AccountDB { AccountDB {
db: db, db: db,
address: x!(address), address: address.into(),
} }
} }
} }
@ -67,7 +67,7 @@ impl<'db> AccountDBMut<'db> {
pub fn new(db: &'db mut HashDB, address: &Address) -> AccountDBMut<'db> { pub fn new(db: &'db mut HashDB, address: &Address) -> AccountDBMut<'db> {
AccountDBMut { AccountDBMut {
db: db, db: db,
address: x!(address), address: address.into(),
} }
} }

View File

@ -86,9 +86,9 @@ impl Engine for BasicAuthority {
let gas_limit = parent.gas_limit; let gas_limit = parent.gas_limit;
let bound_divisor = self.our_params.gas_limit_bound_divisor; let bound_divisor = self.our_params.gas_limit_bound_divisor;
if gas_limit < gas_floor_target { if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - x!(1)) min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
} else { } else {
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1)) max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
} }
}; };
header.note_dirty(); header.note_dirty();
@ -211,12 +211,12 @@ mod tests {
let engine = new_test_authority().engine; let engine = new_test_authority().engine;
let schedule = engine.schedule(&EnvInfo { let schedule = engine.schedule(&EnvInfo {
number: 10000000, number: 10000000,
author: x!(0), author: 0.into(),
timestamp: 0, timestamp: 0,
difficulty: x!(0), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: x!(0), gas_used: 0.into(),
gas_limit: x!(0) gas_limit: 0.into()
}); });
assert!(schedule.stack_limit > 0); assert!(schedule.stack_limit > 0);
@ -278,7 +278,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), x!(3141562), vec![]); let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), 3141562.into(), vec![]);
let b = b.close_and_lock(); let b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();

View File

@ -469,7 +469,7 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head
} }
} }
let mut b = OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone()); let mut b = OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone());
b.set_difficulty(*header.difficulty()); b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit()); b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp()); b.set_timestamp(header.timestamp());
@ -514,7 +514,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
let b = b.close_and_lock(); let b = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]); let _ = b.seal(engine.deref(), vec![]);
} }
@ -530,7 +530,7 @@ mod tests {
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close_and_lock().seal(engine.deref(), vec![]).unwrap(); let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes(); let orig_bytes = b.rlp_bytes();
let orig_db = b.drain(); let orig_db = b.drain();
@ -557,7 +557,7 @@ mod tests {
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); let vm_factory = Default::default();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]); let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]);
let mut uncle1_header = Header::new(); let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec(); uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new(); let mut uncle2_header = Header::new();

View File

@ -311,17 +311,17 @@ impl BlockQueue {
let h = header.hash(); let h = header.hash();
{ {
if self.processing.read().unwrap().contains(&h) { if self.processing.read().unwrap().contains(&h) {
return Err(x!(ImportError::AlreadyQueued)); return Err(ImportError::AlreadyQueued.into());
} }
let mut bad = self.verification.bad.lock().unwrap(); let mut bad = self.verification.bad.lock().unwrap();
if bad.contains(&h) { if bad.contains(&h) {
return Err(x!(ImportError::KnownBad)); return Err(ImportError::KnownBad.into());
} }
if bad.contains(&header.parent_hash) { if bad.contains(&header.parent_hash) {
bad.insert(h.clone()); bad.insert(h.clone());
return Err(x!(ImportError::KnownBad)); return Err(ImportError::KnownBad.into());
} }
} }

View File

@ -37,7 +37,7 @@ use filter::Filter;
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
use block_queue::{BlockQueue, BlockQueueInfo}; use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, TraceFilter, CallAnalytics}; use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, MiningBlockChainClient, TraceFilter, CallAnalytics};
use client::Error as ClientError; use client::Error as ClientError;
use env_info::EnvInfo; use env_info::EnvInfo;
use executive::{Executive, Executed, TransactOptions, contract_address}; use executive::{Executive, Executed, TransactOptions, contract_address};
@ -48,6 +48,7 @@ use trace;
pub use types::blockchain_info::BlockChainInfo; pub use types::blockchain_info::BlockChainInfo;
pub use types::block_status::BlockStatus; pub use types::block_status::BlockStatus;
use evm::Factory as EvmFactory; use evm::Factory as EvmFactory;
use miner::{Miner, MinerService, TransactionImportResult, AccountDetails};
impl fmt::Display for BlockChainInfo { impl fmt::Display for BlockChainInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -90,6 +91,7 @@ pub struct Client<V = CanonVerifier> where V: Verifier {
panic_handler: Arc<PanicHandler>, panic_handler: Arc<PanicHandler>,
verifier: PhantomData<V>, verifier: PhantomData<V>,
vm_factory: Arc<EvmFactory>, vm_factory: Arc<EvmFactory>,
miner: Arc<Miner>,
} }
const HISTORY: u64 = 1200; const HISTORY: u64 = 1200;
@ -102,8 +104,8 @@ const CLIENT_DB_VER_STR: &'static str = "5.3";
impl Client<CanonVerifier> { impl Client<CanonVerifier> {
/// Create a new client with given spec and DB path. /// Create a new client with given spec and DB path.
pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Result<Arc<Client>, ClientError> { pub fn new(config: ClientConfig, spec: Spec, path: &Path, miner: Arc<Miner>, message_channel: IoChannel<NetSyncMessage> ) -> Result<Arc<Client>, ClientError> {
Client::<CanonVerifier>::new_with_verifier(config, spec, path, message_channel) Client::<CanonVerifier>::new_with_verifier(config, spec, path, miner, message_channel)
} }
} }
@ -126,7 +128,14 @@ pub fn append_path(path: &Path, item: &str) -> String {
impl<V> Client<V> where V: Verifier { impl<V> Client<V> where V: Verifier {
/// Create a new client with given spec and DB path and custom verifier. /// Create a new client with given spec and DB path and custom verifier.
pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Result<Arc<Client<V>>, ClientError> { pub fn new_with_verifier(
config: ClientConfig,
spec: Spec,
path: &Path,
miner: Arc<Miner>,
message_channel: IoChannel<NetSyncMessage>)
-> Result<Arc<Client<V>>, ClientError>
{
let path = get_db_path(path, config.pruning, spec.genesis_header().hash()); let path = get_db_path(path, config.pruning, spec.genesis_header().hash());
let gb = spec.genesis_block(); let gb = spec.genesis_block();
let chain = Arc::new(BlockChain::new(config.blockchain, &gb, &path)); let chain = Arc::new(BlockChain::new(config.blockchain, &gb, &path));
@ -155,6 +164,7 @@ impl<V> Client<V> where V: Verifier {
panic_handler: panic_handler, panic_handler: panic_handler,
verifier: PhantomData, verifier: PhantomData,
vm_factory: Arc::new(EvmFactory::new(config.vm_type)), vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
miner: miner,
}; };
Ok(Arc::new(client)) Ok(Arc::new(client))
@ -328,6 +338,11 @@ impl<V> Client<V> where V: Verifier {
{ {
if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() {
let (enacted, retracted) = self.calculate_enacted_retracted(import_results); let (enacted, retracted) = self.calculate_enacted_retracted(import_results);
if self.queue_info().is_empty() {
self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted);
}
io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks {
imported: imported_blocks, imported: imported_blocks,
invalid: invalid_blocks, invalid: invalid_blocks,
@ -339,7 +354,7 @@ impl<V> Client<V> where V: Verifier {
{ {
if self.chain_info().best_block_hash != original_best { if self.chain_info().best_block_hash != original_best {
io.send(NetworkIoMessage::User(SyncMessage::NewChainHead)).unwrap(); self.miner.update_sealing(self);
} }
} }
@ -457,81 +472,10 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
ret ret
} }
// TODO [todr] Should be moved to miner crate eventually.
fn try_seal(&self, block: LockedBlock, seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock> {
block.try_seal(self.engine.deref().deref(), seal)
}
fn vm_factory(&self) -> &EvmFactory { fn vm_factory(&self) -> &EvmFactory {
&self.vm_factory &self.vm_factory
} }
// TODO [todr] Should be moved to miner crate eventually.
fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec<SignedTransaction>)
-> (Option<ClosedBlock>, HashSet<H256>) {
let engine = self.engine.deref().deref();
let h = self.chain.best_block_hash();
let mut invalid_transactions = HashSet::new();
let mut b = OpenBlock::new(
engine,
&self.vm_factory,
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().unwrap().boxed_clone(),
match self.chain.block_header(&h) { Some(ref x) => x, None => { return (None, invalid_transactions) } },
self.build_last_hashes(h.clone()),
author,
gas_floor_target,
extra_data,
);
// Add uncles
self.chain
.find_uncle_headers(&h, engine.maximum_uncle_age())
.unwrap()
.into_iter()
.take(engine.maximum_uncle_count())
.foreach(|h| {
b.push_uncle(h).unwrap();
});
// Add transactions
let block_number = b.block().header().number();
let min_tx_gas = U256::from(self.engine.schedule(&b.env_info()).tx_gas);
for tx in transactions {
// Push transaction to block
let hash = tx.hash();
let import = b.push_transaction(tx, None);
match import {
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => {
trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash);
// Exit early if gas left is smaller then min_tx_gas
if gas_limit - gas_used < min_tx_gas {
break;
}
},
Err(e) => {
invalid_transactions.insert(hash);
trace!(target: "miner",
"Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}",
block_number, hash, e);
},
_ => {}
}
}
// And close
let b = b.close();
trace!(target: "miner", "Sealing: number={}, hash={}, diff={}",
b.block().header().number(),
b.hash(),
b.block().header().difficulty()
);
(Some(b), invalid_transactions)
}
fn block_header(&self, id: BlockID) -> Option<Bytes> { fn block_header(&self, id: BlockID) -> Option<Bytes> {
Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()))
} }
@ -663,10 +607,10 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
{ {
let header = BlockView::new(&bytes).header_view(); let header = BlockView::new(&bytes).header_view();
if self.chain.is_known(&header.sha3()) { if self.chain.is_known(&header.sha3()) {
return Err(x!(ImportError::AlreadyInChain)); return Err(ImportError::AlreadyInChain.into());
} }
if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown { if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown {
return Err(x!(BlockError::UnknownParent(header.parent_hash()))); return Err(BlockError::UnknownParent(header.parent_hash()).into());
} }
} }
self.block_queue.import_block(bytes) self.block_queue.import_block(bytes)
@ -782,6 +726,89 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
fn last_hashes(&self) -> LastHashes { fn last_hashes(&self) -> LastHashes {
self.build_last_hashes(self.chain.best_block_hash()) self.build_last_hashes(self.chain.best_block_hash())
} }
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, Error>> {
let fetch_account = |a: &Address| AccountDetails {
nonce: self.latest_nonce(a),
balance: self.latest_balance(a),
};
self.miner.import_transactions(transactions, fetch_account)
}
fn all_transactions(&self) -> Vec<SignedTransaction> {
self.miner.all_transactions()
}
}
impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec<SignedTransaction>)
-> (Option<ClosedBlock>, HashSet<H256>) {
let engine = self.engine.deref().deref();
let h = self.chain.best_block_hash();
let mut invalid_transactions = HashSet::new();
let mut b = OpenBlock::new(
engine,
&self.vm_factory,
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().unwrap().boxed_clone(),
match self.chain.block_header(&h) { Some(ref x) => x, None => { return (None, invalid_transactions) } },
self.build_last_hashes(h.clone()),
author,
gas_floor_target,
extra_data,
);
// Add uncles
self.chain
.find_uncle_headers(&h, engine.maximum_uncle_age())
.unwrap()
.into_iter()
.take(engine.maximum_uncle_count())
.foreach(|h| {
b.push_uncle(h).unwrap();
});
// Add transactions
let block_number = b.block().header().number();
let min_tx_gas = U256::from(self.engine.schedule(&b.env_info()).tx_gas);
for tx in transactions {
// Push transaction to block
let hash = tx.hash();
let import = b.push_transaction(tx, None);
match import {
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => {
trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash);
// Exit early if gas left is smaller then min_tx_gas
if gas_limit - gas_used < min_tx_gas {
break;
}
},
Err(e) => {
invalid_transactions.insert(hash);
trace!(target: "miner",
"Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}",
block_number, hash, e);
},
_ => {}
}
}
// And close
let b = b.close();
trace!(target: "miner", "Sealing: number={}, hash={}, diff={}",
b.block().header().number(),
b.hash(),
b.block().header().difficulty()
);
(Some(b), invalid_transactions)
}
fn try_seal(&self, block: LockedBlock, seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock> {
block.try_seal(self.engine.deref().deref(), seal)
}
} }
impl MayPanic for Client { impl MayPanic for Client {

View File

@ -46,6 +46,8 @@ use error::{ImportResult, ExecutionError};
use receipt::LocalizedReceipt; use receipt::LocalizedReceipt;
use trace::LocalizedTrace; use trace::LocalizedTrace;
use evm::Factory as EvmFactory; use evm::Factory as EvmFactory;
use miner::{TransactionImportResult};
use error::Error as EthError;
/// Options concerning what analytics we run on the call. /// Options concerning what analytics we run on the call.
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)] #[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
@ -163,15 +165,6 @@ pub trait BlockChainClient : Sync + Send {
/// Returns logs matching given filter. /// Returns logs matching given filter.
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>; fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
// TODO [todr] Should be moved to miner crate eventually.
/// Returns ClosedBlock prepared for sealing.
fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec<SignedTransaction>)
-> (Option<ClosedBlock>, HashSet<H256>);
// TODO [todr] Should be moved to miner crate eventually.
/// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error.
fn try_seal(&self, block: LockedBlock, seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock>;
/// Makes a non-persistent transaction call. /// Makes a non-persistent transaction call.
// TODO: should be able to accept blockchain location for call. // TODO: should be able to accept blockchain location for call.
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>; fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>;
@ -193,5 +186,20 @@ pub trait BlockChainClient : Sync + Send {
/// Get last hashes starting from best block. /// Get last hashes starting from best block.
fn last_hashes(&self) -> LastHashes; fn last_hashes(&self) -> LastHashes;
/// import transactions from network/other 3rd party
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, EthError>>;
/// list all transactions
fn all_transactions(&self) -> Vec<SignedTransaction>;
} }
/// Extended client interface used for mining
pub trait MiningBlockChainClient : BlockChainClient {
/// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error.
fn try_seal(&self, block: LockedBlock, seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock>;
/// Returns ClosedBlock prepared for sealing.
fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec<SignedTransaction>)
-> (Option<ClosedBlock>, HashSet<H256>);
}

View File

@ -20,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder};
use util::*; use util::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute; use blockchain::TreeRoute;
use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics}; use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics};
use header::{Header as BlockHeader, BlockNumber}; use header::{Header as BlockHeader, BlockNumber};
use filter::Filter; use filter::Filter;
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
@ -28,6 +28,7 @@ use receipt::{Receipt, LocalizedReceipt};
use blockchain::extras::BlockReceipts; use blockchain::extras::BlockReceipts;
use error::{ImportResult}; use error::{ImportResult};
use evm::Factory as EvmFactory; use evm::Factory as EvmFactory;
use miner::{Miner, MinerService};
use block_queue::BlockQueueInfo; use block_queue::BlockQueueInfo;
use block::{SealedBlock, ClosedBlock, LockedBlock}; use block::{SealedBlock, ClosedBlock, LockedBlock};
@ -35,6 +36,9 @@ use executive::Executed;
use error::{ExecutionError}; use error::{ExecutionError};
use trace::LocalizedTrace; use trace::LocalizedTrace;
use miner::{TransactionImportResult, AccountDetails};
use error::Error as EthError;
/// Test client. /// Test client.
pub struct TestBlockChainClient { pub struct TestBlockChainClient {
/// Blocks. /// Blocks.
@ -61,6 +65,8 @@ pub struct TestBlockChainClient {
pub receipts: RwLock<HashMap<TransactionID, LocalizedReceipt>>, pub receipts: RwLock<HashMap<TransactionID, LocalizedReceipt>>,
/// Block queue size. /// Block queue size.
pub queue_size: AtomicUsize, pub queue_size: AtomicUsize,
/// Miner
pub miner: Arc<Miner>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -99,6 +105,7 @@ impl TestBlockChainClient {
execution_result: RwLock::new(None), execution_result: RwLock::new(None),
receipts: RwLock::new(HashMap::new()), receipts: RwLock::new(HashMap::new()),
queue_size: AtomicUsize::new(0), queue_size: AtomicUsize::new(0),
miner: Arc::new(Miner::default()),
}; };
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
client.genesis_hash = client.last_hash.read().unwrap().clone(); client.genesis_hash = client.last_hash.read().unwrap().clone();
@ -232,6 +239,17 @@ impl TestBlockChainClient {
} }
} }
impl MiningBlockChainClient for TestBlockChainClient {
fn try_seal(&self, block: LockedBlock, _seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock> {
Err(block)
}
fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec<SignedTransaction>) -> (Option<ClosedBlock>, HashSet<H256>) {
(None, HashSet::new())
}
}
impl BlockChainClient for TestBlockChainClient { impl BlockChainClient for TestBlockChainClient {
fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> { fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
Ok(self.execution_result.read().unwrap().clone().unwrap()) Ok(self.execution_result.read().unwrap().clone().unwrap())
@ -296,14 +314,6 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!(); unimplemented!();
} }
fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec<SignedTransaction>) -> (Option<ClosedBlock>, HashSet<H256>) {
(None, HashSet::new())
}
fn try_seal(&self, block: LockedBlock, _seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock> {
Err(block)
}
fn block_header(&self, id: BlockID) -> Option<Bytes> { fn block_header(&self, id: BlockID) -> Option<Bytes> {
self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
} }
@ -476,4 +486,19 @@ impl BlockChainClient for TestBlockChainClient {
fn block_traces(&self, _trace: BlockID) -> Option<Vec<LocalizedTrace>> { fn block_traces(&self, _trace: BlockID) -> Option<Vec<LocalizedTrace>> {
unimplemented!(); unimplemented!();
} }
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, EthError>> {
let nonces = self.nonces.read().unwrap();
let balances = self.balances.read().unwrap();
let fetch_account = |a: &Address| AccountDetails {
nonce: nonces[a],
balance: balances[a],
};
self.miner.import_transactions(transactions, &fetch_account)
}
fn all_transactions(&self) -> Vec<SignedTransaction> {
self.miner.all_transactions()
}
} }

View File

@ -47,10 +47,10 @@ impl Default for EnvInfo {
number: 0, number: 0,
author: Address::new(), author: Address::new(),
timestamp: 0, timestamp: 0,
difficulty: x!(0), difficulty: 0.into(),
gas_limit: x!(0), gas_limit: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: x!(0), gas_used: 0.into(),
} }
} }
} }
@ -92,15 +92,15 @@ mod tests {
assert_eq!(env_info.number, 1112339); assert_eq!(env_info.number, 1112339);
assert_eq!(env_info.author, Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()); assert_eq!(env_info.author, Address::from_str("000000f00000000f000000000000f00000000f00").unwrap());
assert_eq!(env_info.gas_limit, x!(40000)); assert_eq!(env_info.gas_limit, 40000.into());
assert_eq!(env_info.difficulty, x!(50000)); assert_eq!(env_info.difficulty, 50000.into());
assert_eq!(env_info.gas_used, x!(0)); assert_eq!(env_info.gas_used, 0.into());
} }
#[test] #[test]
fn it_can_be_created_as_default() { fn it_can_be_created_as_default() {
let default_env_info = EnvInfo::default(); let default_env_info = EnvInfo::default();
assert_eq!(default_env_info.difficulty, x!(0)); assert_eq!(default_env_info.difficulty, 0.into());
} }
} }

View File

@ -111,9 +111,9 @@ impl Engine for Ethash {
let gas_limit = parent.gas_limit; let gas_limit = parent.gas_limit;
let bound_divisor = self.ethash_params.gas_limit_bound_divisor; let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
if gas_limit < gas_floor_target { if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - x!(1)) min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
} else { } else {
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1) + (header.gas_used * x!(6) / x!(5)) / bound_divisor) max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into() + (header.gas_used * 6.into() / 5.into()) / bound_divisor)
} }
}; };
header.note_dirty(); header.note_dirty();
@ -255,12 +255,12 @@ impl Ethash {
/// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`. /// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`.
pub fn boundary_to_difficulty(boundary: &H256) -> U256 { pub fn boundary_to_difficulty(boundary: &H256) -> U256 {
U256::from((U512::one() << 256) / x!(U256::from(boundary.as_slice()))) U256::from((U512::one() << 256) / U256::from(boundary.as_slice()).into())
} }
/// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`. /// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`.
pub fn difficulty_to_boundary(difficulty: &U256) -> H256 { pub fn difficulty_to_boundary(difficulty: &U256) -> H256 {
x!(U256::from((U512::one() << 256) / x!(difficulty))) U256::from((U512::one() << 256) / difficulty.into()).into()
} }
fn to_ethash(hash: H256) -> EH256 { fn to_ethash(hash: H256) -> EH256 {
@ -308,7 +308,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
let b = b.close(); let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
} }
@ -323,7 +323,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
let mut uncle = Header::new(); let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone(); uncle.author = uncle_author.clone();
@ -346,24 +346,24 @@ mod tests {
let engine = new_morden().engine; let engine = new_morden().engine;
let schedule = engine.schedule(&EnvInfo { let schedule = engine.schedule(&EnvInfo {
number: 10000000, number: 10000000,
author: x!(0), author: 0.into(),
timestamp: 0, timestamp: 0,
difficulty: x!(0), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: x!(0), gas_used: 0.into(),
gas_limit: x!(0) gas_limit: 0.into()
}); });
assert!(schedule.stack_limit > 0); assert!(schedule.stack_limit > 0);
let schedule = engine.schedule(&EnvInfo { let schedule = engine.schedule(&EnvInfo {
number: 100, number: 100,
author: x!(0), author: 0.into(),
timestamp: 0, timestamp: 0,
difficulty: x!(0), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: x!(0), gas_used: 0.into(),
gas_limit: x!(0) gas_limit: 0.into()
}); });
assert!(!schedule.have_delegate_call); assert!(!schedule.have_delegate_call);

View File

@ -416,7 +416,7 @@ impl<'a> Executive<'a> {
let refunds_bound = sstore_refunds + suicide_refunds; let refunds_bound = sstore_refunds + suicide_refunds;
// real ammount to refund // real ammount to refund
let gas_left_prerefund = match result { Ok(x) => x, _ => x!(0) }; let gas_left_prerefund = match result { Ok(x) => x, _ => 0.into() };
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) / U256::from(2)); let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) / U256::from(2));
let gas_left = gas_left_prerefund + refunded; let gas_left = gas_left_prerefund + refunded;
@ -651,10 +651,10 @@ mod tests {
let expected_trace = vec![ Trace { let expected_trace = vec![ Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("cd1722f3947def4cf144679da39c4c32bdc35681"), from: "cd1722f3947def4cf144679da39c4c32bdc35681".into(),
to: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), to: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(),
value: x!(100), value: 100.into(),
gas: x!(100000), gas: 100000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -664,9 +664,9 @@ mod tests {
subs: vec![Trace { subs: vec![Trace {
depth: 1, depth: 1,
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), from: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(),
value: x!(23), value: 23.into(),
gas: x!(67979), gas: 67979.into(),
init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85] init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85]
}), }),
result: trace::Res::Create(trace::CreateResult { result: trace::Res::Create(trace::CreateResult {
@ -683,28 +683,28 @@ mod tests {
parent_step: 0, parent_step: 0,
code: vec![124, 96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85, 96, 0, 82, 96, 29, 96, 3, 96, 23, 240, 96, 0, 85], code: vec![124, 96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85, 96, 0, 82, 96, 29, 96, 3, 96, 23, 240, 96, 0, 85],
operations: vec![ operations: vec![
VMOperation { pc: 0, instruction: 124, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99997.into(), stack_push: vecx![U256::from_dec_str("2589892687202724018173567190521546555304938078595079151649957320078677").unwrap()], mem_diff: None, store_diff: None }) }, VMOperation { pc: 0, instruction: 124, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99997.into(), stack_push: vec_into![U256::from_dec_str("2589892687202724018173567190521546555304938078595079151649957320078677").unwrap()], mem_diff: None, store_diff: None }) },
VMOperation { pc: 30, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99994.into(), stack_push: vecx![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 30, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99994.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 32, instruction: 82, gas_cost: 6.into(), executed: Some(VMExecutedOperation { gas_used: 99988.into(), stack_push: vecx![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![0, 0, 0, 96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85] }), store_diff: None }) }, VMOperation { pc: 32, instruction: 82, gas_cost: 6.into(), executed: Some(VMExecutedOperation { gas_used: 99988.into(), stack_push: vec_into![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![0, 0, 0, 96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85] }), store_diff: None }) },
VMOperation { pc: 33, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99985.into(), stack_push: vecx![29], mem_diff: None, store_diff: None }) }, VMOperation { pc: 33, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99985.into(), stack_push: vec_into![29], mem_diff: None, store_diff: None }) },
VMOperation { pc: 35, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99982.into(), stack_push: vecx![3], mem_diff: None, store_diff: None }) }, VMOperation { pc: 35, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99982.into(), stack_push: vec_into![3], mem_diff: None, store_diff: None }) },
VMOperation { pc: 37, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vecx![23], mem_diff: None, store_diff: None }) }, VMOperation { pc: 37, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![23], mem_diff: None, store_diff: None }) },
VMOperation { pc: 39, instruction: 240, gas_cost: 32000.into(), executed: Some(VMExecutedOperation { gas_used: 67979.into(), stack_push: vecx![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) }, VMOperation { pc: 39, instruction: 240, gas_cost: 32000.into(), executed: Some(VMExecutedOperation { gas_used: 67979.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) },
VMOperation { pc: 40, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 64752.into(), stack_push: vecx![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 40, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 64752.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 42, instruction: 85, gas_cost: 20000.into(), executed: Some(VMExecutedOperation { gas_used: 44752.into(), stack_push: vecx![], mem_diff: None, store_diff: Some(StorageDiff { location: 0.into(), value: U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap() }) }) } VMOperation { pc: 42, instruction: 85, gas_cost: 20000.into(), executed: Some(VMExecutedOperation { gas_used: 44752.into(), stack_push: vec_into![], mem_diff: None, store_diff: Some(StorageDiff { location: 0.into(), value: U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap() }) }) }
], ],
subs: vec![ subs: vec![
VMTrace { VMTrace {
parent_step: 7, parent_step: 7,
code: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], code: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85],
operations: vec![ operations: vec![
VMOperation { pc: 0, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67976.into(), stack_push: vecx![16], mem_diff: None, store_diff: None }) }, VMOperation { pc: 0, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67976.into(), stack_push: vec_into![16], mem_diff: None, store_diff: None }) },
VMOperation { pc: 2, instruction: 128, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67973.into(), stack_push: vecx![16, 16], mem_diff: None, store_diff: None }) }, VMOperation { pc: 2, instruction: 128, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67973.into(), stack_push: vec_into![16, 16], mem_diff: None, store_diff: None }) },
VMOperation { pc: 3, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67970.into(), stack_push: vecx![12], mem_diff: None, store_diff: None }) }, VMOperation { pc: 3, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67970.into(), stack_push: vec_into![12], mem_diff: None, store_diff: None }) },
VMOperation { pc: 5, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67967.into(), stack_push: vecx![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 5, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67967.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 7, instruction: 57, gas_cost: 9.into(), executed: Some(VMExecutedOperation { gas_used: 67958.into(), stack_push: vecx![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), store_diff: None }) }, VMOperation { pc: 7, instruction: 57, gas_cost: 9.into(), executed: Some(VMExecutedOperation { gas_used: 67958.into(), stack_push: vec_into![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), store_diff: None }) },
VMOperation { pc: 8, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67955.into(), stack_push: vecx![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 8, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67955.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 10, instruction: 243, gas_cost: 0.into(), executed: Some(VMExecutedOperation { gas_used: 67955.into(), stack_push: vecx![], mem_diff: None, store_diff: None }) } VMOperation { pc: 10, instruction: 243, gas_cost: 0.into(), executed: Some(VMExecutedOperation { gas_used: 67955.into(), stack_push: vec_into![], mem_diff: None, store_diff: None }) }
], ],
subs: vec![] subs: vec![]
} }
@ -737,7 +737,7 @@ mod tests {
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(code.clone());
params.value = ActionValue::Transfer(x!(100)); params.value = ActionValue::Transfer(100.into());
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100));
@ -758,7 +758,7 @@ mod tests {
depth: 0, depth: 0,
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: params.sender, from: params.sender,
value: x!(100), value: 100.into(),
gas: params.gas, gas: params.gas,
init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85],
}), }),
@ -775,13 +775,13 @@ mod tests {
parent_step: 0, parent_step: 0,
code: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], code: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85],
operations: vec![ operations: vec![
VMOperation { pc: 0, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99997.into(), stack_push: vecx![16], mem_diff: None, store_diff: None }) }, VMOperation { pc: 0, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99997.into(), stack_push: vec_into![16], mem_diff: None, store_diff: None }) },
VMOperation { pc: 2, instruction: 128, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99994.into(), stack_push: vecx![16, 16], mem_diff: None, store_diff: None }) }, VMOperation { pc: 2, instruction: 128, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99994.into(), stack_push: vec_into![16, 16], mem_diff: None, store_diff: None }) },
VMOperation { pc: 3, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99991.into(), stack_push: vecx![12], mem_diff: None, store_diff: None }) }, VMOperation { pc: 3, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99991.into(), stack_push: vec_into![12], mem_diff: None, store_diff: None }) },
VMOperation { pc: 5, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99988.into(), stack_push: vecx![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 5, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99988.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 7, instruction: 57, gas_cost: 9.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vecx![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), store_diff: None }) }, VMOperation { pc: 7, instruction: 57, gas_cost: 9.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), store_diff: None }) },
VMOperation { pc: 8, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99976.into(), stack_push: vecx![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 8, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99976.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 10, instruction: 243, gas_cost: 0.into(), executed: Some(VMExecutedOperation { gas_used: 99976.into(), stack_push: vecx![], mem_diff: None, store_diff: None }) } VMOperation { pc: 10, instruction: 243, gas_cost: 0.into(), executed: Some(VMExecutedOperation { gas_used: 99976.into(), stack_push: vec_into![], mem_diff: None, store_diff: None }) }
], ],
subs: vec![] subs: vec![]
}; };

View File

@ -321,12 +321,12 @@ mod tests {
fn get_test_env_info() -> EnvInfo { fn get_test_env_info() -> EnvInfo {
EnvInfo { EnvInfo {
number: 100, number: 100,
author: x!(0), author: 0.into(),
timestamp: 0, timestamp: 0,
difficulty: x!(0), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: x!(0), gas_used: 0.into(),
gas_limit: x!(0) gas_limit: 0.into()
} }
} }

View File

@ -22,6 +22,7 @@ use tests::helpers::*;
use devtools::*; use devtools::*;
use spec::Genesis; use spec::Genesis;
use ethjson; use ethjson;
use miner::Miner;
pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> { pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
init_log(); init_log();
@ -53,7 +54,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
let temp = RandomTempPath::new(); let temp = RandomTempPath::new();
{ {
let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); let client = Client::new(ClientConfig::default(), spec, temp.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
for b in &blockchain.blocks_rlp() { for b in &blockchain.blocks_rlp() {
if Block::is_good(&b) { if Block::is_good(&b) {
let _ = client.import_block(b.clone()); let _ = client.import_block(b.clone());

View File

@ -90,6 +90,7 @@ extern crate crossbeam;
extern crate ethjson; extern crate ethjson;
extern crate bloomchain; extern crate bloomchain;
#[macro_use] extern crate ethcore_ipc as ipc; #[macro_use] extern crate ethcore_ipc as ipc;
extern crate rayon;
#[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(test)] extern crate ethcore_devtools as devtools;
#[cfg(feature = "jit" )] extern crate evmjit; #[cfg(feature = "jit" )] extern crate evmjit;
@ -109,6 +110,7 @@ pub mod views;
pub mod pod_state; pub mod pod_state;
pub mod engine; pub mod engine;
pub mod migrations; pub mod migrations;
pub mod miner;
mod blooms; mod blooms;
mod db; mod db;

View File

@ -18,16 +18,16 @@ use rayon::prelude::*;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use util::*; use util::*;
use util::keys::store::{AccountService, AccountProvider}; use util::keys::store::{AccountProvider};
use ethcore::views::{BlockView, HeaderView}; use views::{BlockView, HeaderView};
use ethcore::client::{Executive, Executed, EnvInfo, TransactOptions, BlockChainClient, BlockID, CallAnalytics}; use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockChainClient, BlockID, CallAnalytics};
use ethcore::block::{ClosedBlock, IsBlock}; use block::{ClosedBlock, IsBlock};
use ethcore::error::*; use error::*;
use ethcore::transaction::SignedTransaction; use transaction::SignedTransaction;
use ethcore::receipt::{Receipt}; use receipt::{Receipt};
use ethcore::spec::Spec; use spec::Spec;
use ethcore::engine::Engine; use engine::Engine;
use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
/// Keeps track of transactions using priority queue and holds currently mined block. /// Keeps track of transactions using priority queue and holds currently mined block.
pub struct Miner { pub struct Miner {
@ -43,7 +43,7 @@ pub struct Miner {
extra_data: RwLock<Bytes>, extra_data: RwLock<Bytes>,
spec: Spec, spec: Spec,
accounts: RwLock<Option<Arc<AccountService>>>, // TODO: this is horrible since AccountService already contains a single RwLock field. refactor. accounts: Option<Arc<AccountProvider>>,
} }
impl Default for Miner { impl Default for Miner {
@ -57,7 +57,7 @@ impl Default for Miner {
gas_floor_target: RwLock::new(U256::zero()), gas_floor_target: RwLock::new(U256::zero()),
author: RwLock::new(Address::default()), author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()), extra_data: RwLock::new(Vec::new()),
accounts: RwLock::new(None), accounts: None,
spec: Spec::new_test(), spec: Spec::new_test(),
} }
} }
@ -75,13 +75,13 @@ impl Miner {
gas_floor_target: RwLock::new(U256::zero()), gas_floor_target: RwLock::new(U256::zero()),
author: RwLock::new(Address::default()), author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()), extra_data: RwLock::new(Vec::new()),
accounts: RwLock::new(None), accounts: None,
spec: spec, spec: spec,
}) })
} }
/// Creates new instance of miner /// Creates new instance of miner
pub fn with_accounts(force_sealing: bool, spec: Spec, accounts: Arc<AccountService>) -> Arc<Miner> { pub fn with_accounts(force_sealing: bool, spec: Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
Arc::new(Miner { Arc::new(Miner {
transaction_queue: Mutex::new(TransactionQueue::new()), transaction_queue: Mutex::new(TransactionQueue::new()),
force_sealing: force_sealing, force_sealing: force_sealing,
@ -91,7 +91,7 @@ impl Miner {
gas_floor_target: RwLock::new(U256::zero()), gas_floor_target: RwLock::new(U256::zero()),
author: RwLock::new(Address::default()), author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()), extra_data: RwLock::new(Vec::new()),
accounts: RwLock::new(Some(accounts)), accounts: Some(accounts),
spec: spec, spec: spec,
}) })
} }
@ -103,7 +103,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))] #[cfg_attr(feature="dev", allow(match_same_arms))]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn prepare_sealing(&self, chain: &BlockChainClient) { fn prepare_sealing(&self, chain: &MiningBlockChainClient) {
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();
let mut sealing_work = self.sealing_work.lock().unwrap(); let mut sealing_work = self.sealing_work.lock().unwrap();
@ -136,7 +136,7 @@ impl Miner {
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => { Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => {
trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash);
// Exit early if gas left is smaller then min_tx_gas // Exit early if gas left is smaller then min_tx_gas
let min_tx_gas: U256 = x!(21000); // TODO: figure this out properly. let min_tx_gas: U256 = 21000.into(); // TODO: figure this out properly.
if gas_limit - gas_used < min_tx_gas { if gas_limit - gas_used < min_tx_gas {
break; break;
} }
@ -176,9 +176,8 @@ impl Miner {
if !block.transactions().is_empty() { if !block.transactions().is_empty() {
trace!(target: "miner", "prepare_sealing: block has transaction - attempting internal seal."); trace!(target: "miner", "prepare_sealing: block has transaction - attempting internal seal.");
// block with transactions - see if we can seal immediately. // block with transactions - see if we can seal immediately.
let a = self.accounts.read().unwrap(); let s = self.engine().generate_seal(block.block(), match self.accounts {
let s = self.engine().generate_seal(block.block(), match *a.deref() { Some(ref x) => Some(&**x),
Some(ref x) => Some(x.deref() as &AccountProvider),
None => None, None => None,
}); });
if let Some(seal) = s { if let Some(seal) = s {
@ -205,14 +204,14 @@ impl Miner {
trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash())); trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash()));
} }
fn update_gas_limit(&self, chain: &BlockChainClient) { fn update_gas_limit(&self, chain: &MiningBlockChainClient) {
let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit(); let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit();
let mut queue = self.transaction_queue.lock().unwrap(); let mut queue = self.transaction_queue.lock().unwrap();
queue.set_gas_limit(gas_limit); queue.set_gas_limit(gas_limit);
} }
/// Returns true if we had to prepare new pending block /// Returns true if we had to prepare new pending block
fn enable_and_prepare_sealing(&self, chain: &BlockChainClient) -> bool { fn enable_and_prepare_sealing(&self, chain: &MiningBlockChainClient) -> bool {
trace!(target: "miner", "enable_and_prepare_sealing: entering"); trace!(target: "miner", "enable_and_prepare_sealing: entering");
let have_work = self.sealing_work.lock().unwrap().peek_last_ref().is_some(); let have_work = self.sealing_work.lock().unwrap().peek_last_ref().is_some();
trace!(target: "miner", "enable_and_prepare_sealing: have_work={}", have_work); trace!(target: "miner", "enable_and_prepare_sealing: have_work={}", have_work);
@ -236,7 +235,7 @@ const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5;
impl MinerService for Miner { impl MinerService for Miner {
fn clear_and_reset(&self, chain: &BlockChainClient) { fn clear_and_reset(&self, chain: &MiningBlockChainClient) {
self.transaction_queue.lock().unwrap().clear(); self.transaction_queue.lock().unwrap().clear();
self.update_sealing(chain); self.update_sealing(chain);
} }
@ -251,7 +250,7 @@ impl MinerService for Miner {
} }
} }
fn call(&self, chain: &BlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> { fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
let sealing_work = self.sealing_work.lock().unwrap(); let sealing_work = self.sealing_work.lock().unwrap();
match sealing_work.peek_last_ref() { match sealing_work.peek_last_ref() {
Some(work) => { Some(work) => {
@ -294,7 +293,7 @@ impl MinerService for Miner {
} }
} }
fn balance(&self, chain: &BlockChainClient, address: &Address) -> U256 { fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
let sealing_work = self.sealing_work.lock().unwrap(); let sealing_work = self.sealing_work.lock().unwrap();
sealing_work.peek_last_ref().map_or_else( sealing_work.peek_last_ref().map_or_else(
|| chain.latest_balance(address), || chain.latest_balance(address),
@ -302,7 +301,7 @@ impl MinerService for Miner {
) )
} }
fn storage_at(&self, chain: &BlockChainClient, address: &Address, position: &H256) -> H256 { fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 {
let sealing_work = self.sealing_work.lock().unwrap(); let sealing_work = self.sealing_work.lock().unwrap();
sealing_work.peek_last_ref().map_or_else( sealing_work.peek_last_ref().map_or_else(
|| chain.latest_storage_at(address, position), || chain.latest_storage_at(address, position),
@ -310,12 +309,12 @@ impl MinerService for Miner {
) )
} }
fn nonce(&self, chain: &BlockChainClient, address: &Address) -> U256 { fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
let sealing_work = self.sealing_work.lock().unwrap(); let sealing_work = self.sealing_work.lock().unwrap();
sealing_work.peek_last_ref().map_or_else(|| chain.latest_nonce(address), |b| b.block().fields().state.nonce(address)) sealing_work.peek_last_ref().map_or_else(|| chain.latest_nonce(address), |b| b.block().fields().state.nonce(address))
} }
fn code(&self, chain: &BlockChainClient, address: &Address) -> Option<Bytes> { fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
let sealing_work = self.sealing_work.lock().unwrap(); let sealing_work = self.sealing_work.lock().unwrap();
sealing_work.peek_last_ref().map_or_else(|| chain.code(address), |b| b.block().fields().state.code(address)) sealing_work.peek_last_ref().map_or_else(|| chain.code(address), |b| b.block().fields().state.code(address))
} }
@ -343,11 +342,11 @@ 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() * x!(110) / x!(100) *self.transaction_queue.lock().unwrap().minimal_gas_price() * 110.into() / 100.into()
} }
fn sensible_gas_limit(&self) -> U256 { fn sensible_gas_limit(&self) -> U256 {
*self.gas_floor_target.read().unwrap() / x!(5) *self.gas_floor_target.read().unwrap() / 5.into()
} }
fn transactions_limit(&self) -> usize { fn transactions_limit(&self) -> usize {
@ -382,7 +381,7 @@ impl MinerService for Miner {
.collect() .collect()
} }
fn import_own_transaction<T>(&self, chain: &BlockChainClient, transaction: SignedTransaction, fetch_account: T) -> fn import_own_transaction<T>(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, fetch_account: T) ->
Result<TransactionImportResult, Error> Result<TransactionImportResult, Error>
where T: Fn(&Address) -> AccountDetails { where T: Fn(&Address) -> AccountDetails {
let hash = transaction.hash(); let hash = transaction.hash();
@ -476,7 +475,7 @@ impl MinerService for Miner {
self.transaction_queue.lock().unwrap().last_nonce(address) self.transaction_queue.lock().unwrap().last_nonce(address)
} }
fn update_sealing(&self, chain: &BlockChainClient) { fn update_sealing(&self, chain: &MiningBlockChainClient) {
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;
let has_local_transactions = self.transaction_queue.lock().unwrap().has_local_pending_transactions(); let has_local_transactions = self.transaction_queue.lock().unwrap().has_local_pending_transactions();
@ -496,7 +495,7 @@ impl MinerService for Miner {
} }
} }
fn map_sealing_work<F, T>(&self, chain: &BlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T { fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
trace!(target: "miner", "map_sealing_work: entering"); trace!(target: "miner", "map_sealing_work: entering");
self.enable_and_prepare_sealing(chain); self.enable_and_prepare_sealing(chain);
trace!(target: "miner", "map_sealing_work: sealing prepared"); trace!(target: "miner", "map_sealing_work: sealing prepared");
@ -506,7 +505,7 @@ impl MinerService for Miner {
ret.map(f) ret.map(f)
} }
fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> { fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> {
if let Some(b) = self.sealing_work.lock().unwrap().take_used_if(|b| &b.hash() == &pow_hash) { if let Some(b) = self.sealing_work.lock().unwrap().take_used_if(|b| &b.hash() == &pow_hash) {
match chain.try_seal(b.lock(), seal) { match chain.try_seal(b.lock(), seal) {
Err(_) => { Err(_) => {
@ -529,8 +528,8 @@ impl MinerService for Miner {
} }
} }
fn chain_new_blocks(&self, chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) { fn chain_new_blocks(&self, chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec<SignedTransaction> { fn fetch_transactions(chain: &MiningBlockChainClient, hash: &H256) -> Vec<SignedTransaction> {
let block = chain let block = chain
.block(BlockID::Hash(*hash)) .block(BlockID::Hash(*hash))
// Client should send message after commit to db and inserting to chain. // Client should send message after commit to db and inserting to chain.
@ -591,13 +590,13 @@ impl MinerService for Miner {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use MinerService; use super::super::MinerService;
use super::{Miner}; use super::Miner;
use util::*; use util::*;
use ethcore::client::{TestBlockChainClient, EachBlockWith}; use client::{TestBlockChainClient, EachBlockWith};
use ethcore::block::*; use block::*;
// TODO [ToDr] To uncomment when TestBlockChainClient can actually return a ClosedBlock. // TODO [ToDr] To uncomment` when TestBlockChainClient can actually return a ClosedBlock.
#[ignore] #[ignore]
#[test] #[test]
fn should_prepare_block_to_seal() { fn should_prepare_block_to_seal() {

View File

@ -26,12 +26,10 @@
//! ```rust //! ```rust
//! extern crate ethcore_util as util; //! extern crate ethcore_util as util;
//! extern crate ethcore; //! extern crate ethcore;
//! extern crate ethminer;
//! use std::env; //! use std::env;
//! use util::network::{NetworkService, NetworkConfiguration}; //! use util::network::{NetworkService, NetworkConfiguration};
//! use ethcore::client::{Client, ClientConfig}; //! use ethcore::client::{Client, ClientConfig};
//! use ethcore::ethereum; //! use ethcore::miner::{Miner, MinerService};
//! use ethminer::{Miner, MinerService};
//! //!
//! fn main() { //! fn main() {
//! let miner: Miner = Miner::default(); //! let miner: Miner = Miner::default();
@ -43,30 +41,21 @@
//! } //! }
//! ``` //! ```
#[macro_use]
extern crate log;
#[macro_use]
extern crate ethcore_util as util;
extern crate ethcore;
extern crate env_logger;
extern crate rayon;
mod miner; mod miner;
mod external; mod external;
mod transaction_queue; mod transaction_queue;
pub use transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
pub use miner::{Miner}; pub use self::miner::{Miner};
pub use external::{ExternalMiner, ExternalMinerService}; pub use self::external::{ExternalMiner, ExternalMinerService};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use util::{H256, U256, Address, Bytes}; use util::{H256, U256, Address, Bytes};
use ethcore::client::{BlockChainClient, Executed, CallAnalytics}; use client::{MiningBlockChainClient, Executed, CallAnalytics};
use ethcore::block::ClosedBlock; use block::ClosedBlock;
use ethcore::receipt::Receipt; use receipt::Receipt;
use ethcore::error::{Error, ExecutionError}; use error::{Error, ExecutionError};
use ethcore::transaction::SignedTransaction; use transaction::SignedTransaction;
/// Miner client API /// Miner client API
pub trait MinerService : Send + Sync { pub trait MinerService : Send + Sync {
@ -110,7 +99,7 @@ pub trait MinerService : Send + Sync {
where T: Fn(&Address) -> AccountDetails, Self: Sized; where T: Fn(&Address) -> AccountDetails, Self: Sized;
/// Imports own (node owner) transaction to queue. /// Imports own (node owner) transaction to queue.
fn import_own_transaction<T>(&self, chain: &BlockChainClient, transaction: SignedTransaction, fetch_account: T) -> fn import_own_transaction<T>(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, fetch_account: T) ->
Result<TransactionImportResult, Error> Result<TransactionImportResult, Error>
where T: Fn(&Address) -> AccountDetails, Self: Sized; where T: Fn(&Address) -> AccountDetails, Self: Sized;
@ -118,20 +107,20 @@ pub trait MinerService : Send + Sync {
fn pending_transactions_hashes(&self) -> Vec<H256>; fn pending_transactions_hashes(&self) -> Vec<H256>;
/// 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); fn clear_and_reset(&self, chain: &MiningBlockChainClient);
/// 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]); fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]);
/// New chain head event. Restart mining operation. /// New chain head event. Restart mining operation.
fn update_sealing(&self, chain: &BlockChainClient); fn update_sealing(&self, chain: &MiningBlockChainClient);
/// 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>; fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error>;
/// Get the sealing work package and if `Some`, apply some transform. /// Get the sealing work package and if `Some`, apply some transform.
fn map_sealing_work<F, T>(&self, chain: &BlockChainClient, f: F) -> Option<T> fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T>
where F: FnOnce(&ClosedBlock) -> T, Self: Sized; where F: FnOnce(&ClosedBlock) -> T, Self: Sized;
/// Query pending transactions for hash. /// Query pending transactions for hash.
@ -150,25 +139,25 @@ pub trait MinerService : Send + Sync {
fn last_nonce(&self, address: &Address) -> Option<U256>; fn last_nonce(&self, address: &Address) -> Option<U256>;
/// Suggested gas price. /// Suggested gas price.
fn sensible_gas_price(&self) -> U256 { x!(20000000000u64) } fn sensible_gas_price(&self) -> U256 { 20000000000u64.into() }
/// Suggested gas limit. /// Suggested gas limit.
fn sensible_gas_limit(&self) -> U256 { x!(21000) } fn sensible_gas_limit(&self) -> U256 { 21000.into() }
/// Latest account balance in pending state. /// Latest account balance in pending state.
fn balance(&self, chain: &BlockChainClient, address: &Address) -> U256; fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256;
/// Call into contract code using pending state. /// Call into contract code using pending state.
fn call(&self, chain: &BlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>; fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>;
/// Get storage value in pending state. /// Get storage value in pending state.
fn storage_at(&self, chain: &BlockChainClient, address: &Address, position: &H256) -> H256; fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256;
/// Get account nonce in pending state. /// Get account nonce in pending state.
fn nonce(&self, chain: &BlockChainClient, address: &Address) -> U256; fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256;
/// Get contract code in pending state. /// Get contract code in pending state.
fn code(&self, chain: &BlockChainClient, address: &Address) -> Option<Bytes>; fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes>;
} }
/// Mining status /// Mining status

View File

@ -26,13 +26,12 @@
//! ```rust //! ```rust
//! extern crate ethcore_util as util; //! extern crate ethcore_util as util;
//! extern crate ethcore; //! extern crate ethcore;
//! extern crate ethminer;
//! extern crate rustc_serialize; //! extern crate rustc_serialize;
//! //!
//! use util::crypto::KeyPair; //! use util::crypto::KeyPair;
//! use util::hash::Address; //! use util::hash::Address;
//! use util::numbers::{Uint, U256}; //! use util::numbers::{Uint, U256};
//! use ethminer::{TransactionQueue, AccountDetails, TransactionOrigin}; //! use ethcore::miner::{TransactionQueue, AccountDetails, TransactionOrigin};
//! use ethcore::transaction::*; //! use ethcore::transaction::*;
//! use rustc_serialize::hex::FromHex; //! use rustc_serialize::hex::FromHex;
//! //!
@ -89,8 +88,8 @@ use std::collections::{HashMap, BTreeSet};
use util::numbers::{Uint, U256}; use util::numbers::{Uint, U256};
use util::hash::{Address, H256}; use util::hash::{Address, H256};
use util::table::*; use util::table::*;
use ethcore::transaction::*; use transaction::*;
use ethcore::error::{Error, TransactionError}; use error::{Error, TransactionError};
/// Transaction origin /// Transaction origin
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -778,8 +777,8 @@ mod test {
extern crate rustc_serialize; extern crate rustc_serialize;
use util::table::*; use util::table::*;
use util::*; use util::*;
use ethcore::transaction::*; use transaction::*;
use ethcore::error::{Error, TransactionError}; use error::{Error, TransactionError};
use super::*; use super::*;
use super::{TransactionSet, TransactionOrder, VerifiedTransaction}; use super::{TransactionSet, TransactionOrder, VerifiedTransaction};

View File

@ -152,15 +152,15 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<A
mod test { mod test {
use common::*; use common::*;
use types::account_diff::*; use types::account_diff::*;
use super::diff_pod; use super::{PodAccount, diff_pod};
#[test] #[test]
fn existence() { fn existence() {
let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]}; let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]};
assert_eq!(diff_pod(Some(&a), Some(&a)), None); assert_eq!(diff_pod(Some(&a), Some(&a)), None);
assert_eq!(diff_pod(None, Some(&a)), Some(AccountDiff{ assert_eq!(diff_pod(None, Some(&a)), Some(AccountDiff{
balance: Diff::Born(x!(69)), balance: Diff::Born(69.into()),
nonce: Diff::Born(x!(0)), nonce: Diff::Born(0.into()),
code: Diff::Born(vec![]), code: Diff::Born(vec![]),
storage: map![], storage: map![],
})); }));
@ -168,11 +168,11 @@ mod test {
#[test] #[test]
fn basic() { fn basic() {
let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]}; let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]};
let b = PodAccount{balance: x!(42), nonce: x!(1), code: vec![], storage: map![]}; let b = PodAccount{balance: 42.into(), nonce: 1.into(), code: vec![], storage: map![]};
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff { assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Changed(x!(69), x!(42)), balance: Diff::Changed(69.into(), 42.into()),
nonce: Diff::Changed(x!(0), x!(1)), nonce: Diff::Changed(0.into(), 1.into()),
code: Diff::Same, code: Diff::Same,
storage: map![], storage: map![],
})); }));
@ -180,11 +180,11 @@ mod test {
#[test] #[test]
fn code() { fn code() {
let a = PodAccount{balance: x!(0), nonce: x!(0), code: vec![], storage: map![]}; let a = PodAccount{balance: 0.into(), nonce: 0.into(), code: vec![], storage: map![]};
let b = PodAccount{balance: x!(0), nonce: x!(1), code: vec![0], storage: map![]}; let b = PodAccount{balance: 0.into(), nonce: 1.into(), code: vec![0], storage: map![]};
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff { assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Same, balance: Diff::Same,
nonce: Diff::Changed(x!(0), x!(1)), nonce: Diff::Changed(0.into(), 1.into()),
code: Diff::Changed(vec![], vec![0]), code: Diff::Changed(vec![], vec![0]),
storage: map![], storage: map![],
})); }));
@ -193,27 +193,27 @@ mod test {
#[test] #[test]
fn storage() { fn storage() {
let a = PodAccount { let a = PodAccount {
balance: x!(0), balance: 0.into(),
nonce: x!(0), nonce: 0.into(),
code: vec![], code: vec![],
storage: mapx![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0] storage: map_into![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0]
}; };
let b = PodAccount { let b = PodAccount {
balance: x!(0), balance: 0.into(),
nonce: x!(0), nonce: 0.into(),
code: vec![], code: vec![],
storage: mapx![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9] storage: map_into![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9]
}; };
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff { assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Same, balance: Diff::Same,
nonce: Diff::Same, nonce: Diff::Same,
code: Diff::Same, code: Diff::Same,
storage: map![ storage: map![
x!(2) => Diff::new(x!(2), x!(3)), 2.into() => Diff::new(2.into(), 3.into()),
x!(3) => Diff::new(x!(3), x!(0)), 3.into() => Diff::new(3.into(), 0.into()),
x!(4) => Diff::new(x!(4), x!(0)), 4.into() => Diff::new(4.into(), 0.into()),
x!(7) => Diff::new(x!(0), x!(7)), 7.into() => Diff::new(0.into(), 7.into()),
x!(9) => Diff::new(x!(0), x!(9)) 9.into() => Diff::new(0.into(), 9.into())
], ],
})); }));
} }

View File

@ -80,24 +80,24 @@ mod test {
use common::*; use common::*;
use types::state_diff::*; use types::state_diff::*;
use types::account_diff::*; use types::account_diff::*;
use pod_account::{self, PodAccount}; use pod_account::PodAccount;
use super::PodState; use super::PodState;
#[test] #[test]
fn create_delete() { fn create_delete() {
let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]);
assert_eq!(super::diff_pod(&a, &PodState::new()), StateDiff(map![ assert_eq!(super::diff_pod(&a, &PodState::new()), StateDiff(map![
x!(1) => AccountDiff{ 1.into() => AccountDiff{
balance: Diff::Died(x!(69)), balance: Diff::Died(69.into()),
nonce: Diff::Died(x!(0)), nonce: Diff::Died(0.into()),
code: Diff::Died(vec![]), code: Diff::Died(vec![]),
storage: map![], storage: map![],
} }
])); ]));
assert_eq!(super::diff_pod(&PodState::new(), &a), StateDiff(map![ assert_eq!(super::diff_pod(&PodState::new(), &a), StateDiff(map![
x!(1) => AccountDiff{ 1.into() => AccountDiff{
balance: Diff::Born(x!(69)), balance: Diff::Born(69.into()),
nonce: Diff::Born(x!(0)), nonce: Diff::Born(0.into()),
code: Diff::Born(vec![]), code: Diff::Born(vec![]),
storage: map![], storage: map![],
} }
@ -106,23 +106,23 @@ mod test {
#[test] #[test]
fn create_delete_with_unchanged() { fn create_delete_with_unchanged() {
let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]);
let b = PodState::from(map![ let b = PodState::from(map![
x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]), 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]),
x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) 2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
]); ]);
assert_eq!(super::diff_pod(&a, &b), StateDiff(map![ assert_eq!(super::diff_pod(&a, &b), StateDiff(map![
x!(2) => AccountDiff{ 2.into() => AccountDiff{
balance: Diff::Born(x!(69)), balance: Diff::Born(69.into()),
nonce: Diff::Born(x!(0)), nonce: Diff::Born(0.into()),
code: Diff::Born(vec![]), code: Diff::Born(vec![]),
storage: map![], storage: map![],
} }
])); ]));
assert_eq!(super::diff_pod(&b, &a), StateDiff(map![ assert_eq!(super::diff_pod(&b, &a), StateDiff(map![
x!(2) => AccountDiff{ 2.into() => AccountDiff{
balance: Diff::Died(x!(69)), balance: Diff::Died(69.into()),
nonce: Diff::Died(x!(0)), nonce: Diff::Died(0.into()),
code: Diff::Died(vec![]), code: Diff::Died(vec![]),
storage: map![], storage: map![],
} }
@ -132,17 +132,17 @@ mod test {
#[test] #[test]
fn change_with_unchanged() { fn change_with_unchanged() {
let a = PodState::from(map![ let a = PodState::from(map![
x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]), 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]),
x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) 2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
]); ]);
let b = PodState::from(map![ let b = PodState::from(map![
x!(1) => PodAccount::new(x!(69), x!(1), vec![], map![]), 1.into() => PodAccount::new(69.into(), 1.into(), vec![], map![]),
x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) 2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
]); ]);
assert_eq!(super::diff_pod(&a, &b), StateDiff(map![ assert_eq!(super::diff_pod(&a, &b), StateDiff(map![
x!(1) => AccountDiff{ 1.into() => AccountDiff{
balance: Diff::Same, balance: Diff::Same,
nonce: Diff::Changed(x!(0), x!(1)), nonce: Diff::Changed(0.into(), 1.into()),
code: Diff::Same, code: Diff::Same,
storage: map![], storage: map![],
} }

View File

@ -21,6 +21,7 @@ use util::panics::*;
use spec::Spec; use spec::Spec;
use error::*; use error::*;
use client::{Client, ClientConfig}; use client::{Client, ClientConfig};
use miner::Miner;
/// Message type for external and internal events /// Message type for external and internal events
#[derive(Clone)] #[derive(Clone)]
@ -54,14 +55,14 @@ pub struct ClientService {
impl ClientService { impl ClientService {
/// Start the service in a separate thread. /// Start the service in a separate thread.
pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result<ClientService, Error> { pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path, miner: Arc<Miner>) -> Result<ClientService, Error> {
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
let mut net_service = try!(NetworkService::start(net_config)); let mut net_service = try!(NetworkService::start(net_config));
panic_handler.forward_from(&net_service); panic_handler.forward_from(&net_service);
info!("Starting {}", net_service.host_info()); info!("Starting {}", net_service.host_info());
info!("Configured for {} using {:?} engine", spec.name, spec.engine.name()); info!("Configured for {} using {:?} engine", spec.name, spec.engine.name());
let client = try!(Client::new(config, spec, db_path, net_service.io().channel())); let client = try!(Client::new(config, spec, db_path, miner, net_service.io().channel()));
panic_handler.forward_from(client.deref()); panic_handler.forward_from(client.deref());
let client_io = Arc::new(ClientIoHandler { let client_io = Arc::new(ClientIoHandler {
client: client.clone() client: client.clone()
@ -141,12 +142,14 @@ mod tests {
use util::network::*; use util::network::*;
use devtools::*; use devtools::*;
use client::ClientConfig; use client::ClientConfig;
use std::sync::Arc;
use miner::Miner;
#[test] #[test]
fn it_can_be_started() { fn it_can_be_started() {
let spec = get_test_spec(); let spec = get_test_spec();
let temp_path = RandomTempPath::new(); let temp_path = RandomTempPath::new();
let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path()); let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path(), Arc::new(Miner::default()));
assert!(service.is_ok()); assert!(service.is_ok());
} }
} }

View File

@ -208,7 +208,7 @@ impl State {
/// Initialise the code of account `a` so that it is `value` for `key`. /// Initialise the code of account `a` so that it is `value` for `key`.
/// NOTE: Account should have been created with `new_contract`. /// NOTE: Account should have been created with `new_contract`.
pub fn init_code(&mut self, a: &Address, code: Bytes) { pub fn init_code(&mut self, a: &Address, code: Bytes) {
self.require_or_from(a, true, || Account::new_contract(x!(0), self.account_start_nonce), |_|{}).init_code(code); self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).init_code(code);
} }
/// Execute a given transaction. /// Execute a given transaction.
@ -389,27 +389,27 @@ fn should_apply_create_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Create, action: Action::Create,
value: x!(100), value: 100.into(),
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
value: x!(100), value: 100.into(),
gas: x!(77412), gas: 77412.into(),
init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85],
}), }),
result: trace::Res::Create(trace::CreateResult { result: trace::Res::Create(trace::CreateResult {
@ -450,27 +450,27 @@ fn should_trace_failed_create_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Create, action: Action::Create,
value: x!(100), value: 100.into(),
data: FromHex::from_hex("5b600056").unwrap(), data: FromHex::from_hex("5b600056").unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
value: x!(100), value: 100.into(),
gas: x!(78792), gas: 78792.into(),
init: vec![91, 96, 0, 86], init: vec![91, 96, 0, 86],
}), }),
result: trace::Res::FailedCreate, result: trace::Res::FailedCreate,
@ -488,29 +488,29 @@ fn should_trace_call_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("6000").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -531,28 +531,28 @@ fn should_trace_basic_call_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -573,15 +573,15 @@ fn should_trace_call_transaction_to_builtin() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = Spec::new_test().engine; let engine = Spec::new_test().engine;
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0x1)), action: Action::Call(0x1.into()),
value: x!(0), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
@ -591,10 +591,10 @@ fn should_trace_call_transaction_to_builtin() {
assert_eq!(result.trace, Some(Trace { assert_eq!(result.trace, Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!("0000000000000000000000000000000000000001"), to: "0000000000000000000000000000000000000001".into(),
value: x!(0), value: 0.into(),
gas: x!(79_000), gas: 79_000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -613,29 +613,29 @@ fn should_not_trace_subcall_transaction_to_builtin() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = Spec::new_test().engine; let engine = Spec::new_test().engine;
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(0), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(0), value: 0.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -655,30 +655,30 @@ fn should_not_trace_callcode() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = Spec::new_test().engine; let engine = Spec::new_test().engine;
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(0), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(0), value: 0.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -698,33 +698,33 @@ fn should_not_trace_delegatecall() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
info.number = 0x789b0; info.number = 0x789b0;
let engine = Spec::new_test().engine; let engine = Spec::new_test().engine;
println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(0), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(0), value: 0.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -744,29 +744,29 @@ fn should_trace_failed_call_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("5b600056").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::FailedCall, result: trace::Res::FailedCall,
@ -786,30 +786,30 @@ fn should_trace_call_with_subcall_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -819,10 +819,10 @@ fn should_trace_call_with_subcall_transaction() {
subs: vec![Trace { subs: vec![Trace {
depth: 1, depth: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!(0xa), from: 0xa.into(),
to: x!(0xb), to: 0xb.into(),
value: x!(0), value: 0.into(),
gas: x!(78934), gas: 78934.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -844,29 +844,29 @@ fn should_trace_call_with_basic_subcall_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -876,10 +876,10 @@ fn should_trace_call_with_basic_subcall_transaction() {
subs: vec![Trace { subs: vec![Trace {
depth: 1, depth: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!(0xa), from: 0xa.into(),
to: x!(0xb), to: 0xb.into(),
value: x!(69), value: 69.into(),
gas: x!(2300), gas: 2300.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult::default()), result: trace::Res::Call(trace::CallResult::default()),
@ -898,29 +898,29 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -941,30 +941,30 @@ fn should_trace_failed_subcall_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![],//600480600b6000396000f35b600056 data: vec![],//600480600b6000396000f35b600056
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&x!(0xb), FromHex::from_hex("5b600056").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -974,10 +974,10 @@ fn should_trace_failed_subcall_transaction() {
subs: vec![Trace { subs: vec![Trace {
depth: 1, depth: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!(0xa), from: 0xa.into(),
to: x!(0xb), to: 0xb.into(),
value: x!(0), value: 0.into(),
gas: x!(78934), gas: 78934.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::FailedCall, result: trace::Res::FailedCall,
@ -996,31 +996,31 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -1030,10 +1030,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
subs: vec![Trace { subs: vec![Trace {
depth: 1, depth: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!(0xa), from: 0xa.into(),
to: x!(0xb), to: 0xb.into(),
value: x!(0), value: 0.into(),
gas: x!(78934), gas: 78934.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -1043,10 +1043,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
subs: vec![Trace { subs: vec![Trace {
depth: 2, depth: 2,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!(0xb), from: 0xb.into(),
to: x!(0xc), to: 0xc.into(),
value: x!(0), value: 0.into(),
gas: x!(78868), gas: 78868.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -1069,31 +1069,31 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = x!(1_000_000); info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let t = Transaction { let t = Transaction {
nonce: x!(0), nonce: 0.into(),
gas_price: x!(0), gas_price: 0.into(),
gas: x!(100_000), gas: 100_000.into(),
action: Action::Call(x!(0xa)), action: Action::Call(0xa.into()),
value: x!(100), value: 100.into(),
data: vec![],//600480600b6000396000f35b600056 data: vec![],//600480600b6000396000f35b600056
}.sign(&"".sha3()); }.sign(&"".sha3());
state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = Some(Trace {
depth: 0, depth: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: x!(0xa), to: 0xa.into(),
value: x!(100), value: 100.into(),
gas: x!(79000), gas: 79000.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
@ -1103,21 +1103,21 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
subs: vec![Trace { subs: vec![Trace {
depth: 1, depth: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!(0xa), from: 0xa.into(),
to: x!(0xb), to: 0xb.into(),
value: x!(0), value: 0.into(),
gas: x!(78934), gas: 78934.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::FailedCall, result: trace::Res::FailedCall,
subs: vec![Trace { subs: vec![Trace {
depth: 2, depth: 2,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: x!(0xb), from: 0xb.into(),
to: x!(0xc), to: 0xc.into(),
value: x!(0), value: 0.into(),
gas: x!(78868), gas: 78868.into(),
input: vec![], input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3), gas_used: U256::from(3),
@ -1137,7 +1137,7 @@ fn code_from_database() {
let temp = RandomTempPath::new(); let temp = RandomTempPath::new();
let (root, db) = { let (root, db) = {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
state.require_or_from(&a, false, ||Account::new_contract(x!(42), x!(0)), |_|{}); state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{});
state.init_code(&a, vec![1, 2, 3]); state.init_code(&a, vec![1, 2, 3]);
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
state.commit(); state.commit();

126
ethcore/src/state_diff.rs Normal file
View File

@ -0,0 +1,126 @@
// 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/>.
use util::*;
#[cfg(test)]
use pod_state::*;
use account_diff::*;
#[derive(Debug,Clone,PartialEq,Eq)]
/// Expression for the delta between two system states. Encoded the
/// delta of every altered account.
pub struct StateDiff (BTreeMap<Address, AccountDiff>);
impl StateDiff {
#[cfg(test)]
/// Calculate and return diff between `pre` state and `post` state.
pub fn diff_pod(pre: &PodState, post: &PodState) -> StateDiff {
StateDiff(pre.get().keys().merge(post.get().keys()).filter_map(|acc| AccountDiff::diff_pod(pre.get().get(acc), post.get().get(acc)).map(|d|(acc.clone(), d))).collect())
}
}
impl fmt::Display for StateDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (add, acc) in &self.0 {
try!(write!(f, "{} {}: {}", acc.existance(), add, acc));
}
Ok(())
}
}
impl Deref for StateDiff {
type Target = BTreeMap<Address, AccountDiff>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
mod test {
use common::*;
use pod_state::*;
use account_diff::*;
use pod_account::*;
use super::*;
#[test]
fn create_delete() {
let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]);
assert_eq!(StateDiff::diff_pod(&a, &PodState::new()), StateDiff(map![
1.into() => AccountDiff{
balance: Diff::Died(69.into()),
nonce: Diff::Died(0.into()),
code: Diff::Died(vec![]),
storage: map![],
}
]));
assert_eq!(StateDiff::diff_pod(&PodState::new(), &a), StateDiff(map![
1.into() => AccountDiff{
balance: Diff::Born(69.into()),
nonce: Diff::Born(0.into()),
code: Diff::Born(vec![]),
storage: map![],
}
]));
}
#[test]
fn create_delete_with_unchanged() {
let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]);
let b = PodState::from(map![
1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]),
2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
]);
assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![
2.into() => AccountDiff{
balance: Diff::Born(69.into()),
nonce: Diff::Born(0.into()),
code: Diff::Born(vec![]),
storage: map![],
}
]));
assert_eq!(StateDiff::diff_pod(&b, &a), StateDiff(map![
2.into() => AccountDiff{
balance: Diff::Died(69.into()),
nonce: Diff::Died(0.into()),
code: Diff::Died(vec![]),
storage: map![],
}
]));
}
#[test]
fn change_with_unchanged() {
let a = PodState::from(map![
1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]),
2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
]);
let b = PodState::from(map![
1.into() => PodAccount::new(69.into(), 1.into(), vec![], map![]),
2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
]);
assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![
1.into() => AccountDiff{
balance: Diff::Same,
nonce: Diff::Changed(0.into(), 1.into()),
code: Diff::Same,
storage: map![],
}
]));
}
}

View File

@ -74,7 +74,7 @@ mod tests {
topics: vec![], topics: vec![],
data: vec![] data: vec![]
}); });
sub_state.sstore_clears_count = x!(5); sub_state.sstore_clears_count = 5.into();
sub_state.suicides.insert(address_from_u64(10u64)); sub_state.suicides.insert(address_from_u64(10u64));
let mut sub_state_2 = Substate::new(); let mut sub_state_2 = Substate::new();
@ -84,11 +84,11 @@ mod tests {
topics: vec![], topics: vec![],
data: vec![] data: vec![]
}); });
sub_state_2.sstore_clears_count = x!(7); sub_state_2.sstore_clears_count = 7.into();
sub_state.accrue(sub_state_2); sub_state.accrue(sub_state_2);
assert_eq!(sub_state.contracts_created.len(), 2); assert_eq!(sub_state.contracts_created.len(), 2);
assert_eq!(sub_state.sstore_clears_count, x!(12)); assert_eq!(sub_state.sstore_clears_count, 12.into());
assert_eq!(sub_state.suicides.len(), 1); assert_eq!(sub_state.suicides.len(), 1);
} }
} }

View File

@ -14,16 +14,17 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use client::{BlockChainClient, Client, ClientConfig, BlockID}; use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID};
use block::IsBlock; use block::IsBlock;
use tests::helpers::*; use tests::helpers::*;
use common::*; use common::*;
use devtools::*; use devtools::*;
use miner::Miner;
#[test] #[test]
fn imports_from_empty() { fn imports_from_empty() {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
client.import_verified_blocks(&IoChannel::disconnected()); client.import_verified_blocks(&IoChannel::disconnected());
client.flush_queue(); client.flush_queue();
} }
@ -41,7 +42,7 @@ fn returns_state_root_basic() {
#[test] #[test]
fn imports_good_block() { fn imports_good_block() {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let good_block = get_good_dummy_block(); let good_block = get_good_dummy_block();
if let Err(_) = client.import_block(good_block) { if let Err(_) = client.import_block(good_block) {
panic!("error importing block being good by definition"); panic!("error importing block being good by definition");
@ -56,7 +57,7 @@ fn imports_good_block() {
#[test] #[test]
fn query_none_block() { fn query_none_block() {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let non_existant = client.block_header(BlockID::Number(188)); let non_existant = client.block_header(BlockID::Number(188));
assert!(non_existant.is_none()); assert!(non_existant.is_none());
@ -136,7 +137,7 @@ fn can_mine() {
let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]);
let client = client_result.reference(); let client = client_result.reference();
let b = client.prepare_sealing(Address::default(), x!(31415926), vec![], vec![]).0.unwrap(); let b = client.prepare_sealing(Address::default(), 31415926.into(), vec![], vec![]).0.unwrap();
assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3());
assert!(client.try_seal(b.lock(), vec![]).is_ok()); assert!(client.try_seal(b.lock(), vec![]).is_ok());

View File

@ -23,6 +23,7 @@ use evm::Schedule;
use engine::*; use engine::*;
use ethereum; use ethereum;
use devtools::*; use devtools::*;
use miner::Miner;
#[cfg(feature = "json-tests")] #[cfg(feature = "json-tests")]
pub enum ChainEra { pub enum ChainEra {
@ -98,8 +99,8 @@ pub fn create_test_block(header: &Header) -> Bytes {
fn create_unverifiable_block_header(order: u32, parent_hash: H256) -> Header { fn create_unverifiable_block_header(order: u32, parent_hash: H256) -> Header {
let mut header = Header::new(); let mut header = Header::new();
header.gas_limit = x!(0); header.gas_limit = 0.into();
header.difficulty = x!(order * 100); header.difficulty = (order * 100).into();
header.timestamp = (order * 10) as u64; header.timestamp = (order * 10) as u64;
header.number = order as u64; header.number = order as u64;
header.parent_hash = parent_hash; header.parent_hash = parent_hash;
@ -139,7 +140,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans
pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>> { pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>> {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let test_spec = get_test_spec(); let test_spec = get_test_spec();
let test_engine = &test_spec.engine; let test_engine = &test_spec.engine;
let state_root = test_spec.genesis_header().state_root; let state_root = test_spec.genesis_header().state_root;
@ -205,7 +206,7 @@ pub fn push_blocks_to_client(client: &Arc<Client>, timestamp_salt: u64, starting
pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<Client>> { pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<Client>> {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
for block in &blocks { for block in &blocks {
if let Err(_) = client.import_block(block.clone()) { if let Err(_) = client.import_block(block.clone()) {
panic!("panic importing block which is well-formed"); panic!("panic importing block which is well-formed");
@ -335,7 +336,7 @@ pub fn get_bad_state_dummy_block() -> Bytes {
block_header.timestamp = 40; block_header.timestamp = 40;
block_header.number = 1; block_header.number = 1;
block_header.parent_hash = test_spec.genesis_header().hash(); block_header.parent_hash = test_spec.genesis_header().hash();
block_header.state_root = x!(0xbad); block_header.state_root = 0xbad.into();
create_test_block(&block_header) create_test_block(&block_header)
} }

View File

@ -105,10 +105,10 @@ pub struct LocalizedReceipt {
fn test_basic() { fn test_basic() {
let expected = ::rustc_serialize::hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); let expected = ::rustc_serialize::hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
let r = Receipt::new( let r = Receipt::new(
x!("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee"), "2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into(),
x!(0x40cae), 0x40cae.into(),
vec![LogEntry { vec![LogEntry {
address: x!("dcf421d093428b096ca501a7cd1a740855a7976f"), address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
topics: vec![], topics: vec![],
data: vec![0u8; 32] data: vec![0u8; 32]
}] }]

View File

@ -1,24 +0,0 @@
[package]
description = "Ethminer library"
homepage = "http://ethcore.io"
license = "GPL-3.0"
name = "ethminer"
version = "1.2.0"
authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
[build-dependencies]
rustc_version = "0.1"
[dependencies]
ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" }
log = "0.3"
env_logger = "0.3"
rustc-serialize = "0.3"
rayon = "0.3.1"
clippy = { version = "0.0.69", optional = true}
[features]
default = []
dev = ["clippy"]

View File

@ -1,25 +0,0 @@
// 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/>.
extern crate rustc_version;
use rustc_version::{version_meta, Channel};
fn main() {
if let Channel::Nightly = version_meta().channel {
println!("cargo:rustc-cfg=nightly");
}
}

View File

@ -76,13 +76,13 @@ API and Console Options:
interface. APIS is a comma-delimited list of API interface. APIS is a comma-delimited list of API
name. Possible name are web3, eth, net, personal, name. Possible name are web3, eth, net, personal,
ethcore, traces. ethcore, traces.
[default: web3,eth,net,personal,ethcore,traces]. [default: web3,eth,net,personal,traces].
--ipc-off Disable JSON-RPC over IPC service. --ipc-off Disable JSON-RPC over IPC service.
--ipc-path PATH Specify custom path for JSON-RPC over IPC service --ipc-path PATH Specify custom path for JSON-RPC over IPC service
[default: $HOME/.parity/jsonrpc.ipc]. [default: $HOME/.parity/jsonrpc.ipc].
--ipc-apis APIS Specify custom API set available via JSON-RPC over --ipc-apis APIS Specify custom API set available via JSON-RPC over
IPC [default: web3,eth,net,personal,ethcore]. IPC [default: web3,eth,net,personal,traces].
--dapps-off Disable the Dapps server (e.g. status page). --dapps-off Disable the Dapps server (e.g. status page).
--dapps-port PORT Specify the port portion of the Dapps server --dapps-port PORT Specify the port portion of the Dapps server

View File

@ -17,14 +17,9 @@
use std::sync::Arc; use std::sync::Arc;
use std::str::FromStr; use std::str::FromStr;
use std::net::SocketAddr; use std::net::SocketAddr;
use ethcore::client::Client;
use ethsync::EthSync;
use ethminer::{Miner, ExternalMiner};
use util::RotatingLogger;
use util::panics::PanicHandler; use util::panics::PanicHandler;
use util::keys::store::AccountService;
use util::network_settings::NetworkSettings;
use die::*; use die::*;
use rpc_apis;
#[cfg(feature = "dapps")] #[cfg(feature = "dapps")]
pub use ethcore_dapps::Server as WebappServer; pub use ethcore_dapps::Server as WebappServer;
@ -41,13 +36,7 @@ pub struct Configuration {
pub struct Dependencies { pub struct Dependencies {
pub panic_handler: Arc<PanicHandler>, pub panic_handler: Arc<PanicHandler>,
pub client: Arc<Client>, pub apis: Arc<rpc_apis::Dependencies>,
pub sync: Arc<EthSync>,
pub secret_store: Arc<AccountService>,
pub miner: Arc<Miner>,
pub external_miner: Arc<ExternalMiner>,
pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>,
} }
pub fn new(configuration: Configuration, deps: Dependencies) -> Option<WebappServer> { pub fn new(configuration: Configuration, deps: Dependencies) -> Option<WebappServer> {
@ -92,17 +81,10 @@ pub fn setup_dapps_server(
url: &SocketAddr, url: &SocketAddr,
auth: Option<(String, String)> auth: Option<(String, String)>
) -> WebappServer { ) -> WebappServer {
use ethcore_rpc::v1::*;
use ethcore_dapps as dapps; use ethcore_dapps as dapps;
let server = dapps::ServerBuilder::new(); let server = dapps::ServerBuilder::new();
server.add_delegate(Web3Client::new().to_delegate()); let server = rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::UnsafeContext);
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate());
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate());
server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate());
let start_result = match auth { let start_result = match auth {
None => { None => {
server.start_unsecure_http(url) server.start_unsecure_http(url)

View File

@ -27,7 +27,6 @@ extern crate rustc_serialize;
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate ethcore; extern crate ethcore;
extern crate ethsync; extern crate ethsync;
extern crate ethminer;
#[macro_use] #[macro_use]
extern crate log as rlog; extern crate log as rlog;
extern crate env_logger; extern crate env_logger;
@ -67,6 +66,7 @@ mod cli;
mod configuration; mod configuration;
mod migration; mod migration;
mod signer; mod signer;
mod rpc_apis;
use std::io::{Write, Read, BufReader, BufRead}; use std::io::{Write, Read, BufReader, BufRead};
use std::ops::Deref; use std::ops::Deref;
@ -85,7 +85,7 @@ use ethcore::error::{Error, ImportError};
use ethcore::service::ClientService; use ethcore::service::ClientService;
use ethcore::spec::Spec; use ethcore::spec::Spec;
use ethsync::EthSync; use ethsync::EthSync;
use ethminer::{Miner, MinerService, ExternalMiner}; use ethcore::miner::{Miner, MinerService, ExternalMiner};
use daemonize::Daemonize; use daemonize::Daemonize;
use migration::migrate; use migration::migrate;
use informant::Informant; use informant::Informant;
@ -173,14 +173,6 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
// Secret Store // Secret Store
let account_service = Arc::new(conf.account_service()); let account_service = Arc::new(conf.account_service());
// Build client
let mut service = ClientService::start(
client_config, spec, net_settings, Path::new(&conf.path())
).unwrap_or_else(|e| die_with_error("Client", e));
panic_handler.forward_from(&service);
let client = service.client();
// Miner // Miner
let miner = Miner::with_accounts(conf.args.flag_force_sealing, conf.spec(), account_service.clone()); let miner = Miner::with_accounts(conf.args.flag_force_sealing, conf.spec(), account_service.clone());
miner.set_author(conf.author()); miner.set_author(conf.author());
@ -189,14 +181,23 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
miner.set_minimal_gas_price(conf.gas_price()); miner.set_minimal_gas_price(conf.gas_price());
miner.set_transactions_limit(conf.args.flag_tx_limit); miner.set_transactions_limit(conf.args.flag_tx_limit);
// Build client
let mut service = ClientService::start(
client_config, spec, net_settings, Path::new(&conf.path()), miner.clone()
).unwrap_or_else(|e| die_with_error("Client", e));
panic_handler.forward_from(&service);
let client = service.client();
let external_miner = Arc::new(ExternalMiner::default()); let external_miner = Arc::new(ExternalMiner::default());
let network_settings = Arc::new(conf.network_settings()); let network_settings = Arc::new(conf.network_settings());
// Sync // Sync
let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); let sync = EthSync::register(service.network(), sync_config, client.clone());
let dependencies = Arc::new(rpc::Dependencies { let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies {
panic_handler: panic_handler.clone(), signer_enabled: conf.args.flag_signer,
signer_queue: Arc::new(rpc_apis::ConfirmationsQueue::default()),
client: client.clone(), client: client.clone(),
sync: sync.clone(), sync: sync.clone(),
secret_store: account_service.clone(), secret_store: account_service.clone(),
@ -206,6 +207,11 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
settings: network_settings.clone(), settings: network_settings.clone(),
}); });
let dependencies = rpc::Dependencies {
panic_handler: panic_handler.clone(),
apis: deps_for_rpc_apis.clone(),
};
// Setup http rpc // Setup http rpc
let rpc_server = rpc::new_http(rpc::HttpConfiguration { let rpc_server = rpc::new_http(rpc::HttpConfiguration {
enabled: network_settings.rpc_enabled, enabled: network_settings.rpc_enabled,
@ -227,26 +233,16 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
pass: conf.args.flag_dapps_pass.clone(), pass: conf.args.flag_dapps_pass.clone(),
}, dapps::Dependencies { }, dapps::Dependencies {
panic_handler: panic_handler.clone(), panic_handler: panic_handler.clone(),
client: client.clone(), apis: deps_for_rpc_apis.clone(),
sync: sync.clone(),
secret_store: account_service.clone(),
miner: miner.clone(),
external_miner: external_miner.clone(),
logger: logger.clone(),
settings: network_settings.clone(),
}); });
// Set up a signer // Set up a signer
let signer_server = signer::start(signer::Configuration { let signer_server = signer::start(signer::Configuration {
enabled: conf.args.flag_signer, enabled: deps_for_rpc_apis.signer_enabled,
port: conf.args.flag_signer_port, port: conf.args.flag_signer_port,
}, signer::Dependencies { }, signer::Dependencies {
panic_handler: panic_handler.clone(), panic_handler: panic_handler.clone(),
client: client.clone(), apis: deps_for_rpc_apis.clone(),
sync: sync.clone(),
secret_store: account_service.clone(),
miner: miner.clone(),
external_miner: external_miner.clone(),
}); });
// Register IO handler // Register IO handler
@ -295,7 +291,7 @@ fn execute_export(conf: Configuration) {
// Build client // Build client
let service = ClientService::start( let service = ClientService::start(
client_config, spec, net_settings, Path::new(&conf.path()) client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()),
).unwrap_or_else(|e| die_with_error("Client", e)); ).unwrap_or_else(|e| die_with_error("Client", e));
panic_handler.forward_from(&service); panic_handler.forward_from(&service);
@ -366,7 +362,7 @@ fn execute_import(conf: Configuration) {
// Build client // Build client
let service = ClientService::start( let service = ClientService::start(
client_config, spec, net_settings, Path::new(&conf.path()) client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()),
).unwrap_or_else(|e| die_with_error("Client", e)); ).unwrap_or_else(|e| die_with_error("Client", e));
panic_handler.forward_from(&service); panic_handler.forward_from(&service);

View File

@ -15,19 +15,13 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeMap;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use std::net::SocketAddr; use std::net::SocketAddr;
use ethcore::client::Client;
use ethsync::EthSync;
use ethminer::{Miner, ExternalMiner};
use util::RotatingLogger;
use util::panics::PanicHandler; use util::panics::PanicHandler;
use util::keys::store::AccountService;
use util::network_settings::NetworkSettings;
use die::*; use die::*;
use jsonipc; use jsonipc;
use rpc_apis;
#[cfg(feature = "rpc")] #[cfg(feature = "rpc")]
pub use ethcore_rpc::Server as RpcServer; pub use ethcore_rpc::Server as RpcServer;
@ -52,16 +46,10 @@ pub struct IpcConfiguration {
pub struct Dependencies { pub struct Dependencies {
pub panic_handler: Arc<PanicHandler>, pub panic_handler: Arc<PanicHandler>,
pub client: Arc<Client>, pub apis: Arc<rpc_apis::Dependencies>,
pub sync: Arc<EthSync>,
pub secret_store: Arc<AccountService>,
pub miner: Arc<Miner>,
pub external_miner: Arc<ExternalMiner>,
pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>,
} }
pub fn new_http(conf: HttpConfiguration, deps: &Arc<Dependencies>) -> Option<RpcServer> { pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Option<RpcServer> {
if !conf.enabled { if !conf.enabled {
return None; return None;
} }
@ -78,58 +66,23 @@ pub fn new_http(conf: HttpConfiguration, deps: &Arc<Dependencies>) -> Option<Rpc
Some(setup_http_rpc_server(deps, &addr, conf.cors, apis)) Some(setup_http_rpc_server(deps, &addr, conf.cors, apis))
} }
pub fn new_ipc(conf: IpcConfiguration, deps: &Arc<Dependencies>) -> Option<jsonipc::Server> { pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Option<jsonipc::Server> {
if !conf.enabled { return None; } if !conf.enabled { return None; }
let apis = conf.apis.split(',').collect(); let apis = conf.apis.split(',').collect();
Some(setup_ipc_rpc_server(deps, &conf.socket_addr, apis)) Some(setup_ipc_rpc_server(deps, &conf.socket_addr, apis))
} }
fn setup_rpc_server(apis: Vec<&str>, deps: &Arc<Dependencies>) -> Server { fn setup_rpc_server(apis: Vec<&str>, deps: &Dependencies) -> Server {
use ethcore_rpc::v1::*; let apis = rpc_apis::from_str(apis);
let server = Server::new(); let server = Server::new();
let mut modules = BTreeMap::new(); rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::List(apis))
for api in apis.into_iter() {
match api {
"web3" => {
modules.insert("web3".to_owned(), "1.0".to_owned());
server.add_delegate(Web3Client::new().to_delegate());
},
"net" => {
modules.insert("net".to_owned(), "1.0".to_owned());
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
},
"eth" => {
modules.insert("eth".to_owned(), "1.0".to_owned());
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate());
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
},
"personal" => {
modules.insert("personal".to_owned(), "1.0".to_owned());
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate())
},
"ethcore" => {
modules.insert("ethcore".to_owned(), "1.0".to_owned());
server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate())
},
"traces" => {
modules.insert("traces".to_owned(), "1.0".to_owned());
server.add_delegate(TracesClient::new(&deps.client).to_delegate())
},
_ => {
die!("{}: Invalid API name to be enabled.", api);
},
}
}
server.add_delegate(RpcClient::new(modules).to_delegate());
server
} }
#[cfg(not(feature = "rpc"))] #[cfg(not(feature = "rpc"))]
pub fn setup_http_rpc_server( pub fn setup_http_rpc_server(
_deps: Dependencies, _deps: &Dependencies,
_url: &SocketAddr, _url: &SocketAddr,
_cors_domain: Option<String>, _cors_domain: Vec<String>,
_apis: Vec<&str>, _apis: Vec<&str>,
) -> ! { ) -> ! {
die!("Your Parity version has been compiled without JSON-RPC support.") die!("Your Parity version has been compiled without JSON-RPC support.")
@ -137,27 +90,31 @@ pub fn setup_http_rpc_server(
#[cfg(feature = "rpc")] #[cfg(feature = "rpc")]
pub fn setup_http_rpc_server( pub fn setup_http_rpc_server(
dependencies: &Arc<Dependencies>, dependencies: &Dependencies,
url: &SocketAddr, url: &SocketAddr,
cors_domains: Vec<String>, cors_domains: Vec<String>,
apis: Vec<&str>, apis: Vec<&str>,
) -> RpcServer { ) -> RpcServer {
let server = setup_rpc_server(apis, dependencies); let server = setup_rpc_server(apis, dependencies);
let start_result = server.start_http(url, cors_domains); let start_result = server.start_http(url, cors_domains);
let deps = dependencies.clone(); let ph = dependencies.panic_handler.clone();
match start_result { match start_result {
Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err), Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err),
Err(e) => die!("RPC: {:?}", e), Err(e) => die!("RPC: {:?}", e),
Ok(server) => { Ok(server) => {
server.set_panic_handler(move || { server.set_panic_handler(move || {
deps.panic_handler.notify_all("Panic in RPC thread.".to_owned()); ph.notify_all("Panic in RPC thread.".to_owned());
}); });
server server
}, },
} }
} }
#[cfg(not(feature = "rpc"))]
pub fn setup_ipc_rpc_server(dependencies: &Arc<Dependencies>, addr: &str, apis: Vec<&str>) -> jsonipc::Server { pub fn setup_ipc_rpc_server(_dependencies: &Dependencies, _addr: &str, _apis: Vec<&str>) -> ! {
die!("Your Parity version has been compiled without JSON-RPC support.")
}
#[cfg(feature = "rpc")]
pub fn setup_ipc_rpc_server(dependencies: &Dependencies, addr: &str, apis: Vec<&str>) -> jsonipc::Server {
let server = setup_rpc_server(apis, dependencies); let server = setup_rpc_server(apis, dependencies);
match server.start_ipc(addr) { match server.start_ipc(addr) {
Err(jsonipc::Error::Io(io_error)) => die_with_io_error("RPC", io_error), Err(jsonipc::Error::Io(io_error)) => die_with_io_error("RPC", io_error),

168
parity/rpc_apis.rs Normal file
View File

@ -0,0 +1,168 @@
// 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/>.
use std::collections::BTreeMap;
use std::str::FromStr;
use std::sync::Arc;
use die::*;
use ethsync::EthSync;
use ethcore::miner::{Miner, ExternalMiner};
use ethcore::client::Client;
use util::RotatingLogger;
use util::keys::store::AccountService;
use util::network_settings::NetworkSettings;
#[cfg(feature="rpc")]
pub use ethcore_rpc::ConfirmationsQueue;
#[cfg(not(feature="rpc"))]
#[derive(Default)]
pub struct ConfirmationsQueue;
#[cfg(feature="rpc")]
use ethcore_rpc::Extendable;
pub enum Api {
Web3,
Net,
Eth,
Personal,
Ethcore,
Traces,
Rpc,
}
pub enum ApiError {
UnknownApi(String)
}
pub enum ApiSet {
SafeContext,
UnsafeContext,
List(Vec<Api>),
}
impl FromStr for Api {
type Err = ApiError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::Api::*;
match s {
"web3" => Ok(Web3),
"net" => Ok(Net),
"eth" => Ok(Eth),
"personal" => Ok(Personal),
"ethcore" => Ok(Ethcore),
"traces" => Ok(Traces),
"rpc" => Ok(Rpc),
e => Err(ApiError::UnknownApi(e.into())),
}
}
}
pub struct Dependencies {
pub signer_enabled: bool,
pub signer_queue: Arc<ConfirmationsQueue>,
pub client: Arc<Client>,
pub sync: Arc<EthSync>,
pub secret_store: Arc<AccountService>,
pub miner: Arc<Miner>,
pub external_miner: Arc<ExternalMiner>,
pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>,
}
fn to_modules(apis: &[Api]) -> BTreeMap<String, String> {
let mut modules = BTreeMap::new();
for api in apis {
let (name, version) = match *api {
Api::Web3 => ("web3", "1.0"),
Api::Net => ("net", "1.0"),
Api::Eth => ("eth", "1.0"),
Api::Personal => ("personal", "1.0"),
Api::Ethcore => ("ethcore", "1.0"),
Api::Traces => ("traces", "1.0"),
Api::Rpc => ("rpc", "1.0"),
};
modules.insert(name.into(), version.into());
}
modules
}
pub fn from_str(apis: Vec<&str>) -> Vec<Api> {
apis.into_iter()
.map(Api::from_str)
.collect::<Result<Vec<Api>, ApiError>>()
.unwrap_or_else(|e| match e {
ApiError::UnknownApi(s) => die!("Unknown RPC API specified: {}", s),
})
}
fn list_apis(apis: ApiSet, signer_enabled: bool) -> Vec<Api> {
match apis {
ApiSet::List(apis) => apis,
ApiSet::UnsafeContext if signer_enabled => {
vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc]
}
_ => {
vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Ethcore, Api::Traces, Api::Rpc]
}
}
}
pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet) -> T {
use ethcore_rpc::v1::*;
let apis = list_apis(apis, deps.signer_enabled);
for api in &apis {
match *api {
Api::Web3 => {
server.add_delegate(Web3Client::new().to_delegate());
},
Api::Net => {
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
},
Api::Eth => {
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate());
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
if deps.signer_enabled {
server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue).to_delegate());
} else {
server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate());
}
},
Api::Personal => {
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate());
if deps.signer_enabled {
server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_queue).to_delegate());
}
},
Api::Ethcore => {
server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate())
},
Api::Traces => {
server.add_delegate(TracesClient::new(&deps.client).to_delegate())
},
Api::Rpc => {
let modules = to_modules(&apis);
server.add_delegate(RpcClient::new(modules).to_delegate());
}
}
}
server
}

View File

@ -15,12 +15,9 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc; use std::sync::Arc;
use ethcore::client::Client;
use ethsync::EthSync;
use ethminer::{Miner, ExternalMiner};
use util::keys::store::AccountService;
use util::panics::{PanicHandler, ForwardPanic}; use util::panics::{PanicHandler, ForwardPanic};
use die::*; use die::*;
use rpc_apis;
#[cfg(feature = "ethcore-signer")] #[cfg(feature = "ethcore-signer")]
use ethcore_signer as signer; use ethcore_signer as signer;
@ -36,11 +33,7 @@ pub struct Configuration {
pub struct Dependencies { pub struct Dependencies {
pub panic_handler: Arc<PanicHandler>, pub panic_handler: Arc<PanicHandler>,
pub client: Arc<Client>, pub apis: Arc<rpc_apis::Dependencies>,
pub sync: Arc<EthSync>,
pub secret_store: Arc<AccountService>,
pub miner: Arc<Miner>,
pub external_miner: Arc<ExternalMiner>,
} }
pub fn start(conf: Configuration, deps: Dependencies) -> Option<SignerServer> { pub fn start(conf: Configuration, deps: Dependencies) -> Option<SignerServer> {
@ -58,13 +51,8 @@ fn do_start(conf: Configuration, deps: Dependencies) -> SignerServer {
}); });
let start_result = { let start_result = {
use ethcore_rpc::v1::*;
let server = signer::ServerBuilder::new(); let server = signer::ServerBuilder::new();
server.add_delegate(Web3Client::new().to_delegate()); let server = rpc_apis::setup_rpc(server, deps.apis, rpc_apis::ApiSet::SafeContext);
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate());
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate());
server.start(addr) server.start(addr)
}; };

View File

@ -18,7 +18,6 @@ ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" } ethcore = { path = "../ethcore" }
ethash = { path = "../ethash" } ethash = { path = "../ethash" }
ethsync = { path = "../sync" } ethsync = { path = "../sync" }
ethminer = { path = "../miner" }
ethjson = { path = "../json" } ethjson = { path = "../json" }
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
rustc-serialize = "0.3" rustc-serialize = "0.3"
@ -34,4 +33,4 @@ syntex = "^0.32.0"
[features] [features]
default = ["serde_codegen"] default = ["serde_codegen"]
nightly = ["serde_macros"] nightly = ["serde_macros"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethminer/dev"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev"]

View File

@ -30,7 +30,6 @@ extern crate jsonrpc_http_server;
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate ethcore; extern crate ethcore;
extern crate ethsync; extern crate ethsync;
extern crate ethminer;
extern crate transient_hashmap; extern crate transient_hashmap;
extern crate json_ipc_server as ipc; extern crate json_ipc_server as ipc;
@ -45,12 +44,26 @@ use self::jsonrpc_core::{IoHandler, IoDelegate};
pub use jsonrpc_http_server::{Server, RpcServerError}; pub use jsonrpc_http_server::{Server, RpcServerError};
pub mod v1; pub mod v1;
pub use v1::{SigningQueue, ConfirmationsQueue};
/// An object that can be extended with `IoDelegates`
pub trait Extendable {
/// Add `Delegate` to this object.
fn add_delegate<D: Send + Sync + 'static>(&self, delegate: IoDelegate<D>);
}
/// Http server. /// Http server.
pub struct RpcServer { pub struct RpcServer {
handler: Arc<jsonrpc_core::io::IoHandler>, handler: Arc<jsonrpc_core::io::IoHandler>,
} }
impl Extendable for RpcServer {
/// Add io delegate.
fn add_delegate<D: Send + Sync + 'static>(&self, delegate: IoDelegate<D>) {
self.handler.add_delegate(delegate);
}
}
impl RpcServer { impl RpcServer {
/// Construct new http server object. /// Construct new http server object.
pub fn new() -> RpcServer { pub fn new() -> RpcServer {
@ -59,11 +72,6 @@ impl RpcServer {
} }
} }
/// Add io delegate.
pub fn add_delegate<D>(&self, delegate: IoDelegate<D>) where D: Send + Sync + 'static {
self.handler.add_delegate(delegate);
}
/// Start http server asynchronously and returns result with `Server` handle on success or an error. /// Start http server asynchronously and returns result with `Server` handle on success or an error.
pub fn start_http(&self, addr: &SocketAddr, cors_domains: Vec<String>) -> Result<Server, RpcServerError> { pub fn start_http(&self, addr: &SocketAddr, cors_domains: Vec<String>) -> Result<Server, RpcServerError> {
let cors_domains = cors_domains.into_iter() let cors_domains = cors_domains.into_iter()

View File

@ -16,6 +16,8 @@
mod poll_manager; mod poll_manager;
mod poll_filter; mod poll_filter;
mod signing_queue;
pub use self::poll_manager::PollManager; pub use self::poll_manager::PollManager;
pub use self::poll_filter::PollFilter; pub use self::poll_filter::PollFilter;
pub use self::signing_queue::{ConfirmationsQueue, SigningQueue};

View File

@ -0,0 +1,108 @@
// 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/>.
use std::sync::Mutex;
use std::collections::HashMap;
use v1::types::{TransactionRequest, TransactionConfirmation};
use util::U256;
/// A queue of transactions awaiting to be confirmed and signed.
pub trait SigningQueue: Send + Sync {
/// Add new request to the queue.
fn add_request(&self, transaction: TransactionRequest) -> U256;
/// Remove request from the queue.
fn remove_request(&self, id: U256) -> Option<TransactionConfirmation>;
/// Return copy of all the requests in the queue.
fn requests(&self) -> Vec<TransactionConfirmation>;
}
/// Queue for all unconfirmed transactions.
pub struct ConfirmationsQueue {
id: Mutex<U256>,
queue: Mutex<HashMap<U256, TransactionConfirmation>>,
}
impl Default for ConfirmationsQueue {
fn default() -> Self {
ConfirmationsQueue {
id: Mutex::new(U256::from(0)),
queue: Mutex::new(HashMap::new()),
}
}
}
impl SigningQueue for ConfirmationsQueue {
fn add_request(&self, transaction: TransactionRequest) -> U256 {
// Increment id
let id = {
let mut last_id = self.id.lock().unwrap();
*last_id = *last_id + U256::from(1);
*last_id
};
let mut queue = self.queue.lock().unwrap();
queue.insert(id, TransactionConfirmation {
id: id,
transaction: transaction,
});
id
}
fn remove_request(&self, id: U256) -> Option<TransactionConfirmation> {
self.queue.lock().unwrap().remove(&id)
}
fn requests(&self) -> Vec<TransactionConfirmation> {
let queue = self.queue.lock().unwrap();
queue.values().cloned().collect()
}
}
#[cfg(test)]
mod test {
use util::hash::Address;
use util::numbers::U256;
use v1::types::TransactionRequest;
use super::*;
#[test]
fn should_work_for_hashset() {
// given
let queue = ConfirmationsQueue::default();
let request = TransactionRequest {
from: Address::from(1),
to: Some(Address::from(2)),
gas_price: None,
gas: None,
value: Some(U256::from(10_000_000)),
data: None,
nonce: None,
};
// when
queue.add_request(request.clone());
let all = queue.requests();
// then
assert_eq!(all.len(), 1);
let el = all.get(0).unwrap();
assert_eq!(el.id, U256::from(1));
assert_eq!(el.transaction, request);
}
}

View File

@ -18,17 +18,16 @@
extern crate ethash; extern crate ethash;
use std::collections::HashSet;
use std::sync::{Arc, Weak, Mutex}; use std::sync::{Arc, Weak, Mutex};
use std::ops::Deref; use std::ops::Deref;
use ethsync::{SyncProvider, SyncState}; use ethsync::{SyncProvider, SyncState};
use ethminer::{MinerService, ExternalMinerService}; use ethcore::miner::{MinerService, ExternalMinerService};
use jsonrpc_core::*; use jsonrpc_core::*;
use util::numbers::*; use util::numbers::*;
use util::sha3::*; use util::sha3::*;
use util::rlp::{encode, decode, UntrustedRlp, View}; use util::rlp::{encode, decode, UntrustedRlp, View};
use util::keys::store::AccountProvider; use util::keys::store::AccountProvider;
use ethcore::client::{BlockChainClient, BlockID, TransactionID, UncleID}; use ethcore::client::{MiningBlockChainClient, BlockID, TransactionID, UncleID};
use ethcore::block::IsBlock; use ethcore::block::IsBlock;
use ethcore::views::*; use ethcore::views::*;
use ethcore::ethereum::Ethash; use ethcore::ethereum::Ethash;
@ -36,15 +35,14 @@ use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Act
use ethcore::log_entry::LogEntry; use ethcore::log_entry::LogEntry;
use ethcore::filter::Filter as EthcoreFilter; use ethcore::filter::Filter as EthcoreFilter;
use self::ethash::SeedHashCompute; use self::ethash::SeedHashCompute;
use v1::traits::{Eth, EthFilter}; use v1::traits::Eth;
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, OptionalValue, Index, Filter, Log, Receipt};
use v1::helpers::{PollFilter, PollManager}; use v1::impls::dispatch_transaction;
use v1::impls::{dispatch_transaction, sign_and_dispatch};
use serde; use serde;
/// Eth rpc implementation. /// Eth rpc implementation.
pub struct EthClient<C, S, A, M, EM> where pub struct EthClient<C, S, A, M, EM> where
C: BlockChainClient, C: MiningBlockChainClient,
S: SyncProvider, S: SyncProvider,
A: AccountProvider, A: AccountProvider,
M: MinerService, M: MinerService,
@ -59,7 +57,7 @@ pub struct EthClient<C, S, A, M, EM> where
} }
impl<C, S, A, M, EM> EthClient<C, S, A, M, EM> where impl<C, S, A, M, EM> EthClient<C, S, A, M, EM> where
C: BlockChainClient, C: MiningBlockChainClient,
S: SyncProvider, S: SyncProvider,
A: AccountProvider, A: AccountProvider,
M: MinerService, M: MinerService,
@ -170,6 +168,25 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM> where
} }
} }
pub fn pending_logs<M>(miner: &M, filter: &EthcoreFilter) -> Vec<Log> where M: MinerService {
let receipts = miner.pending_receipts();
let pending_logs = receipts.into_iter()
.flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::<Vec<(H256, LogEntry)>>())
.collect::<Vec<(H256, LogEntry)>>();
let result = pending_logs.into_iter()
.filter(|pair| filter.matches(&pair.1))
.map(|pair| {
let mut log = Log::from(pair.1);
log.transaction_hash = Some(pair.0);
log
})
.collect();
result
}
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6. const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
fn params_len(params: &Params) -> usize { fn params_len(params: &Params) -> usize {
@ -193,25 +210,6 @@ fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNum
} }
} }
fn pending_logs<M>(miner: &M, filter: &EthcoreFilter) -> Vec<Log> where M: MinerService {
let receipts = miner.pending_receipts();
let pending_logs = receipts.into_iter()
.flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::<Vec<(H256, LogEntry)>>())
.collect::<Vec<(H256, LogEntry)>>();
let result = pending_logs.into_iter()
.filter(|pair| filter.matches(&pair.1))
.map(|pair| {
let mut log = Log::from(pair.1);
log.transaction_hash = Some(pair.0);
log
})
.collect();
result
}
// must be in range [-32099, -32000] // must be in range [-32099, -32000]
const UNSUPPORTED_REQUEST_CODE: i64 = -32000; const UNSUPPORTED_REQUEST_CODE: i64 = -32000;
@ -224,7 +222,7 @@ fn make_unsupported_err() -> Error {
} }
impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
C: BlockChainClient + 'static, C: MiningBlockChainClient + 'static,
S: SyncProvider + 'static, S: SyncProvider + 'static,
A: AccountProvider + 'static, A: AccountProvider + 'static,
M: MinerService + 'static, M: MinerService + 'static,
@ -496,23 +494,6 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
}) })
} }
fn sign(&self, params: Params) -> Result<Value, Error> {
from_params::<(Address, H256)>(params).and_then(|(addr, msg)| {
to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero()))
})
}
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(TransactionRequest, )>(params)
.and_then(|(request, )| {
let accounts = take_weak!(self.accounts);
match accounts.account_secret(&request.from) {
Ok(secret) => sign_and_dispatch(&self.client, &self.miner, request, secret),
Err(_) => to_value(&H256::zero())
}
})
}
fn send_raw_transaction(&self, params: Params) -> Result<Value, Error> { fn send_raw_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(Bytes, )>(params) from_params::<(Bytes, )>(params)
.and_then(|(raw_transaction, )| { .and_then(|(raw_transaction, )| {
@ -563,186 +544,3 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
rpc_unimplemented!() rpc_unimplemented!()
} }
} }
/// Eth filter rpc implementation.
pub struct EthFilterClient<C, M> where
C: BlockChainClient,
M: MinerService {
client: Weak<C>,
miner: Weak<M>,
polls: Mutex<PollManager<PollFilter>>,
}
impl<C, M> EthFilterClient<C, M> where
C: BlockChainClient,
M: MinerService {
/// Creates new Eth filter client.
pub fn new(client: &Arc<C>, miner: &Arc<M>) -> Self {
EthFilterClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
polls: Mutex::new(PollManager::new()),
}
}
}
impl<C, M> EthFilter for EthFilterClient<C, M> where
C: BlockChainClient + 'static,
M: MinerService + 'static {
fn new_filter(&self, params: Params) -> Result<Value, Error> {
from_params::<(Filter,)>(params)
.and_then(|(filter,)| {
let mut polls = self.polls.lock().unwrap();
let block_number = take_weak!(self.client).chain_info().best_block_number;
let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter));
to_value(&U256::from(id))
})
}
fn new_block_filter(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => {
let mut polls = self.polls.lock().unwrap();
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
to_value(&U256::from(id))
},
_ => Err(Error::invalid_params())
}
}
fn new_pending_transaction_filter(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => {
let mut polls = self.polls.lock().unwrap();
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes();
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
to_value(&U256::from(id))
},
_ => Err(Error::invalid_params())
}
}
fn filter_changes(&self, params: Params) -> Result<Value, Error> {
let client = take_weak!(self.client);
from_params::<(Index,)>(params)
.and_then(|(index,)| {
let mut polls = self.polls.lock().unwrap();
match polls.poll_mut(&index.value()) {
None => Ok(Value::Array(vec![] as Vec<Value>)),
Some(filter) => match *filter {
PollFilter::Block(ref mut block_number) => {
// + 1, cause we want to return hashes including current block hash.
let current_number = client.chain_info().best_block_number + 1;
let hashes = (*block_number..current_number).into_iter()
.map(BlockID::Number)
.filter_map(|id| client.block_hash(id))
.collect::<Vec<H256>>();
*block_number = current_number;
to_value(&hashes)
},
PollFilter::PendingTransaction(ref mut previous_hashes) => {
// get hashes of pending transactions
let current_hashes = take_weak!(self.miner).pending_transactions_hashes();
let new_hashes =
{
let previous_hashes_set = previous_hashes.iter().collect::<HashSet<_>>();
// find all new hashes
current_hashes
.iter()
.filter(|hash| !previous_hashes_set.contains(hash))
.cloned()
.collect::<Vec<H256>>()
};
// save all hashes of pending transactions
*previous_hashes = current_hashes;
// return new hashes
to_value(&new_hashes)
},
PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => {
// retrive the current block number
let current_number = client.chain_info().best_block_number;
// check if we need to check pending hashes
let include_pending = filter.to_block == Some(BlockNumber::Pending);
// build appropriate filter
let mut filter: EthcoreFilter = filter.clone().into();
filter.from_block = BlockID::Number(*block_number);
filter.to_block = BlockID::Latest;
// retrieve logs in range from_block..min(BlockID::Latest..to_block)
let mut logs = client.logs(filter.clone())
.into_iter()
.map(From::from)
.collect::<Vec<Log>>();
// additionally retrieve pending logs
if include_pending {
let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter);
// remove logs about which client was already notified about
let new_pending_logs: Vec<_> = pending_logs.iter()
.filter(|p| !previous_logs.contains(p))
.cloned()
.collect();
// save all logs retrieved by client
*previous_logs = pending_logs.into_iter().collect();
// append logs array with new pending logs
logs.extend(new_pending_logs);
}
// save current block number as next from block number
*block_number = current_number;
to_value(&logs)
}
}
}
})
}
fn filter_logs(&self, params: Params) -> Result<Value, Error> {
from_params::<(Index,)>(params)
.and_then(|(index,)| {
let mut polls = self.polls.lock().unwrap();
match polls.poll(&index.value()) {
Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => {
let include_pending = filter.to_block == Some(BlockNumber::Pending);
let filter: EthcoreFilter = filter.clone().into();
let mut logs = take_weak!(self.client).logs(filter.clone())
.into_iter()
.map(From::from)
.collect::<Vec<Log>>();
if include_pending {
logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter));
}
to_value(&logs)
},
// just empty array
_ => Ok(Value::Array(vec![] as Vec<Value>)),
}
})
}
fn uninstall_filter(&self, params: Params) -> Result<Value, Error> {
from_params::<(Index,)>(params)
.and_then(|(index,)| {
self.polls.lock().unwrap().remove_poll(&index.value());
to_value(&true)
})
}
}

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/>.
//! Eth Filter RPC implementation
use std::ops::Deref;
use std::sync::{Arc, Weak, Mutex};
use std::collections::HashSet;
use jsonrpc_core::*;
use util::numbers::*;
use ethcore::miner::MinerService;
use ethcore::filter::Filter as EthcoreFilter;
use ethcore::client::{BlockChainClient, BlockID};
use v1::traits::EthFilter;
use v1::types::{BlockNumber, Index, Filter, Log};
use v1::helpers::{PollFilter, PollManager};
use v1::impls::eth::pending_logs;
/// Eth filter rpc implementation.
pub struct EthFilterClient<C, M> where
C: BlockChainClient,
M: MinerService {
client: Weak<C>,
miner: Weak<M>,
polls: Mutex<PollManager<PollFilter>>,
}
impl<C, M> EthFilterClient<C, M> where
C: BlockChainClient,
M: MinerService {
/// Creates new Eth filter client.
pub fn new(client: &Arc<C>, miner: &Arc<M>) -> Self {
EthFilterClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
polls: Mutex::new(PollManager::new()),
}
}
}
impl<C, M> EthFilter for EthFilterClient<C, M> where
C: BlockChainClient + 'static,
M: MinerService + 'static {
fn new_filter(&self, params: Params) -> Result<Value, Error> {
from_params::<(Filter,)>(params)
.and_then(|(filter,)| {
let mut polls = self.polls.lock().unwrap();
let block_number = take_weak!(self.client).chain_info().best_block_number;
let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter));
to_value(&U256::from(id))
})
}
fn new_block_filter(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => {
let mut polls = self.polls.lock().unwrap();
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
to_value(&U256::from(id))
},
_ => Err(Error::invalid_params())
}
}
fn new_pending_transaction_filter(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => {
let mut polls = self.polls.lock().unwrap();
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes();
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
to_value(&U256::from(id))
},
_ => Err(Error::invalid_params())
}
}
fn filter_changes(&self, params: Params) -> Result<Value, Error> {
let client = take_weak!(self.client);
from_params::<(Index,)>(params)
.and_then(|(index,)| {
let mut polls = self.polls.lock().unwrap();
match polls.poll_mut(&index.value()) {
None => Ok(Value::Array(vec![] as Vec<Value>)),
Some(filter) => match *filter {
PollFilter::Block(ref mut block_number) => {
// + 1, cause we want to return hashes including current block hash.
let current_number = client.chain_info().best_block_number + 1;
let hashes = (*block_number..current_number).into_iter()
.map(BlockID::Number)
.filter_map(|id| client.block_hash(id))
.collect::<Vec<H256>>();
*block_number = current_number;
to_value(&hashes)
},
PollFilter::PendingTransaction(ref mut previous_hashes) => {
// get hashes of pending transactions
let current_hashes = take_weak!(self.miner).pending_transactions_hashes();
let new_hashes =
{
let previous_hashes_set = previous_hashes.iter().collect::<HashSet<_>>();
// find all new hashes
current_hashes
.iter()
.filter(|hash| !previous_hashes_set.contains(hash))
.cloned()
.collect::<Vec<H256>>()
};
// save all hashes of pending transactions
*previous_hashes = current_hashes;
// return new hashes
to_value(&new_hashes)
},
PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => {
// retrive the current block number
let current_number = client.chain_info().best_block_number;
// check if we need to check pending hashes
let include_pending = filter.to_block == Some(BlockNumber::Pending);
// build appropriate filter
let mut filter: EthcoreFilter = filter.clone().into();
filter.from_block = BlockID::Number(*block_number);
filter.to_block = BlockID::Latest;
// retrieve logs in range from_block..min(BlockID::Latest..to_block)
let mut logs = client.logs(filter.clone())
.into_iter()
.map(From::from)
.collect::<Vec<Log>>();
// additionally retrieve pending logs
if include_pending {
let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter);
// remove logs about which client was already notified about
let new_pending_logs: Vec<_> = pending_logs.iter()
.filter(|p| !previous_logs.contains(p))
.cloned()
.collect();
// save all logs retrieved by client
*previous_logs = pending_logs.into_iter().collect();
// append logs array with new pending logs
logs.extend(new_pending_logs);
}
// save current block number as next from block number
*block_number = current_number;
to_value(&logs)
}
}
}
})
}
fn filter_logs(&self, params: Params) -> Result<Value, Error> {
from_params::<(Index,)>(params)
.and_then(|(index,)| {
let mut polls = self.polls.lock().unwrap();
match polls.poll(&index.value()) {
Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => {
let include_pending = filter.to_block == Some(BlockNumber::Pending);
let filter: EthcoreFilter = filter.clone().into();
let mut logs = take_weak!(self.client).logs(filter.clone())
.into_iter()
.map(From::from)
.collect::<Vec<Log>>();
if include_pending {
logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter));
}
to_value(&logs)
},
// just empty array
_ => Ok(Value::Array(vec![] as Vec<Value>)),
}
})
}
fn uninstall_filter(&self, params: Params) -> Result<Value, Error> {
from_params::<(Index,)>(params)
.and_then(|(index,)| {
self.polls.lock().unwrap().remove_poll(&index.value());
to_value(&true)
})
}
}

View File

@ -0,0 +1,111 @@
// 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/>.
//! Eth Signing RPC implementation.
use std::sync::{Arc, Weak};
use jsonrpc_core::*;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use util::numbers::*;
use util::keys::store::AccountProvider;
use v1::helpers::{SigningQueue, ConfirmationsQueue};
use v1::traits::EthSigning;
use v1::types::TransactionRequest;
use v1::impls::sign_and_dispatch;
/// Implementation of functions that require signing when no trusted signer is used.
pub struct EthSigningQueueClient {
queue: Weak<ConfirmationsQueue>,
}
impl EthSigningQueueClient {
/// Creates a new signing queue client given shared signing queue.
pub fn new(queue: &Arc<ConfirmationsQueue>) -> Self {
EthSigningQueueClient {
queue: Arc::downgrade(queue),
}
}
}
impl EthSigning for EthSigningQueueClient {
fn sign(&self, _params: Params) -> Result<Value, Error> {
// TODO [ToDr] Implement sign when rest of the signing queue is ready.
rpc_unimplemented!()
}
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(TransactionRequest, )>(params)
.and_then(|(request, )| {
let queue = take_weak!(self.queue);
queue.add_request(request);
// TODO [ToDr] Block and wait for confirmation?
to_value(&H256::zero())
})
}
}
/// Implementation of functions that require signing when no trusted signer is used.
pub struct EthSigningUnsafeClient<C, A, M> where
C: MiningBlockChainClient,
A: AccountProvider,
M: MinerService {
client: Weak<C>,
accounts: Weak<A>,
miner: Weak<M>,
}
impl<C, A, M> EthSigningUnsafeClient<C, A, M> where
C: MiningBlockChainClient,
A: AccountProvider,
M: MinerService {
/// Creates new EthClient.
pub fn new(client: &Arc<C>, accounts: &Arc<A>, miner: &Arc<M>)
-> Self {
EthSigningUnsafeClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
accounts: Arc::downgrade(accounts),
}
}
}
impl<C, A, M> EthSigning for EthSigningUnsafeClient<C, A, M> where
C: MiningBlockChainClient + 'static,
A: AccountProvider + 'static,
M: MinerService + 'static {
fn sign(&self, params: Params) -> Result<Value, Error> {
from_params::<(Address, H256)>(params).and_then(|(addr, msg)| {
to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero()))
})
}
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(TransactionRequest, )>(params)
.and_then(|(request, )| {
let accounts = take_weak!(self.accounts);
match accounts.account_secret(&request.from) {
Ok(secret) => sign_and_dispatch(&self.client, &self.miner, request, secret),
Err(_) => to_value(&H256::zero())
}
})
}
}

View File

@ -23,12 +23,12 @@ use std::ops::Deref;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use jsonrpc_core::*; use jsonrpc_core::*;
use serde; use serde;
use ethminer::MinerService; use ethcore::miner::MinerService;
use ethcore::state_diff::StateDiff; use ethcore::state_diff::StateDiff;
use ethcore::account_diff::{Diff, Existance}; use ethcore::account_diff::{Diff, Existance};
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
use ethcore::client::{BlockChainClient, CallAnalytics}; use ethcore::client::{BlockChainClient, CallAnalytics};
use ethcore::trace::VMTrace; use ethcore::trace::VMTrace;
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
use v1::traits::Ethcore; use v1::traits::Ethcore;
use v1::types::{Bytes, CallRequest}; use v1::types::{Bytes, CallRequest};

View File

@ -31,24 +31,30 @@ macro_rules! rpc_unimplemented {
mod web3; mod web3;
mod eth; mod eth;
mod eth_filter;
mod eth_signing;
mod net; mod net;
mod personal; mod personal;
mod personal_signer;
mod ethcore; mod ethcore;
mod traces; mod traces;
mod rpc; mod rpc;
pub use self::web3::Web3Client; pub use self::web3::Web3Client;
pub use self::eth::{EthClient, EthFilterClient}; pub use self::eth::EthClient;
pub use self::eth_filter::EthFilterClient;
pub use self::eth_signing::{EthSigningUnsafeClient, EthSigningQueueClient};
pub use self::net::NetClient; pub use self::net::NetClient;
pub use self::personal::PersonalClient; pub use self::personal::PersonalClient;
pub use self::personal_signer::SignerClient;
pub use self::ethcore::EthcoreClient; pub use self::ethcore::EthcoreClient;
pub use self::traces::TracesClient; pub use self::traces::TracesClient;
pub use self::rpc::RpcClient; pub use self::rpc::RpcClient;
use v1::types::TransactionRequest; use v1::types::TransactionRequest;
use std::sync::Weak; use std::sync::Weak;
use ethminer::{AccountDetails, MinerService}; use ethcore::miner::{AccountDetails, MinerService};
use ethcore::client::BlockChainClient; use ethcore::client::MiningBlockChainClient;
use ethcore::transaction::{Action, SignedTransaction, Transaction}; use ethcore::transaction::{Action, SignedTransaction, Transaction};
use util::numbers::*; use util::numbers::*;
use util::rlp::encode; use util::rlp::encode;
@ -56,7 +62,7 @@ use util::bytes::ToPretty;
use jsonrpc_core::{Error, to_value, Value}; use jsonrpc_core::{Error, to_value, Value};
fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error> fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
where C: BlockChainClient, M: MinerService { where C: MiningBlockChainClient, M: MinerService {
let hash = signed_transaction.hash(); let hash = signed_transaction.hash();
let import = miner.import_own_transaction(client, signed_transaction, |a: &Address| { let import = miner.import_own_transaction(client, signed_transaction, |a: &Address| {
@ -70,7 +76,7 @@ fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedT
} }
fn sign_and_dispatch<C, M>(client: &Weak<C>, miner: &Weak<M>, request: TransactionRequest, secret: H256) -> Result<Value, Error> fn sign_and_dispatch<C, M>(client: &Weak<C>, miner: &Weak<M>, request: TransactionRequest, secret: H256) -> Result<Value, Error>
where C: BlockChainClient, M: MinerService { where C: MiningBlockChainClient, M: MinerService {
let client = take_weak!(client); let client = take_weak!(client);
let miner = take_weak!(miner); let miner = take_weak!(miner);
@ -92,4 +98,4 @@ fn sign_and_dispatch<C, M>(client: &Weak<C>, miner: &Weak<M>, request: Transacti
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
dispatch_transaction(&*client, &*miner, signed_transaction) dispatch_transaction(&*client, &*miner, signed_transaction)
} }

View File

@ -20,21 +20,21 @@ use jsonrpc_core::*;
use v1::traits::Personal; use v1::traits::Personal;
use v1::types::TransactionRequest; use v1::types::TransactionRequest;
use v1::impls::sign_and_dispatch; use v1::impls::sign_and_dispatch;
use util::keys::store::*; use util::keys::store::AccountProvider;
use util::numbers::*; use util::numbers::*;
use ethcore::client::BlockChainClient; use ethcore::client::MiningBlockChainClient;
use ethminer::MinerService; use ethcore::miner::MinerService;
/// Account management (personal) rpc implementation. /// Account management (personal) rpc implementation.
pub struct PersonalClient<A, C, M> pub struct PersonalClient<A, C, M>
where A: AccountProvider, C: BlockChainClient, M: MinerService { where A: AccountProvider, C: MiningBlockChainClient, M: MinerService {
accounts: Weak<A>, accounts: Weak<A>,
client: Weak<C>, client: Weak<C>,
miner: Weak<M>, miner: Weak<M>,
} }
impl<A, C, M> PersonalClient<A, C, M> impl<A, C, M> PersonalClient<A, C, M>
where A: AccountProvider, C: BlockChainClient, M: MinerService { where A: AccountProvider, C: MiningBlockChainClient, M: MinerService {
/// Creates new PersonalClient /// Creates new PersonalClient
pub fn new(store: &Arc<A>, client: &Arc<C>, miner: &Arc<M>) -> Self { pub fn new(store: &Arc<A>, client: &Arc<C>, miner: &Arc<M>) -> Self {
PersonalClient { PersonalClient {
@ -46,7 +46,7 @@ impl<A, C, M> PersonalClient<A, C, M>
} }
impl<A: 'static, C: 'static, M: 'static> Personal for PersonalClient<A, C, M> impl<A: 'static, C: 'static, M: 'static> Personal for PersonalClient<A, C, M>
where A: AccountProvider, C: BlockChainClient, M: MinerService { where A: AccountProvider, C: MiningBlockChainClient, M: MinerService {
fn accounts(&self, _: Params) -> Result<Value, Error> { fn accounts(&self, _: Params) -> Result<Value, Error> {
let store = take_weak!(self.accounts); let store = take_weak!(self.accounts);
match store.accounts() { match store.accounts() {

View File

@ -0,0 +1,93 @@
// 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/>.
//! Transactions Confirmations (personal) rpc implementation
use std::sync::{Arc, Weak};
use jsonrpc_core::*;
use v1::traits::PersonalSigner;
use v1::types::TransactionModification;
use v1::impls::sign_and_dispatch;
use v1::helpers::{SigningQueue, ConfirmationsQueue};
use util::keys::store::AccountProvider;
use util::numbers::*;
use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
/// Transactions confirmation (personal) rpc implementation.
pub struct SignerClient<A, C, M>
where A: AccountProvider, C: MiningBlockChainClient, M: MinerService {
queue: Weak<ConfirmationsQueue>,
accounts: Weak<A>,
client: Weak<C>,
miner: Weak<M>,
}
impl<A: 'static, C: 'static, M: 'static> SignerClient<A, C, M>
where A: AccountProvider, C: MiningBlockChainClient, M: MinerService {
/// Create new instance of signer client.
pub fn new(store: &Arc<A>, client: &Arc<C>, miner: &Arc<M>, queue: &Arc<ConfirmationsQueue>) -> Self {
SignerClient {
queue: Arc::downgrade(queue),
accounts: Arc::downgrade(store),
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
}
}
}
impl<A: 'static, C: 'static, M: 'static> PersonalSigner for SignerClient<A, C, M>
where A: AccountProvider, C: MiningBlockChainClient, M: MinerService {
fn transactions_to_confirm(&self, _params: Params) -> Result<Value, Error> {
let queue = take_weak!(self.queue);
to_value(&queue.requests())
}
fn confirm_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(U256, TransactionModification, String)>(params).and_then(
|(id, modification, pass)| {
let accounts = take_weak!(self.accounts);
let queue = take_weak!(self.queue);
queue.remove_request(id)
.and_then(|confirmation| {
let mut request = confirmation.transaction;
// apply modification
if let Some(gas_price) = modification.gas_price {
request.gas_price = Some(gas_price);
}
match accounts.locked_account_secret(&request.from, &pass) {
Ok(secret) => Some(sign_and_dispatch(&self.client, &self.miner, request, secret)),
Err(_) => None
}
})
.unwrap_or_else(|| to_value(&H256::zero()))
}
)
}
fn reject_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(U256, )>(params).and_then(
|(id, )| {
let queue = take_weak!(self.queue);
let res = queue.remove_request(id);
to_value(&res.is_some())
}
)
}
}

View File

@ -25,5 +25,6 @@ pub mod traits;
pub mod tests; pub mod tests;
pub mod types; pub mod types;
pub use self::traits::{Web3, Eth, EthFilter, Personal, Net, Ethcore, Traces, Rpc}; pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Personal, PersonalSigner, Net, Ethcore, Traces, Rpc};
pub use self::impls::*; pub use self::impls::*;
pub use self::helpers::{SigningQueue, ConfirmationsQueue};

View File

@ -20,150 +20,24 @@ use std::sync::Arc;
use std::str::FromStr; use std::str::FromStr;
use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::client::{BlockChainClient, Client, ClientConfig};
use ethcore::spec::Genesis; use ethcore::ids::BlockID;
use ethcore::spec::{Genesis, Spec};
use ethcore::block::Block; use ethcore::block::Block;
use ethcore::views::BlockView;
use ethcore::ethereum; use ethcore::ethereum;
use ethcore::transaction::{Transaction, Action}; use ethcore::miner::{MinerService, ExternalMiner, Miner};
use ethminer::{MinerService, ExternalMiner};
use devtools::RandomTempPath; use devtools::RandomTempPath;
use util::Hashable;
use util::io::IoChannel; use util::io::IoChannel;
use util::hash::Address; use util::hash::{Address, H256};
use util::numbers::{Uint, U256}; use util::numbers::U256;
use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use util::keys::{AccountProvider, TestAccount, TestAccountProvider};
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use ethjson::blockchain::BlockChain; use ethjson::blockchain::BlockChain;
use v1::traits::eth::Eth; use v1::traits::eth::{Eth, EthSigning};
use v1::impls::EthClient; use v1::impls::{EthClient, EthSigningUnsafeClient};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use v1::tests::helpers::{TestSyncProvider, Config};
struct EthTester {
_client: Arc<BlockChainClient>,
_miner: Arc<MinerService>,
accounts: Arc<TestAccountProvider>,
handler: IoHandler,
}
#[test]
fn harness_works() {
let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest");
chain_harness(chain, |_| {});
}
#[test]
fn eth_get_balance() {
let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs");
chain_harness(chain, |tester| {
// final account state
let req_latest = r#"{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"],
"id": 1
}"#;
let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#.to_owned();
assert_eq!(tester.handler.handle_request(req_latest).unwrap(), res_latest);
// non-existant account
let req_new_acc = r#"{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],
"id": 3
}"#;
let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#.to_owned();
assert_eq!(tester.handler.handle_request(req_new_acc).unwrap(), res_new_acc);
});
}
#[test]
fn eth_block_number() {
let chain = extract_chain!("BlockchainTests/bcRPC_API_Test");
chain_harness(chain, |tester| {
let req_number = r#"{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}"#;
let res_number = r#"{"jsonrpc":"2.0","result":"0x20","id":1}"#.to_owned();
assert_eq!(tester.handler.handle_request(req_number).unwrap(), res_number);
});
}
#[cfg(test)]
#[test]
fn eth_transaction_count() {
let chain = extract_chain!("BlockchainTests/bcRPC_API_Test");
chain_harness(chain, |tester| {
let address = tester.accounts.new_account("123").unwrap();
let secret = tester.accounts.account_secret(&address).unwrap();
let req_before = r#"{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"],
"id": 15
}"#;
let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#;
assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before);
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 req_send_trans = 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": 16
}"#;
let res_send_trans = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":16}"#;
// dispatch the transaction.
assert_eq!(tester.handler.handle_request(&req_send_trans).unwrap(), res_send_trans);
// we have submitted the transaction -- but this shouldn't be reflected in a "latest" query.
let req_after_latest = r#"{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"],
"id": 17
}"#;
let res_after_latest = r#"{"jsonrpc":"2.0","result":"0x00","id":17}"#;
assert_eq!(&tester.handler.handle_request(&req_after_latest).unwrap(), res_after_latest);
// the pending transactions should have been updated.
let req_after_pending = r#"{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "pending"],
"id": 18
}"#;
let res_after_pending = r#"{"jsonrpc":"2.0","result":"0x01","id":18}"#;
assert_eq!(&tester.handler.handle_request(&req_after_pending).unwrap(), res_after_pending);
});
}
fn account_provider() -> Arc<TestAccountProvider> { fn account_provider() -> Arc<TestAccountProvider> {
let mut accounts = HashMap::new(); let mut accounts = HashMap::new();
@ -179,51 +53,308 @@ fn sync_provider() -> Arc<TestSyncProvider> {
})) }))
} }
fn miner_service() -> Arc<TestMinerService> { fn miner_service(spec: Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
Arc::new(TestMinerService::default()) Miner::with_accounts(true, spec, accounts)
} }
// given a blockchain, this harness will create an EthClient wrapping it fn make_spec(chain: &BlockChain) -> Spec {
// which tests can pass specially crafted requests to.
fn chain_harness<F, U>(chain: BlockChain, mut cb: F) -> U
where F: FnMut(&EthTester) -> U {
let genesis = Genesis::from(chain.genesis()); let genesis = Genesis::from(chain.genesis());
let mut spec = ethereum::new_frontier_test(); let mut spec = ethereum::new_frontier_test();
let state = chain.pre_state.clone().into(); let state = chain.pre_state.clone().into();
spec.set_genesis_state(state); spec.set_genesis_state(state);
spec.overwrite_genesis_params(genesis); spec.overwrite_genesis_params(genesis);
assert!(spec.is_state_root_valid()); assert!(spec.is_state_root_valid());
spec
}
let dir = RandomTempPath::new(); struct EthTester {
let client = Client::new(ClientConfig::default(), spec, dir.as_path(), IoChannel::disconnected()).unwrap(); client: Arc<Client>,
let sync_provider = sync_provider(); _miner: Arc<MinerService>,
let miner_service = miner_service(); accounts: Arc<TestAccountProvider>,
let account_provider = account_provider(); handler: IoHandler,
let external_miner = Arc::new(ExternalMiner::default()); }
for b in &chain.blocks_rlp() { impl EthTester {
if Block::is_good(&b) { fn from_chain(chain: &BlockChain) -> Self {
let _ = client.import_block(b.clone()); let tester = Self::from_spec_provider(|| make_spec(chain));
client.flush_queue();
client.import_verified_blocks(&IoChannel::disconnected()); for b in &chain.blocks_rlp() {
if Block::is_good(&b) {
let _ = tester.client.import_block(b.clone());
tester.client.flush_queue();
tester.client.import_verified_blocks(&IoChannel::disconnected());
}
}
tester.client.flush_queue();
assert!(tester.client.chain_info().best_block_hash == chain.best_block.clone().into());
tester
}
fn from_spec_provider<F>(spec_provider: F) -> Self
where F: Fn() -> Spec {
let dir = RandomTempPath::new();
let account_provider = account_provider();
let miner_service = miner_service(spec_provider(), account_provider.clone());
let client = Client::new(ClientConfig::default(), spec_provider(), dir.as_path(), miner_service.clone(), IoChannel::disconnected()).unwrap();
let sync_provider = sync_provider();
let external_miner = Arc::new(ExternalMiner::default());
let eth_client = EthClient::new(
&client,
&sync_provider,
&account_provider,
&miner_service,
&external_miner
);
let eth_sign = EthSigningUnsafeClient::new(
&client,
&account_provider,
&miner_service
);
let handler = IoHandler::new();
handler.add_delegate(eth_client.to_delegate());
handler.add_delegate(eth_sign.to_delegate());
EthTester {
_miner: miner_service,
client: client,
accounts: account_provider,
handler: handler,
}
}
}
#[test]
fn harness_works() {
let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest");
let _ = EthTester::from_chain(&chain);
}
#[test]
fn eth_get_balance() {
let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs");
let tester = EthTester::from_chain(&chain);
// final account state
let req_latest = r#"{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"],
"id": 1
}"#;
let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#.to_owned();
assert_eq!(tester.handler.handle_request(req_latest).unwrap(), res_latest);
// non-existant account
let req_new_acc = r#"{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],
"id": 3
}"#;
let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#.to_owned();
assert_eq!(tester.handler.handle_request(req_new_acc).unwrap(), res_new_acc);
}
#[test]
fn eth_block_number() {
let chain = extract_chain!("BlockchainTests/bcRPC_API_Test");
let tester = EthTester::from_chain(&chain);
let req_number = r#"{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}"#;
let res_number = r#"{"jsonrpc":"2.0","result":"0x20","id":1}"#.to_owned();
assert_eq!(tester.handler.handle_request(req_number).unwrap(), res_number);
}
// a frontier-like test with an expanded gas limit and balance on known account.
const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{
"name": "Frontier (Test)",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x50000",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x50000"
},
"accounts": {
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"faa34835af5c2ea724333018a515fbb7d5bc0b33": { "balance": "10000000000000", "nonce": "0" }
}
}
"#;
#[test]
fn eth_transaction_count() {
use util::crypto::Secret;
let address = Address::from_str("faa34835af5c2ea724333018a515fbb7d5bc0b33").unwrap();
let secret = Secret::from_str("8a283037bb19c4fed7b1c569e40c7dcff366165eb869110a1b11532963eb9cb2").unwrap();
let tester = EthTester::from_spec_provider(|| Spec::load(TRANSACTION_COUNT_SPEC));
tester.accounts.accounts.write().unwrap().insert(address, TestAccount {
unlocked: false,
password: "123".into(),
secret: secret
});
let req_before = r#"{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"],
"id": 15
}"#;
let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#;
assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before);
let req_send_trans = r#"{
"jsonrpc": "2.0",
"method": "eth_sendTransaction",
"params": [{
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"gas": "0x30000",
"gasPrice": "0x01",
"value": "0x9184e72a"
}],
"id": 16
}"#;
// dispatch the transaction.
tester.handler.handle_request(&req_send_trans).unwrap();
// we have submitted the transaction -- but this shouldn't be reflected in a "latest" query.
let req_after_latest = r#"{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"],
"id": 17
}"#;
let res_after_latest = r#"{"jsonrpc":"2.0","result":"0x00","id":17}"#;
assert_eq!(&tester.handler.handle_request(&req_after_latest).unwrap(), res_after_latest);
// the pending transactions should have been updated.
let req_after_pending = r#"{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "pending"],
"id": 18
}"#;
let res_after_pending = r#"{"jsonrpc":"2.0","result":"0x01","id":18}"#;
assert_eq!(&tester.handler.handle_request(&req_after_pending).unwrap(), res_after_pending);
}
fn verify_transaction_counts(name: String, chain: BlockChain) {
struct PanicHandler(String);
impl Drop for PanicHandler {
fn drop(&mut self) {
if ::std::thread::panicking() {
println!("Test failed: {}", self.0);
}
} }
} }
assert!(client.chain_info().best_block_hash == chain.best_block.into()); let _panic = PanicHandler(name);
let eth_client = EthClient::new(&client, &sync_provider, &account_provider, fn by_hash(hash: H256, count: usize, id: &mut usize) -> (String, String) {
&miner_service, &external_miner); let req = r#"{
"jsonrpc": "2.0",
"method": "eth_getBlockTransactionCountByHash",
"params": [
""#.to_owned() + format!("0x{:?}", hash).as_ref() + r#""
],
"id": "# + format!("{}", *id).as_ref() + r#"
}"#;
let handler = IoHandler::new(); let res = r#"{"jsonrpc":"2.0","result":""#.to_owned()
let delegate = eth_client.to_delegate(); + format!("0x{:02x}", count).as_ref()
handler.add_delegate(delegate); + r#"","id":"#
+ format!("{}", *id).as_ref() + r#"}"#;
*id += 1;
(req, res)
}
let tester = EthTester { fn by_number(num: u64, count: usize, id: &mut usize) -> (String, String) {
_miner: miner_service, let req = r#"{
_client: client, "jsonrpc": "2.0",
accounts: account_provider, "method": "eth_getBlockTransactionCountByNumber",
handler: handler, "params": [
}; "#.to_owned() + &::serde_json::to_string(&U256::from(num)).unwrap() + r#"
],
"id": "# + format!("{}", *id).as_ref() + r#"
}"#;
cb(&tester) let res = r#"{"jsonrpc":"2.0","result":""#.to_owned()
+ format!("0x{:02x}", count).as_ref()
+ r#"","id":"#
+ format!("{}", *id).as_ref() + r#"}"#;
*id += 1;
(req, res)
}
let tester = EthTester::from_chain(&chain);
let mut id = 1;
for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| BlockView::new(b)) {
let count = b.transactions_count();
let hash = b.sha3();
let number = b.header_view().number();
let (req, res) = by_hash(hash, count, &mut id);
assert_eq!(tester.handler.handle_request(&req), Some(res));
// uncles can share block numbers, so skip them.
if tester.client.block_hash(BlockID::Number(number)) == Some(hash) {
let (req, res) = by_number(number, count, &mut id);
assert_eq!(tester.handler.handle_request(&req), Some(res));
}
}
} }
register_test!(eth_transaction_count_1, verify_transaction_counts, "BlockchainTests/bcWalletTest");
register_test!(eth_transaction_count_2, verify_transaction_counts, "BlockchainTests/bcTotalDifficultyTest");
register_test!(eth_transaction_count_3, verify_transaction_counts, "BlockchainTests/bcGasPricerTest");

View File

@ -19,11 +19,11 @@
use util::{Address, H256, Bytes, U256, FixedHash, Uint}; use util::{Address, H256, Bytes, U256, FixedHash, Uint};
use util::standard::*; use util::standard::*;
use ethcore::error::{Error, ExecutionError}; use ethcore::error::{Error, ExecutionError};
use ethcore::client::{BlockChainClient, Executed, CallAnalytics}; use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::block::{ClosedBlock, IsBlock};
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
use ethcore::receipt::Receipt; use ethcore::receipt::Receipt;
use ethminer::{MinerService, MinerStatus, AccountDetails, TransactionImportResult}; use ethcore::miner::{MinerService, MinerStatus, AccountDetails, TransactionImportResult};
/// Test miner service. /// Test miner service.
pub struct TestMinerService { pub struct TestMinerService {
@ -132,7 +132,7 @@ impl MinerService for TestMinerService {
} }
/// Imports transactions to transaction queue. /// Imports transactions to transaction queue.
fn import_own_transaction<T>(&self, chain: &BlockChainClient, transaction: SignedTransaction, _fetch_account: T) -> fn import_own_transaction<T>(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, _fetch_account: T) ->
Result<TransactionImportResult, Error> Result<TransactionImportResult, Error>
where T: Fn(&Address) -> AccountDetails { where T: Fn(&Address) -> AccountDetails {
@ -154,21 +154,21 @@ impl MinerService for TestMinerService {
} }
/// 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) { fn clear_and_reset(&self, _chain: &MiningBlockChainClient) {
unimplemented!(); 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]) { fn chain_new_blocks(&self, _chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
unimplemented!(); unimplemented!();
} }
/// New chain head event. Restart mining operation. /// New chain head event. Restart mining operation.
fn update_sealing(&self, _chain: &BlockChainClient) { fn update_sealing(&self, _chain: &MiningBlockChainClient) {
unimplemented!(); unimplemented!();
} }
fn map_sealing_work<F, T>(&self, _chain: &BlockChainClient, _f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T { fn map_sealing_work<F, T>(&self, _chain: &MiningBlockChainClient, _f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
unimplemented!(); unimplemented!();
} }
@ -194,29 +194,29 @@ impl MinerService for TestMinerService {
/// 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> { fn submit_seal(&self, _chain: &MiningBlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
unimplemented!(); unimplemented!();
} }
fn balance(&self, _chain: &BlockChainClient, address: &Address) -> U256 { fn balance(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 {
self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone()) self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone())
} }
fn call(&self, _chain: &BlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> { fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
unimplemented!(); unimplemented!();
} }
fn storage_at(&self, _chain: &BlockChainClient, address: &Address, position: &H256) -> H256 { fn storage_at(&self, _chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 {
self.latest_closed_block.lock().unwrap().as_ref().map_or_else(H256::default, |b| b.block().fields().state.storage_at(address, position).clone()) self.latest_closed_block.lock().unwrap().as_ref().map_or_else(H256::default, |b| b.block().fields().state.storage_at(address, position).clone())
} }
fn nonce(&self, _chain: &BlockChainClient, address: &Address) -> U256 { fn nonce(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 {
// we assume all transactions are in a pending block, ignoring the // we assume all transactions are in a pending block, ignoring the
// reality of gas limits. // reality of gas limits.
self.last_nonce(address).unwrap_or(U256::zero()) self.last_nonce(address).unwrap_or(U256::zero())
} }
fn code(&self, _chain: &BlockChainClient, address: &Address) -> Option<Bytes> { fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
self.latest_closed_block.lock().unwrap().as_ref().map_or(None, |b| b.block().fields().state.code(address).clone()) self.latest_closed_block.lock().unwrap().as_ref().map_or(None, |b| b.block().fields().state.code(address).clone())
} }

View File

@ -25,9 +25,9 @@ use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, Transaction
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 ethcore::transaction::{Transaction, Action};
use ethminer::{ExternalMiner, MinerService}; use ethcore::miner::{ExternalMiner, MinerService};
use ethsync::SyncState; use ethsync::SyncState;
use v1::{Eth, EthClient}; use v1::{Eth, EthClient, EthSigning, EthSigningUnsafeClient};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};
use rustc_serialize::hex::ToHex; use rustc_serialize::hex::ToHex;
@ -72,8 +72,11 @@ impl Default for EthTester {
let hashrates = Arc::new(RwLock::new(HashMap::new())); let hashrates = Arc::new(RwLock::new(HashMap::new()));
let external_miner = Arc::new(ExternalMiner::new(hashrates.clone())); let external_miner = Arc::new(ExternalMiner::new(hashrates.clone()));
let eth = EthClient::new(&client, &sync, &ap, &miner, &external_miner).to_delegate(); let eth = EthClient::new(&client, &sync, &ap, &miner, &external_miner).to_delegate();
let sign = EthSigningUnsafeClient::new(&client, &ap, &miner).to_delegate();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(eth); io.add_delegate(eth);
io.add_delegate(sign);
EthTester { EthTester {
client: client, client: client,
sync: sync, sync: sync,
@ -428,6 +431,7 @@ fn rpc_eth_call() {
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: None,
vm_trace: None, vm_trace: None,
diff: None,
}); });
let request = r#"{ let request = r#"{
@ -462,6 +466,7 @@ fn rpc_eth_call_default_block() {
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: None,
vm_trace: None, vm_trace: None,
diff: None,
}); });
let request = r#"{ let request = r#"{
@ -495,6 +500,7 @@ fn rpc_eth_estimate_gas() {
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: None,
vm_trace: None, vm_trace: None,
diff: None,
}); });
let request = r#"{ let request = r#"{
@ -529,6 +535,7 @@ fn rpc_eth_estimate_gas_default_block() {
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: None,
vm_trace: None, vm_trace: None,
diff: None,
}); });
let request = r#"{ let request = r#"{

View File

@ -0,0 +1,75 @@
// 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/>.
use std::sync::Arc;
use jsonrpc_core::IoHandler;
use v1::impls::EthSigningQueueClient;
use v1::traits::EthSigning;
use v1::helpers::{ConfirmationsQueue, SigningQueue};
use util::keys::TestAccount;
struct EthSigningTester {
pub queue: Arc<ConfirmationsQueue>,
pub io: IoHandler,
}
impl Default for EthSigningTester {
fn default() -> Self {
let queue = Arc::new(ConfirmationsQueue::default());
let io = IoHandler::new();
io.add_delegate(EthSigningQueueClient::new(&queue).to_delegate());
EthSigningTester {
queue: queue,
io: io,
}
}
}
fn eth_signing() -> EthSigningTester {
EthSigningTester::default()
}
#[test]
fn should_add_transaction_to_queue() {
// given
let tester = eth_signing();
let account = TestAccount::new("123");
let address = account.address();
assert_eq!(tester.queue.requests().len(), 0);
// when
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 response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000","id":1}"#;
// then
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
assert_eq!(tester.queue.requests().len(), 1);
}

View File

@ -18,8 +18,8 @@ use std::sync::Arc;
use std::str::FromStr; use std::str::FromStr;
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use v1::{Ethcore, EthcoreClient}; use v1::{Ethcore, EthcoreClient};
use ethminer::MinerService;
use ethcore::client::{TestBlockChainClient}; use ethcore::client::{TestBlockChainClient};
use ethcore::miner::MinerService;
use v1::tests::helpers::TestMinerService; use v1::tests::helpers::TestMinerService;
use util::numbers::*; use util::numbers::*;
use rustc_serialize::hex::FromHex; use rustc_serialize::hex::FromHex;

View File

@ -18,8 +18,10 @@
//! method calls properly. //! method calls properly.
mod eth; mod eth;
mod eth_signing;
mod net; mod net;
mod web3; mod web3;
mod personal; mod personal;
mod personal_signer;
mod ethcore; mod ethcore;
mod rpc; mod rpc;

View File

@ -176,4 +176,4 @@ fn sign_and_send_transaction() {
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; 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)); assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
} }

View File

@ -0,0 +1,169 @@
// 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/>.
use std::sync::Arc;
use std::str::FromStr;
use std::collections::HashMap;
use jsonrpc_core::IoHandler;
use util::numbers::*;
use util::keys::{TestAccount, TestAccountProvider};
use ethcore::client::TestBlockChainClient;
use ethcore::transaction::{Transaction, Action};
use v1::{SignerClient, PersonalSigner};
use v1::tests::helpers::TestMinerService;
use v1::helpers::{SigningQueue, ConfirmationsQueue};
use v1::types::TransactionRequest;
struct PersonalSignerTester {
queue: Arc<ConfirmationsQueue>,
accounts: Arc<TestAccountProvider>,
io: IoHandler,
miner: Arc<TestMinerService>,
// these unused fields are necessary to keep the data alive
// as the handler has only weak pointers.
_client: Arc<TestBlockChainClient>,
}
fn blockchain_client() -> Arc<TestBlockChainClient> {
let client = TestBlockChainClient::new();
Arc::new(client)
}
fn accounts_provider() -> Arc<TestAccountProvider> {
let accounts = HashMap::new();
let ap = TestAccountProvider::new(accounts);
Arc::new(ap)
}
fn miner_service() -> Arc<TestMinerService> {
Arc::new(TestMinerService::default())
}
fn signer_tester() -> PersonalSignerTester {
let queue = Arc::new(ConfirmationsQueue::default());
let accounts = accounts_provider();
let client = blockchain_client();
let miner = miner_service();
let io = IoHandler::new();
io.add_delegate(SignerClient::new(&accounts, &client, &miner, &queue).to_delegate());
PersonalSignerTester {
queue: queue,
accounts: accounts,
io: io,
miner: miner,
_client: client,
}
}
#[test]
fn should_return_list_of_transactions_in_queue() {
// given
let tester = signer_tester();
tester.queue.add_request(TransactionRequest {
from: Address::from(1),
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
gas_price: Some(U256::from(10_000)),
gas: Some(U256::from(10_000_000)),
value: Some(U256::from(1)),
data: None,
nonce: None,
});
// when
let request = r#"{"jsonrpc":"2.0","method":"personal_transactionsToConfirm","params":[],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":[{"id":"0x01","transaction":{"data":null,"from":"0x0000000000000000000000000000000000000001","gas":"0x989680","gasPrice":"0x2710","nonce":null,"to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","value":"0x01"}}],"id":1}"#;
// then
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
}
#[test]
fn should_reject_transaction_from_queue_without_dispatching() {
// given
let tester = signer_tester();
tester.queue.add_request(TransactionRequest {
from: Address::from(1),
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
gas_price: Some(U256::from(10_000)),
gas: Some(U256::from(10_000_000)),
value: Some(U256::from(1)),
data: None,
nonce: None,
});
assert_eq!(tester.queue.requests().len(), 1);
// when
let request = r#"{"jsonrpc":"2.0","method":"personal_rejectTransaction","params":["0x01"],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
// then
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
assert_eq!(tester.queue.requests().len(), 0);
assert_eq!(tester.miner.imported_transactions.lock().unwrap().len(), 0);
}
#[test]
fn should_confirm_transaction_and_dispatch() {
// given
let tester = signer_tester();
let account = TestAccount::new("test");
let address = account.address();
let secret = account.secret.clone();
let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap();
tester.accounts.accounts
.write()
.unwrap()
.insert(address, account);
tester.queue.add_request(TransactionRequest {
from: address,
to: Some(recipient),
gas_price: Some(U256::from(10_000)),
gas: Some(U256::from(10_000_000)),
value: Some(U256::from(1)),
data: None,
nonce: None,
});
let t = Transaction {
nonce: U256::zero(),
gas_price: U256::from(0x1000),
gas: U256::from(10_000_000),
action: Action::Call(recipient),
value: U256::from(0x1),
data: vec![]
}.sign(&secret);
assert_eq!(tester.queue.requests().len(), 1);
// when
let request = r#"{
"jsonrpc":"2.0",
"method":"personal_confirmTransaction",
"params":["0x01", {"gasPrice":"0x1000"}, "test"],
"id":1
}"#;
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
// then
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
assert_eq!(tester.queue.requests().len(), 0);
assert_eq!(tester.miner.imported_transactions.lock().unwrap().len(), 1);
}

View File

@ -13,11 +13,15 @@ pub mod helpers;
// extract the chain with that name. This will panic if no chain by that name // extract the chain with that name. This will panic if no chain by that name
// is found. // is found.
macro_rules! extract_chain { macro_rules! extract_chain {
($file:expr, $name:expr) => {{ (iter $file:expr) => {{
const RAW_DATA: &'static [u8] = const RAW_DATA: &'static [u8] =
include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json")); include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json"));
::ethjson::blockchain::Test::load(RAW_DATA).unwrap().into_iter()
}};
($file:expr, $name:expr) => {{
let mut chain = None; let mut chain = None;
for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { for (name, c) in extract_chain!(iter $file) {
if name == $name { if name == $name {
chain = Some(c); chain = Some(c);
break; break;
@ -27,14 +31,41 @@ macro_rules! extract_chain {
}}; }};
($file:expr) => {{ ($file:expr) => {{
const RAW_DATA: &'static [u8] = extract_chain!(iter $file).next().unwrap().1
include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json"));
::ethjson::blockchain::Test::load(RAW_DATA)
.unwrap().into_iter().next().unwrap().1
}}; }};
} }
macro_rules! register_test {
($name:ident, $cb:expr, $file:expr) => {
#[test]
fn $name() {
for (name, chain) in extract_chain!(iter $file) {
$cb(name, chain);
}
}
};
(heavy $name:ident, $cb:expr, $file:expr) => {
#[test]
#[cfg(feature = "test-heavy")]
fn $name() {
for (name, chain) in extract_chain!(iter $file) {
$cb(name, chain);
}
}
};
(ignore $name:ident, $cb:expr, $file:expr) => {
#[test]
#[ignore]
fn $name() {
for (name, chain) in extract_chain!(iter $file) {
$cb(name, chain);
}
}
};
}
#[cfg(test)] #[cfg(test)]
mod mocked; mod mocked;
#[cfg(test)] #[cfg(test)]

View File

@ -74,12 +74,6 @@ pub trait Eth: Sized + Send + Sync + 'static {
/// Returns the code at given address at given time (block number). /// Returns the code at given address at given time (block number).
fn code_at(&self, _: Params) -> Result<Value, Error>; fn code_at(&self, _: Params) -> Result<Value, Error>;
/// Signs the data with given address signature.
fn sign(&self, _: Params) -> Result<Value, Error>;
/// Sends transaction.
fn send_transaction(&self, _: Params) -> Result<Value, Error>;
/// Sends signed transaction. /// Sends signed transaction.
fn send_raw_transaction(&self, _: Params) -> Result<Value, Error>; fn send_raw_transaction(&self, _: Params) -> Result<Value, Error>;
@ -150,8 +144,6 @@ pub trait Eth: Sized + Send + Sync + 'static {
delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash); delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash);
delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number); delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number);
delegate.add_method("eth_getCode", Eth::code_at); delegate.add_method("eth_getCode", Eth::code_at);
delegate.add_method("eth_sign", Eth::sign);
delegate.add_method("eth_sendTransaction", Eth::send_transaction);
delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction); delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction);
delegate.add_method("eth_call", Eth::call); delegate.add_method("eth_call", Eth::call);
delegate.add_method("eth_estimateGas", Eth::estimate_gas); delegate.add_method("eth_estimateGas", Eth::estimate_gas);
@ -208,3 +200,20 @@ pub trait EthFilter: Sized + Send + Sync + 'static {
delegate delegate
} }
} }
/// Signing methods implementation relying on unlocked accounts.
pub trait EthSigning: Sized + Send + Sync + 'static {
/// Signs the data with given address signature.
fn sign(&self, _: Params) -> Result<Value, Error>;
/// Sends transaction.
fn send_transaction(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
let mut delegate = IoDelegate::new(Arc::new(self));
delegate.add_method("eth_sign", EthSigning::sign);
delegate.add_method("eth_sendTransaction", EthSigning::send_transaction);
delegate
}
}

View File

@ -25,9 +25,11 @@ pub mod traces;
pub mod rpc; pub mod rpc;
pub use self::web3::Web3; pub use self::web3::Web3;
pub use self::eth::{Eth, EthFilter}; pub use self::eth::{Eth, EthFilter, EthSigning};
pub use self::net::Net; pub use self::net::Net;
pub use self::personal::Personal; pub use self::personal::{Personal, PersonalSigner};
pub use self::ethcore::Ethcore; pub use self::ethcore::Ethcore;
pub use self::traces::Traces; pub use self::traces::Traces;
pub use self::rpc::Rpc; pub use self::rpc::Rpc;

View File

@ -43,3 +43,26 @@ pub trait Personal: Sized + Send + Sync + 'static {
delegate delegate
} }
} }
/// Personal extension for transactions confirmations rpc interface.
pub trait PersonalSigner: Sized + Send + Sync + 'static {
/// Returns a list of transactions to confirm.
fn transactions_to_confirm(&self, _: Params) -> Result<Value, Error>;
/// Confirm and send a specific transaction.
fn confirm_transaction(&self, _: Params) -> Result<Value, Error>;
/// Reject the transaction request.
fn reject_transaction(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
let mut delegate = IoDelegate::new(Arc::new(self));
delegate.add_method("personal_transactionsToConfirm", PersonalSigner::transactions_to_confirm);
delegate.add_method("personal_confirmTransaction", PersonalSigner::confirm_transaction);
delegate.add_method("personal_rejectTransaction", PersonalSigner::reject_transaction);
delegate
}
}

View File

@ -38,7 +38,7 @@ pub use self::log::Log;
pub use self::optionals::OptionalValue; pub use self::optionals::OptionalValue;
pub use self::sync::{SyncStatus, SyncInfo}; pub use self::sync::{SyncStatus, SyncInfo};
pub use self::transaction::Transaction; pub use self::transaction::Transaction;
pub use self::transaction_request::TransactionRequest; pub use self::transaction_request::{TransactionRequest, TransactionConfirmation, TransactionModification};
pub use self::call_request::CallRequest; pub use self::call_request::CallRequest;
pub use self::receipt::Receipt; pub use self::receipt::Receipt;
pub use self::trace::Trace; pub use self::trace::Trace;

View File

@ -21,7 +21,7 @@ use util::numbers::U256;
use v1::types::bytes::Bytes; use v1::types::bytes::Bytes;
/// Transaction request coming from RPC /// Transaction request coming from RPC
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize)] #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct TransactionRequest { pub struct TransactionRequest {
/// Sender /// Sender
pub from: Address, pub from: Address,
@ -40,6 +40,24 @@ pub struct TransactionRequest {
pub nonce: Option<U256>, pub nonce: Option<U256>,
} }
/// Transaction confirmation waiting in a queue
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Serialize)]
pub struct TransactionConfirmation {
/// Id of this confirmation
pub id: U256,
/// TransactionRequest
pub transaction: TransactionRequest,
}
/// Possible modifications to the confirmed transaction sent by SystemUI
#[derive(Debug, PartialEq, Deserialize)]
pub struct TransactionModification {
/// Modified gas price
#[serde(rename="gasPrice")]
pub gas_price: Option<U256>,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::str::FromStr; use std::str::FromStr;
@ -135,5 +153,26 @@ mod tests {
nonce: None, nonce: None,
}); });
} }
#[test]
fn should_deserialize_modification() {
// given
let s1 = r#"{
"gasPrice":"0x0ba43b7400"
}"#;
let s2 = r#"{}"#;
// when
let res1: TransactionModification = serde_json::from_str(s1).unwrap();
let res2: TransactionModification = serde_json::from_str(s2).unwrap();
// then
assert_eq!(res1, TransactionModification {
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
});
assert_eq!(res2, TransactionModification {
gas_price: None,
});
}
} }

View File

@ -9,13 +9,8 @@ build = "build.rs"
[build-dependencies] [build-dependencies]
rustc_version = "0.1" rustc_version = "0.1"
serde_codegen = { version = "0.7.0", optional = true }
syntex = "^0.32.0"
[dependencies] [dependencies]
serde = "0.7.0"
serde_json = "0.7.0"
rustc-serialize = "0.3"
jsonrpc-core = "2.0" jsonrpc-core = "2.0"
log = "0.3" log = "0.3"
env_logger = "0.3" env_logger = "0.3"
@ -23,10 +18,7 @@ ws = "0.4.7"
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
ethcore-rpc = { path = "../rpc" } ethcore-rpc = { path = "../rpc" }
serde_macros = { version = "0.7.0", optional = true }
clippy = { version = "0.0.69", optional = true} clippy = { version = "0.0.69", optional = true}
[features] [features]
default = ["serde_codegen"]
nightly = ["serde_macros"]
dev = ["clippy"] dev = ["clippy"]

View File

@ -19,34 +19,7 @@ extern crate rustc_version;
use rustc_version::{version_meta, Channel}; use rustc_version::{version_meta, Channel};
fn main() { fn main() {
serde::main();
if let Channel::Nightly = version_meta().channel { if let Channel::Nightly = version_meta().channel {
println!("cargo:rustc-cfg=nightly"); println!("cargo:rustc-cfg=nightly");
} }
} }
#[cfg(not(feature = "serde_macros"))]
mod serde {
extern crate syntex;
extern crate serde_codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("src/types/mod.rs.in");
let dst = Path::new(&out_dir).join("mod.rs");
let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
}
#[cfg(feature = "serde_macros")]
mod serde {
pub fn main() {}
}

View File

@ -17,8 +17,6 @@
#![warn(missing_docs)] #![warn(missing_docs)]
#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] #![cfg_attr(all(nightly, feature="dev"), feature(plugin))]
#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] #![cfg_attr(all(nightly, feature="dev"), plugin(clippy))]
// Generated by serde
#![cfg_attr(all(nightly, feature="dev"), allow(redundant_closure_call))]
//! Signer module //! Signer module
//! //!
@ -45,18 +43,12 @@
extern crate log; extern crate log;
extern crate env_logger; extern crate env_logger;
extern crate serde;
extern crate serde_json;
extern crate rustc_serialize;
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate ethcore_rpc as rpc; extern crate ethcore_rpc as rpc;
extern crate jsonrpc_core; extern crate jsonrpc_core;
extern crate ws; extern crate ws;
mod signing_queue;
mod ws_server; mod ws_server;
pub use ws_server::*; pub use ws_server::*;
#[cfg(test)] #[cfg(test)]

View File

@ -1,74 +0,0 @@
// 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/>.
use std::collections::HashSet;
use rpc::v1::types::TransactionRequest;
pub trait SigningQueue {
fn add_request(&mut self, transaction: TransactionRequest);
fn remove_request(&mut self, id: TransactionRequest);
fn requests(&self) -> &HashSet<TransactionRequest>;
}
impl SigningQueue for HashSet<TransactionRequest> {
fn add_request(&mut self, transaction: TransactionRequest) {
self.insert(transaction);
}
fn remove_request(&mut self, id: TransactionRequest) {
self.remove(&id);
}
fn requests(&self) -> &HashSet<TransactionRequest> {
self
}
}
#[cfg(test)]
mod test {
use std::collections::HashSet;
use util::hash::Address;
use util::numbers::U256;
use rpc::v1::types::TransactionRequest;
use super::*;
#[test]
fn should_work_for_hashset() {
// given
let mut queue = HashSet::new();
let request = TransactionRequest {
from: Address::from(1),
to: Some(Address::from(2)),
gas_price: None,
gas: None,
value: Some(U256::from(10_000_000)),
data: None,
nonce: None,
};
// when
queue.add_request(request.clone());
let all = queue.requests();
// then
assert_eq!(all.len(), 1);
assert!(all.contains(&request));
}
}

View File

@ -1,23 +0,0 @@
// 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/>.
//! Reusable types with JSON Serialization.
#[cfg(feature = "serde_macros")]
include!("mod.rs.in");
#[cfg(not(feature = "serde_macros"))]
include!(concat!(env!("OUT_DIR"), "/mod.rs"));

View File

@ -1,25 +0,0 @@
// 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/>.
// TODO [ToDr] Types are empty for now. But they are about to come.

View File

@ -25,6 +25,7 @@ use std::sync::Arc;
use std::net::SocketAddr; use std::net::SocketAddr;
use util::panics::{PanicHandler, OnPanicListener, MayPanic}; use util::panics::{PanicHandler, OnPanicListener, MayPanic};
use jsonrpc_core::{IoHandler, IoDelegate}; use jsonrpc_core::{IoHandler, IoDelegate};
use rpc::Extendable;
mod session; mod session;
@ -57,6 +58,12 @@ impl Default for ServerBuilder {
} }
} }
impl Extendable for ServerBuilder {
fn add_delegate<D: Send + Sync + 'static>(&self, delegate: IoDelegate<D>) {
self.handler.add_delegate(delegate);
}
}
impl ServerBuilder { impl ServerBuilder {
/// Creates new `ServerBuilder` /// Creates new `ServerBuilder`
pub fn new() -> Self { pub fn new() -> Self {
@ -65,11 +72,6 @@ impl ServerBuilder {
} }
} }
/// Adds rpc delegate
pub fn add_delegate<D>(&self, delegate: IoDelegate<D>) where D: Send + Sync + 'static {
self.handler.add_delegate(delegate);
}
/// Starts a new `WebSocket` server in separate thread. /// Starts a new `WebSocket` server in separate thread.
/// Returns a `Server` handle which closes the server when droped. /// Returns a `Server` handle which closes the server when droped.
pub fn start(self, addr: SocketAddr) -> Result<Server, ServerError> { pub fn start(self, addr: SocketAddr) -> Result<Server, ServerError> {

View File

@ -11,7 +11,6 @@ authors = ["Ethcore <admin@ethcore.io"]
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" } ethcore = { path = "../ethcore" }
clippy = { version = "0.0.69", optional = true} clippy = { version = "0.0.69", optional = true}
ethminer = { path = "../miner" }
log = "0.3" log = "0.3"
env_logger = "0.3" env_logger = "0.3"
time = "0.1.34" time = "0.1.34"
@ -20,4 +19,4 @@ heapsize = "0.3"
[features] [features]
default = [] default = []
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethminer/dev"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev"]

View File

@ -97,7 +97,6 @@ use ethcore::client::{BlockChainClient, BlockStatus, BlockID, BlockChainInfo};
use ethcore::error::*; use ethcore::error::*;
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
use ethcore::block::Block; use ethcore::block::Block;
use ethminer::{Miner, MinerService, AccountDetails};
use io::SyncIo; use io::SyncIo;
use time; use time;
use super::SyncConfig; use super::SyncConfig;
@ -241,15 +240,13 @@ pub struct ChainSync {
imported_this_round: Option<usize>, imported_this_round: Option<usize>,
/// Network ID /// Network ID
network_id: U256, network_id: U256,
/// Miner
miner: Arc<Miner>,
} }
type RlpResponseResult = Result<Option<(PacketId, RlpStream)>, PacketDecodeError>; type RlpResponseResult = Result<Option<(PacketId, RlpStream)>, PacketDecodeError>;
impl ChainSync { impl ChainSync {
/// Create a new instance of syncing strategy. /// Create a new instance of syncing strategy.
pub fn new(config: SyncConfig, miner: Arc<Miner>, chain: &BlockChainClient) -> ChainSync { pub fn new(config: SyncConfig, chain: &BlockChainClient) -> ChainSync {
let chain = chain.chain_info(); let chain = chain.chain_info();
let mut sync = ChainSync { let mut sync = ChainSync {
state: SyncState::ChainHead, state: SyncState::ChainHead,
@ -265,7 +262,6 @@ impl ChainSync {
imported_this_round: None, imported_this_round: None,
_max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), _max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks),
network_id: config.network_id, network_id: config.network_id,
miner: miner,
}; };
sync.reset(); sync.reset();
sync sync
@ -898,12 +894,7 @@ impl ChainSync {
let tx: SignedTransaction = try!(r.val_at(i)); let tx: SignedTransaction = try!(r.val_at(i));
transactions.push(tx); transactions.push(tx);
} }
let chain = io.chain(); let _ = io.chain().import_transactions(transactions);
let fetch_account = |a: &Address| AccountDetails {
nonce: chain.latest_nonce(a),
balance: chain.latest_balance(a),
};
let _ = self.miner.import_transactions(transactions, fetch_account);
Ok(()) Ok(())
} }
@ -1226,7 +1217,7 @@ impl ChainSync {
return 0; return 0;
} }
let mut transactions = self.miner.all_transactions(); let mut transactions = io.chain().all_transactions();
if transactions.is_empty() { if transactions.is_empty() {
return 0; return 0;
} }
@ -1276,11 +1267,9 @@ impl ChainSync {
self.check_resume(io); self.check_resume(io);
} }
/// called when block is imported to chain, updates transactions queue and propagates the blocks /// called when block is imported to chain, updates transactions queue and propagates the blocks
pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { pub fn chain_new_blocks(&mut self, io: &mut SyncIo, _imported: &[H256], invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
if io.is_chain_queue_empty() { if io.is_chain_queue_empty() {
// Notify miner
self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted);
// Propagate latests blocks // Propagate latests blocks
self.propagate_latest_blocks(io); self.propagate_latest_blocks(io);
} }
@ -1289,10 +1278,6 @@ impl ChainSync {
self.restart_on_bad_block(io); self.restart_on_bad_block(io);
} }
} }
pub fn chain_new_head(&mut self, io: &mut SyncIo) {
self.miner.update_sealing(io.chain());
}
} }
#[cfg(test)] #[cfg(test)]
@ -1305,13 +1290,12 @@ mod tests {
use ethcore::views::BlockView; use ethcore::views::BlockView;
use ethcore::header::*; use ethcore::header::*;
use ethcore::client::*; use ethcore::client::*;
use ethcore::spec::Spec; use ethcore::miner::MinerService;
use ethminer::{Miner, MinerService};
fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes {
let mut header = Header::new(); let mut header = Header::new();
header.gas_limit = x!(0); header.gas_limit = 0.into();
header.difficulty = x!(order * 100); header.difficulty = (order * 100).into();
header.timestamp = (order * 10) as u64; header.timestamp = (order * 10) as u64;
header.number = order as u64; header.number = order as u64;
header.parent_hash = parent_hash; header.parent_hash = parent_hash;
@ -1327,7 +1311,7 @@ mod tests {
fn get_dummy_blocks(order: u32, parent_hash: H256) -> Bytes { fn get_dummy_blocks(order: u32, parent_hash: H256) -> Bytes {
let mut rlp = RlpStream::new_list(1); let mut rlp = RlpStream::new_list(1);
rlp.append_raw(&get_dummy_block(order, parent_hash), 1); rlp.append_raw(&get_dummy_block(order, parent_hash), 1);
let difficulty: U256 = x!(100 * order); let difficulty: U256 = (100 * order).into();
rlp.append(&difficulty); rlp.append(&difficulty);
rlp.out() rlp.out()
} }
@ -1480,7 +1464,7 @@ mod tests {
} }
fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync { fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync {
let mut sync = ChainSync::new(SyncConfig::default(), Miner::new(false, Spec::new_test()), client); let mut sync = ChainSync::new(SyncConfig::default(), client);
sync.peers.insert(0, sync.peers.insert(0,
PeerInfo { PeerInfo {
protocol_version: 0, protocol_version: 0,
@ -1711,9 +1695,10 @@ mod tests {
{ {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
let mut io = TestIo::new(&mut client, &mut queue, None); let mut io = TestIo::new(&mut client, &mut queue, None);
io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks);
sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks);
assert_eq!(sync.miner.status().transactions_in_future_queue, 0); assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0);
assert_eq!(sync.miner.status().transactions_in_pending_queue, 1); assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 1);
} }
// We need to update nonce status (because we say that the block has been imported) // We need to update nonce status (because we say that the block has been imported)
for h in &[good_blocks[0]] { for h in &[good_blocks[0]] {
@ -1724,11 +1709,12 @@ mod tests {
{ {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
let mut io = TestIo::new(&mut client, &mut queue, None); let mut io = TestIo::new(&mut client, &mut queue, None);
io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks);
sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks);
} }
// then // then
let status = sync.miner.status(); let status = client.miner.status();
assert_eq!(status.transactions_in_pending_queue, 1); assert_eq!(status.transactions_in_pending_queue, 1);
assert_eq!(status.transactions_in_future_queue, 0); assert_eq!(status.transactions_in_future_queue, 0);
} }
@ -1750,12 +1736,12 @@ mod tests {
// when // when
sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks);
assert_eq!(sync.miner.status().transactions_in_future_queue, 0); assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0);
assert_eq!(sync.miner.status().transactions_in_pending_queue, 0); assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 0);
sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks);
// then // then
let status = sync.miner.status(); let status = io.chain.miner.status();
assert_eq!(status.transactions_in_pending_queue, 0); assert_eq!(status.transactions_in_pending_queue, 0);
assert_eq!(status.transactions_in_future_queue, 0); assert_eq!(status.transactions_in_future_queue, 0);
} }

View File

@ -14,10 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use ethcore::client::BlockChainClient;
use util::{NetworkContext, PeerId, PacketId,}; use util::{NetworkContext, PeerId, PacketId,};
use util::error::UtilError; use util::error::UtilError;
use ethcore::service::SyncMessage; use ethcore::service::SyncMessage;
use ethcore::client::BlockChainClient;
/// IO interface for the syning handler. /// IO interface for the syning handler.
/// Provides peer connection management and an interface to the blockchain client. /// Provides peer connection management and an interface to the blockchain client.

View File

@ -32,21 +32,20 @@
//! extern crate ethcore_util as util; //! extern crate ethcore_util as util;
//! extern crate ethcore; //! extern crate ethcore;
//! extern crate ethsync; //! extern crate ethsync;
//! extern crate ethminer;
//! use std::env; //! use std::env;
//! use std::sync::Arc; //! use std::sync::Arc;
//! use util::network::{NetworkService, NetworkConfiguration}; //! use util::network::{NetworkService, NetworkConfiguration};
//! use ethcore::client::{Client, ClientConfig}; //! use ethcore::client::{Client, ClientConfig};
//! use ethsync::{EthSync, SyncConfig}; //! use ethsync::{EthSync, SyncConfig};
//! use ethminer::Miner;
//! use ethcore::ethereum; //! use ethcore::ethereum;
//! use ethcore::miner::Miner;
//! //!
//! fn main() { //! fn main() {
//! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap();
//! let dir = env::temp_dir(); //! let dir = env::temp_dir();
//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); //! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, Arc::new(Miner::default()), service.io().channel()).unwrap();
//! let miner = Miner::new(false, ethereum::new_frontier()); //! let miner = Miner::new(false, ethereum::new_frontier());
//! EthSync::register(&mut service, SyncConfig::default(), client, miner); //! EthSync::register(&mut service, SyncConfig::default(), client);
//! } //! }
//! ``` //! ```
@ -55,7 +54,6 @@ extern crate log;
#[macro_use] #[macro_use]
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate ethcore; extern crate ethcore;
extern crate ethminer;
extern crate env_logger; extern crate env_logger;
extern crate time; extern crate time;
extern crate rand; extern crate rand;
@ -69,7 +67,6 @@ use util::TimerToken;
use util::{U256, ONE_U256}; use util::{U256, ONE_U256};
use ethcore::client::Client; use ethcore::client::Client;
use ethcore::service::SyncMessage; use ethcore::service::SyncMessage;
use ethminer::Miner;
use io::NetSyncIo; use io::NetSyncIo;
use chain::ChainSync; use chain::ChainSync;
@ -115,8 +112,8 @@ pub use self::chain::{SyncStatus, SyncState};
impl EthSync { impl EthSync {
/// Creates and register protocol with the network service /// Creates and register protocol with the network service
pub fn register(service: &mut NetworkService<SyncMessage>, config: SyncConfig, chain: Arc<Client>, miner: Arc<Miner>) -> Arc<EthSync> { pub fn register(service: &mut NetworkService<SyncMessage>, config: SyncConfig, chain: Arc<Client>) -> Arc<EthSync> {
let sync = ChainSync::new(config, miner, chain.deref()); let sync = ChainSync::new(config, chain.deref());
let sync = Arc::new(EthSync { let sync = Arc::new(EthSync {
chain: chain, chain: chain,
sync: RwLock::new(sync), sync: RwLock::new(sync),
@ -171,10 +168,6 @@ impl NetworkProtocolHandler<SyncMessage> for EthSync {
let mut sync_io = NetSyncIo::new(io, self.chain.deref()); let mut sync_io = NetSyncIo::new(io, self.chain.deref());
self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted); self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted);
}, },
SyncMessage::NewChainHead => {
let mut sync_io = NetSyncIo::new(io, self.chain.deref());
self.sync.write().unwrap().chain_new_head(&mut sync_io);
},
_ => {/* Ignore other messages */}, _ => {/* Ignore other messages */},
} }
} }

View File

@ -16,10 +16,8 @@
use util::*; use util::*;
use ethcore::client::{TestBlockChainClient, BlockChainClient}; use ethcore::client::{TestBlockChainClient, BlockChainClient};
use ethcore::spec::Spec;
use io::SyncIo; use io::SyncIo;
use chain::ChainSync; use chain::ChainSync;
use ethminer::Miner;
use ::SyncConfig; use ::SyncConfig;
pub struct TestIo<'p> { pub struct TestIo<'p> {
@ -93,7 +91,7 @@ impl TestNet {
}; };
for _ in 0..n { for _ in 0..n {
let chain = TestBlockChainClient::new(); let chain = TestBlockChainClient::new();
let sync = ChainSync::new(SyncConfig::default(), Miner::new(false, Spec::new_test()), &chain); let sync = ChainSync::new(SyncConfig::default(), &chain);
net.peers.push(TestPeer { net.peers.push(TestPeer {
sync: sync, sync: sync,
chain: chain, chain: chain,

View File

@ -10,5 +10,4 @@ cargo test --features ethcore/json-tests $1 \
-p ethcore-signer \ -p ethcore-signer \
-p ethcore-dapps \ -p ethcore-dapps \
-p parity \ -p parity \
-p ethminer \
-p bigint -p bigint

View File

@ -25,52 +25,58 @@ pub use numbers::*;
pub use sha3::*; pub use sha3::*;
#[macro_export] #[macro_export]
macro_rules! hash_map { macro_rules! vec_into {
( $( $x:expr => $y:expr ),* ) => { ( $( $x:expr ),* ) => {
vec![ $( ($x, $y) ),* ].into_iter().collect::<HashMap<_, _>>() vec![ $( $x.into() ),* ]
} }
} }
#[macro_export] #[macro_export]
macro_rules! hash_mapx { macro_rules! hash_map {
( $( $x:expr => $y:expr ),* ) => { () => { HashMap::new() };
vec![ $( ( From::from($x), From::from($y) ) ),* ].into_iter().collect::<HashMap<_, _>>() ( $( $x:expr => $y:expr ),* ) => {{
} let mut x = HashMap::new();
$(
x.insert($x, $y);
)*
x
}}
}
#[macro_export]
macro_rules! hash_map_into {
() => { HashMap::new() };
( $( $x:expr => $y:expr ),* ) => {{
let mut x = HashMap::new();
$(
x.insert($x.into(), $y.into());
)*
x
}}
} }
#[macro_export] #[macro_export]
macro_rules! map { macro_rules! map {
( $( $x:expr => $y:expr ),* ) => { () => { BTreeMap::new() };
vec![ $( ($x, $y) ),* ].into_iter().collect::<BTreeMap<_, _>>() ( $( $x:expr => $y:expr ),* ) => {{
} let mut x = BTreeMap::new();
$(
x.insert($x, $y);
)*
x
}}
} }
#[macro_export] #[macro_export]
macro_rules! mapx { macro_rules! map_into {
( $( $x:expr => $y:expr ),* ) => { () => { BTreeMap::new() };
vec![ $( ( From::from($x), From::from($y) ) ),* ].into_iter().collect::<BTreeMap<_, _>>() ( $( $x:expr => $y:expr ),* ) => {{
} let mut x = BTreeMap::new();
} $(
x.insert($x.into(), $y.into());
#[macro_export] )*
macro_rules! vecx { x
( $( $x:expr ),* ) => { }}
vec![ $( From::from($x) ),* ]
}
}
#[macro_export]
macro_rules! x {
( $x:expr ) => {
From::from($x)
}
}
#[macro_export]
macro_rules! xx {
( $x:expr ) => {
From::from(From::from($x))
}
} }
#[macro_export] #[macro_export]

View File

@ -718,7 +718,7 @@ mod tests {
#[test] #[test]
fn from_and_to_u256() { fn from_and_to_u256() {
let u: U256 = x!(0x123456789abcdef0u64); let u: U256 = 0x123456789abcdef0u64.into();
let h = H256::from(u); let h = H256::from(u);
assert_eq!(H256::from(u), H256::from("000000000000000000000000000000000000000000000000123456789abcdef0")); assert_eq!(H256::from(u), H256::from("000000000000000000000000000000000000000000000000123456789abcdef0"));
let h_ref = H256::from(&u); let h_ref = H256::from(&u);

View File

@ -48,7 +48,7 @@ impl FromJson for Bytes {
impl FromJson for BTreeMap<H256, H256> { impl FromJson for BTreeMap<H256, H256> {
fn from_json(json: &Json) -> Self { fn from_json(json: &Json) -> Self {
match *json { match *json {
Json::Object(ref o) => o.iter().map(|(key, value)| (x!(&u256_from_str(key)), x!(&U256::from_json(value)))).collect(), Json::Object(ref o) => o.iter().map(|(key, value)| (u256_from_str(key).into(), U256::from_json(value).into())).collect(),
_ => BTreeMap::new(), _ => BTreeMap::new(),
} }
} }

View File

@ -87,7 +87,7 @@ struct AccountUnlock {
} }
/// Basic account management trait /// Basic account management trait
pub trait AccountProvider : Send + Sync { pub trait AccountProvider: Send + Sync {
/// Lists all accounts /// Lists all accounts
fn accounts(&self) -> Result<Vec<Address>, ::std::io::Error>; fn accounts(&self) -> Result<Vec<Address>, ::std::io::Error>;
/// Unlocks account with the password provided /// Unlocks account with the password provided
@ -325,7 +325,7 @@ impl SecretStore {
ret ret
} }
/// Returns secret for unlocked account. /// Returns secret for locked account.
pub fn locked_account_secret(&self, account: &Address, pass: &str) -> Result<crypto::Secret, SigningError> { pub fn locked_account_secret(&self, account: &Address, pass: &str) -> Result<crypto::Secret, SigningError> {
let secret_id = try!(self.account(&account).ok_or(SigningError::NoAccount)); let secret_id = try!(self.account(&account).ok_or(SigningError::NoAccount));
self.get(&secret_id, pass).or_else(|e| Err(match e { self.get(&secret_id, pass).or_else(|e| Err(match e {
@ -554,7 +554,7 @@ mod tests {
H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(),
262144, 262144,
32)); 32));
key_file.account = Some(x!(i as u64)); key_file.account = Some((i as u64).into());
result.push(key_file.id.clone()); result.push(key_file.id.clone());
write_sstore.import_key(key_file).unwrap(); write_sstore.import_key(key_file).unwrap();
} }
@ -627,7 +627,7 @@ mod tests {
sstore.sign(&address, &H256::random()).unwrap() sstore.sign(&address, &H256::random()).unwrap()
}; };
assert!(signature != x!(0)); assert!(signature != 0.into());
} }
#[test] #[test]