Merge with master
This commit is contained in:
parent
3850ee64bb
commit
49024a4f28
@ -33,10 +33,10 @@ 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 ethjson -p ethcore-dapps -p ethcore-signer"
|
- TARGETS="-p ethkey -p ethstore -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,ethstore/tests target/kcov"
|
||||||
- RUN_TESTS="false"
|
- RUN_TESTS="false"
|
||||||
- RUN_COVERAGE="false"
|
- RUN_COVERAGE="false"
|
||||||
- RUN_BUILD="false"
|
- RUN_BUILD="false"
|
||||||
@ -65,6 +65,8 @@ after_success: |
|
|||||||
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
||||||
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
|
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
|
||||||
cargo test --no-run ${KCOV_FEATURES} ${TARGETS} &&
|
cargo test --no-run ${KCOV_FEATURES} ${TARGETS} &&
|
||||||
|
$KCOV_CMD target/debug/deps/ethkey-* &&
|
||||||
|
$KCOV_CMD target/debug/deps/ethstore-* &&
|
||||||
$KCOV_CMD target/debug/deps/ethcore_util-* &&
|
$KCOV_CMD target/debug/deps/ethcore_util-* &&
|
||||||
$KCOV_CMD target/debug/deps/ethash-* &&
|
$KCOV_CMD target/debug/deps/ethash-* &&
|
||||||
$KCOV_CMD target/debug/deps/ethcore-* &&
|
$KCOV_CMD target/debug/deps/ethcore-* &&
|
||||||
|
350
Cargo.lock
generated
350
Cargo.lock
generated
@ -1,26 +1,26 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "parity"
|
name = "parity"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clippy 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)",
|
"ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)",
|
||||||
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"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.3.0",
|
||||||
"ethcore-dapps 1.2.0",
|
"ethcore-dapps 1.3.0",
|
||||||
"ethcore-devtools 1.2.0",
|
"ethcore-devtools 1.3.0",
|
||||||
"ethcore-ipc 1.2.0",
|
"ethcore-ipc 1.3.0",
|
||||||
"ethcore-ipc-codegen 1.2.0",
|
"ethcore-ipc-codegen 1.3.0",
|
||||||
"ethcore-ipc-nano 1.2.0",
|
"ethcore-ipc-nano 1.3.0",
|
||||||
"ethcore-rpc 1.2.0",
|
"ethcore-rpc 1.3.0",
|
||||||
"ethcore-signer 1.2.0",
|
"ethcore-signer 1.3.0",
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.0",
|
||||||
"ethsync 1.2.0",
|
"ethsync 1.3.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)",
|
||||||
"json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)",
|
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
|
||||||
"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)",
|
||||||
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -30,6 +30,7 @@ dependencies = [
|
|||||||
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -66,12 +67,10 @@ dependencies = [
|
|||||||
name = "bigint"
|
name = "bigint"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"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)",
|
||||||
"rand 0.3.14 (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)",
|
||||||
"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.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -130,15 +129,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy"
|
name = "clippy"
|
||||||
version = "0.0.76"
|
version = "0.0.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clippy_lints 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy_lints 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy_lints"
|
name = "clippy_lints"
|
||||||
version = "0.0.76"
|
version = "0.0.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -165,7 +164,7 @@ version = "0.2.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -179,7 +178,7 @@ version = "1.1.1"
|
|||||||
source = "git+https://github.com/ethcore/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48"
|
source = "git+https://github.com/ethcore/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -188,7 +187,7 @@ name = "daemonize"
|
|||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -230,16 +229,16 @@ source = "git+https://github.com/ethcore/rust-secp256k1#b6fdd43bbcf6d46adb72a92d
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (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)",
|
||||||
"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)",
|
||||||
"serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethash"
|
name = "ethash"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"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)",
|
||||||
"primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -248,24 +247,25 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore"
|
name = "ethcore"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clippy 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"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)",
|
||||||
"ethash 1.2.0",
|
"ethash 1.3.0",
|
||||||
"ethcore-devtools 1.2.0",
|
"ethcore-devtools 1.3.0",
|
||||||
"ethcore-ipc 1.2.0",
|
"ethcore-ipc 1.3.0",
|
||||||
"ethcore-ipc-codegen 1.2.0",
|
"ethcore-ipc-codegen 1.3.0",
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
|
"ethstore 0.1.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)",
|
||||||
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (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)",
|
"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.36 (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.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -273,50 +273,48 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-dapps"
|
name = "ethcore-dapps"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clippy 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore-rpc 1.2.0",
|
"ethcore-rpc 1.3.0",
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.0",
|
||||||
"hyper 0.9.3 (git+https://github.com/ethcore/hyper)",
|
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
|
||||||
"jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
|
"jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
|
||||||
"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)",
|
||||||
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
||||||
"parity-dapps-builtins 0.5.1 (git+https://github.com/ethcore/parity-dapps-builtins-rs.git)",
|
"parity-dapps-builtins 0.5.1 (git+https://github.com/ethcore/parity-dapps-builtins-rs.git)",
|
||||||
"parity-dapps-dao 0.4.0 (git+https://github.com/ethcore/parity-dapps-dao-rs.git)",
|
|
||||||
"parity-dapps-makerotc 0.3.0 (git+https://github.com/ethcore/parity-dapps-makerotc-rs.git)",
|
|
||||||
"parity-dapps-status 0.5.0 (git+https://github.com/ethcore/parity-dapps-status-rs.git)",
|
"parity-dapps-status 0.5.0 (git+https://github.com/ethcore/parity-dapps-status-rs.git)",
|
||||||
"parity-dapps-wallet 0.6.1 (git+https://github.com/ethcore/parity-dapps-wallet-rs.git)",
|
"parity-dapps-wallet 0.6.1 (git+https://github.com/ethcore/parity-dapps-wallet-rs.git)",
|
||||||
"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)",
|
||||||
"serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-devtools"
|
name = "ethcore-devtools"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-ipc"
|
name = "ethcore-ipc"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-devtools 1.2.0",
|
"ethcore-devtools 1.3.0",
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.0",
|
||||||
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-ipc-codegen"
|
name = "ethcore-ipc-codegen"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quasi 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quasi 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -327,32 +325,32 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-ipc-nano"
|
name = "ethcore-ipc-nano"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-ipc 1.2.0",
|
"ethcore-ipc 1.3.0",
|
||||||
"jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.7 (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)",
|
||||||
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-rpc"
|
name = "ethcore-rpc"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clippy 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethash 1.2.0",
|
"ethash 1.3.0",
|
||||||
"ethcore 1.2.0",
|
"ethcore 1.3.0",
|
||||||
"ethcore-devtools 1.2.0",
|
"ethcore-devtools 1.3.0",
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"ethsync 1.2.0",
|
"ethsync 1.3.0",
|
||||||
"json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)",
|
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
|
||||||
"jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
|
"jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
|
||||||
"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-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -360,48 +358,48 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-signer"
|
name = "ethcore-signer"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clippy 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"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-rpc 1.2.0",
|
"ethcore-rpc 1.3.0",
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.0",
|
||||||
"jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.7 (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)",
|
||||||
"parity-minimal-sysui 0.1.0 (git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git)",
|
"parity-minimal-sysui 0.2.0 (git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git)",
|
||||||
"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)",
|
||||||
"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)",
|
||||||
"ws 0.4.6 (git+https://github.com/ethcore/ws-rs.git)",
|
"ws 0.5.0 (git+https://github.com/ethcore/ws-rs.git?branch=stable)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-util"
|
name = "ethcore-util"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bigint 0.1.0",
|
"bigint 0.1.0",
|
||||||
"chrono 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clippy 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
|
"eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
|
||||||
"ethcore-devtools 1.2.0",
|
"ethcore-devtools 1.3.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)",
|
||||||
"igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"json-tests 0.1.0",
|
"json-tests 0.1.0",
|
||||||
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (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)",
|
||||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
|
||||||
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.5.0 (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)",
|
||||||
"rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)",
|
"rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)",
|
||||||
"rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-crypto 0.2.36 (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)",
|
||||||
"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.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sha3 0.1.0",
|
"sha3 0.1.0",
|
||||||
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -414,22 +412,49 @@ dependencies = [
|
|||||||
name = "ethjson"
|
name = "ethjson"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.0",
|
||||||
"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)",
|
||||||
"serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethsync"
|
name = "ethkey"
|
||||||
version = "1.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clippy 0.0.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
"eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
|
||||||
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ethstore"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ethkey 0.2.0",
|
||||||
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ethsync"
|
||||||
|
version = "1.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"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.3.0",
|
||||||
"ethcore-util 1.2.0",
|
"ethcore-util 1.3.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)",
|
||||||
@ -440,7 +465,7 @@ dependencies = [
|
|||||||
name = "fdlimit"
|
name = "fdlimit"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -521,23 +546,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.9.3"
|
version = "0.9.4"
|
||||||
source = "git+https://github.com/ethcore/hyper#dbb4cf160ebf242f7f0459d547c40e9e6877ccf4"
|
source = "git+https://github.com/ethcore/hyper#7ccfcb2aa7e6aa6300efa8cebd6a0e6ce55582ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"language-tags 0.2.2 (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)",
|
||||||
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rotor 0.6.3 (git+https://github.com/ethcore/rotor)",
|
||||||
"rotor 0.6.3 (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)",
|
||||||
"spmc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"spmc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -570,12 +594,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "json-ipc-server"
|
name = "json-ipc-server"
|
||||||
version = "0.1.0"
|
version = "0.2.4"
|
||||||
source = "git+https://github.com/ethcore/json-ipc-server.git#4f9226c4f84dcce2385a188374e3b5fc66b63e68"
|
source = "git+https://github.com/ethcore/json-ipc-server.git#902b031b8f50a59ecb4f389cbec1d264a98556bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -589,11 +617,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-core"
|
name = "jsonrpc-core"
|
||||||
version = "2.0.5"
|
version = "2.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -601,10 +629,10 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-http-server"
|
name = "jsonrpc-http-server"
|
||||||
version = "5.1.0"
|
version = "5.1.0"
|
||||||
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#6117b1d77b5a60d6fa2dc884f12aa7f5fd4585ca"
|
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#e59c2fbaca499620874023755cb91f05b858ffe7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper 0.9.3 (git+https://github.com/ethcore/hyper)",
|
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
|
||||||
"jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -629,17 +657,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "0.1.16"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.1.12"
|
version = "0.2.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -657,7 +680,7 @@ name = "memchr"
|
|||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -690,15 +713,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
source = "git+https://github.com/carllerche/mio.git#f4aa49a9d2c4507fb33a4533d5238e0365f67c99"
|
source = "git+https://github.com/ethcore/mio?branch=v0.5.x#3842d3b250ffd7bd9b16f9586b875ddcbac2b0dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (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)",
|
||||||
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nix 0.5.0-pre (git+https://github.com/carllerche/nix-rust?rev=c4257f8a76)",
|
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -710,7 +733,7 @@ version = "0.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (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)",
|
||||||
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -736,7 +759,7 @@ name = "nanomsg"
|
|||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
|
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -746,7 +769,7 @@ version = "0.5.0"
|
|||||||
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
|
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -756,27 +779,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.5.0-pre"
|
|
||||||
source = "git+https://github.com/carllerche/nix-rust?rev=c4257f8a76#c4257f8a76b69b0d2e9a001d83e4bef67c03b23f"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -863,7 +877,7 @@ name = "num_cpus"
|
|||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -882,7 +896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-dapps"
|
name = "parity-dapps"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/ethcore/parity-dapps-rs.git#1f065d93aa49338e4a453c77c839957f2db78895"
|
source = "git+https://github.com/ethcore/parity-dapps-rs.git#8cc812c26c903cf5764ce0f4cc3f2a7c3ddb0dc2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -896,23 +910,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-dapps-builtins"
|
name = "parity-dapps-builtins"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "git+https://github.com/ethcore/parity-dapps-builtins-rs.git#b3970ff4686a12321365cfafba6552bfaa2e7874"
|
source = "git+https://github.com/ethcore/parity-dapps-builtins-rs.git#7408838e8ca3b57c6b0cf5da2e31e0e275959955"
|
||||||
dependencies = [
|
|
||||||
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parity-dapps-dao"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "git+https://github.com/ethcore/parity-dapps-dao-rs.git#dd6b9ca7c18fbfa714183a4f570bd75b8391c13d"
|
|
||||||
dependencies = [
|
|
||||||
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parity-dapps-makerotc"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "git+https://github.com/ethcore/parity-dapps-makerotc-rs.git#33568ac7209aa765c498bb2322e848f552656303"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
||||||
]
|
]
|
||||||
@ -920,7 +918,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-dapps-status"
|
name = "parity-dapps-status"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/ethcore/parity-dapps-status-rs.git#53e159f52013be5d2e8ba7eca35f605ad6e3bfa9"
|
source = "git+https://github.com/ethcore/parity-dapps-status-rs.git#0cdd3512004e403aff7da3b8c16ba0bf5d6c911c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
||||||
]
|
]
|
||||||
@ -928,15 +926,15 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-dapps-wallet"
|
name = "parity-dapps-wallet"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
source = "git+https://github.com/ethcore/parity-dapps-wallet-rs.git#8923d4c73359c75ce04f0639bbcde46adb846b81"
|
source = "git+https://github.com/ethcore/parity-dapps-wallet-rs.git#867994fe25038f000f1cc09cd024a83700a03930"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-minimal-sysui"
|
name = "parity-minimal-sysui"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git#4c704913f671060bb0e43b5ce4a68d02281115d5"
|
source = "git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git#996c9f3f0ebedc727aecb4ece191154e956ae292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
@ -1033,7 +1031,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "0.2.2"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1046,7 +1044,7 @@ name = "rand"
|
|||||||
version = "0.3.14"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1079,30 +1077,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rocksdb"
|
name = "rocksdb"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
source = "git+https://github.com/ethcore/rust-rocksdb#8f6e43b2d8799578a378648bcb17c01fb431dbec"
|
source = "git+https://github.com/ethcore/rust-rocksdb#9be41e05923616dfa28741c58b22776d479751e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
|
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rocksdb-sys"
|
name = "rocksdb-sys"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/ethcore/rust-rocksdb#8f6e43b2d8799578a378648bcb17c01fb431dbec"
|
source = "git+https://github.com/ethcore/rust-rocksdb#9be41e05923616dfa28741c58b22776d479751e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rotor"
|
name = "rotor"
|
||||||
version = "0.6.3"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/ethcore/rotor#e63d45137b2eb66d1e085a7c6321a5db8b187576"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"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)",
|
||||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
|
||||||
"quick-error 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1112,18 +1109,18 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-crypto"
|
name = "rust-crypto"
|
||||||
version = "0.2.35"
|
version = "0.2.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (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)",
|
||||||
"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)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1165,12 +1162,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "0.7.7"
|
version = "0.7.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_codegen"
|
name = "serde_codegen"
|
||||||
version = "0.7.7"
|
version = "0.7.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1186,7 +1183,7 @@ version = "0.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1247,7 +1244,7 @@ version = "0.33.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (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-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1273,7 +1270,7 @@ name = "termios"
|
|||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1282,7 +1279,7 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1299,7 +1296,7 @@ version = "0.1.35"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1384,7 +1381,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "1.0.0"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1448,16 +1445,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ws"
|
name = "ws"
|
||||||
version = "0.4.6"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/ethcore/ws-rs.git#5b28de58421b017b01f4565b2c35a46679707789"
|
source = "git+https://github.com/ethcore/ws-rs.git?branch=stable#a876fc115c3ef50a17c8822c9bd2f6e94473e005"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"httparse 1.1.2 (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)",
|
||||||
"mio 0.5.0 (git+https://github.com/carllerche/mio.git)",
|
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
|
||||||
"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)",
|
||||||
"sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
11
Cargo.toml
11
Cargo.toml
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Ethcore client."
|
description = "Ethcore client."
|
||||||
name = "parity"
|
name = "parity"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["Ethcore <admin@ethcore.io>"]
|
authors = ["Ethcore <admin@ethcore.io>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@ -19,11 +19,10 @@ docopt = "0.6"
|
|||||||
time = "0.1"
|
time = "0.1"
|
||||||
ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" }
|
ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" }
|
||||||
fdlimit = { path = "util/fdlimit" }
|
fdlimit = { path = "util/fdlimit" }
|
||||||
daemonize = "0.2"
|
|
||||||
num_cpus = "0.2"
|
num_cpus = "0.2"
|
||||||
number_prefix = "0.2"
|
number_prefix = "0.2"
|
||||||
rpassword = "0.2.1"
|
rpassword = "0.2.1"
|
||||||
clippy = { version = "0.0.76", optional = true}
|
clippy = { version = "0.0.77", optional = true}
|
||||||
ethcore = { path = "ethcore" }
|
ethcore = { path = "ethcore" }
|
||||||
ethcore-util = { path = "util" }
|
ethcore-util = { path = "util" }
|
||||||
ethsync = { path = "sync" }
|
ethsync = { path = "sync" }
|
||||||
@ -37,6 +36,12 @@ ethcore-ipc = { path = "ipc/rpc" }
|
|||||||
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
|
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
|
||||||
ansi_term = "0.7"
|
ansi_term = "0.7"
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
winapi = "0.2"
|
||||||
|
|
||||||
|
[target.'cfg(not(windows))'.dependencies]
|
||||||
|
daemonize = "0.2"
|
||||||
|
|
||||||
[dependencies.hyper]
|
[dependencies.hyper]
|
||||||
version = "0.8"
|
version = "0.8"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
39
README.md
39
README.md
@ -31,29 +31,43 @@ In a near-future release, it will be easy to install Dapps and use them through
|
|||||||
If you run into an issue while using parity, feel free to file one in this repository
|
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!
|
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
|
Parity's current release is 1.2. You can download it at https://ethcore.io/parity.html or follow the instructions
|
||||||
below to build from source.
|
below to build from source.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Building from source
|
## Build dependencies
|
||||||
|
|
||||||
Parity is fully compatible with Stable Rust.
|
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:
|
We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this:
|
||||||
|
|
||||||
- Linux:
|
- Linux and OSX:
|
||||||
```bash
|
```bash
|
||||||
$ curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sh
|
$ curl https://sh.rustup.rs -sSf | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
- OSX with Homebrew:
|
- Windows
|
||||||
```bash
|
|
||||||
$ brew update && brew install multirust
|
Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from
|
||||||
$ multirust default stable
|
https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe, start "VS2015 x64 Native Tools Command Prompt", and use the following command to install and set up the msvc toolchain:
|
||||||
|
```
|
||||||
|
$ rustup default stable-x86_64-pc-windows-msvc
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, download and build Parity:
|
Once you have rustup, install parity or download and build from source
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Quick install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo install --git https://github.com/ethcore/parity.git parity
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Build from source
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# download Parity code
|
# download Parity code
|
||||||
@ -64,12 +78,11 @@ $ cd parity
|
|||||||
$ cargo build --release
|
$ cargo build --release
|
||||||
```
|
```
|
||||||
|
|
||||||
This will produce an executable in the `target/release` subdirectory.
|
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
|
To get started, just run
|
||||||
```bash
|
```bash
|
||||||
$ parity
|
$ ./target/release/parity
|
||||||
```
|
```
|
||||||
|
|
||||||
and parity will begin syncing the Ethereum blockchain.
|
and parity will begin syncing the Ethereum blockchain.
|
46
appveyor.yml
Normal file
46
appveyor.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- TARGET: x86_64-pc-windows-msvc
|
||||||
|
cert:
|
||||||
|
secure: ESPpYVVAMG1fbJx6kq4ct/g9SQTXac4Hs6xXr6Oh4Zrk2dwYglNjxmzErdPnvu7gs/gekzrJ6KEQHYRc+5+4dKg6rRADQ681NLVx9vOggBs=
|
||||||
|
certpass:
|
||||||
|
secure: 0BgXJqxq9Ei34/hZ7121FQ==
|
||||||
|
keyfile: C:\users\appveyor\Certificates.p12
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- /^beta-.*$/
|
||||||
|
- /^stable-.*$/
|
||||||
|
- /^beta$/
|
||||||
|
- /^stable$/
|
||||||
|
|
||||||
|
install:
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-x86_64-pc-windows-msvc.exe"
|
||||||
|
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -FileName nsis\SimpleFC.dll
|
||||||
|
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe
|
||||||
|
- rust-1.9.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||||
|
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin
|
||||||
|
- rustc -V
|
||||||
|
- cargo -V
|
||||||
|
|
||||||
|
build: off
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- cargo test --verbose --release
|
||||||
|
|
||||||
|
after_test:
|
||||||
|
- cargo build --verbose --release
|
||||||
|
- ps: if($env:cert) { Start-FileDownload $env:cert -FileName $env:keyfile }
|
||||||
|
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass target\release\parity.exe }
|
||||||
|
- makensis.exe nsis\installer.nsi
|
||||||
|
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass nsis\installer.exe }
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
- path: nsis\installer.exe
|
||||||
|
name: Windows Installer (x86_64)
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- target
|
||||||
|
- C:\users\appveyor\.cargo -> appveyor.yml
|
6
cov.sh
6
cov.sh
@ -16,6 +16,8 @@ if ! type kcov > /dev/null; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cargo test \
|
cargo test \
|
||||||
|
-p ethkey \
|
||||||
|
-p ethstore \
|
||||||
-p ethash \
|
-p ethash \
|
||||||
-p ethcore-util \
|
-p ethcore-util \
|
||||||
-p ethcore \
|
-p ethcore \
|
||||||
@ -28,7 +30,9 @@ cargo test \
|
|||||||
rm -rf target/coverage
|
rm -rf target/coverage
|
||||||
mkdir -p target/coverage
|
mkdir -p target/coverage
|
||||||
|
|
||||||
EXCLUDE="~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests"
|
EXCLUDE="~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests,ethstore/tests"
|
||||||
|
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethkey-*
|
||||||
|
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethstore-*
|
||||||
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore-*
|
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore-*
|
||||||
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethash-*
|
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethash-*
|
||||||
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-*
|
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Parity Dapps crate"
|
description = "Parity Dapps crate"
|
||||||
name = "ethcore-dapps"
|
name = "ethcore-dapps"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["Ethcore <admin@ethcore.io"]
|
authors = ["Ethcore <admin@ethcore.io"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@ -28,7 +28,7 @@ parity-dapps-wallet = { git = "https://github.com/ethcore/parity-dapps-wallet-rs
|
|||||||
parity-dapps-dao = { git = "https://github.com/ethcore/parity-dapps-dao-rs.git", version = "0.4.0", optional = true }
|
parity-dapps-dao = { git = "https://github.com/ethcore/parity-dapps-dao-rs.git", version = "0.4.0", optional = true }
|
||||||
parity-dapps-makerotc = { git = "https://github.com/ethcore/parity-dapps-makerotc-rs.git", version = "0.3.0", optional = true }
|
parity-dapps-makerotc = { git = "https://github.com/ethcore/parity-dapps-makerotc-rs.git", version = "0.3.0", optional = true }
|
||||||
mime_guess = { version = "1.6.1" }
|
mime_guess = { version = "1.6.1" }
|
||||||
clippy = { version = "0.0.76", optional = true}
|
clippy = { version = "0.0.77", optional = true}
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
serde_codegen = { version = "0.7.0", optional = true }
|
serde_codegen = { version = "0.7.0", optional = true }
|
||||||
@ -36,6 +36,6 @@ syntex = "*"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["serde_codegen", "extra-dapps"]
|
default = ["serde_codegen", "extra-dapps"]
|
||||||
extra-dapps = ["parity-dapps-wallet", "parity-dapps-dao", "parity-dapps-makerotc"]
|
extra-dapps = ["parity-dapps-wallet"]
|
||||||
nightly = ["serde_macros"]
|
nightly = ["serde_macros"]
|
||||||
dev = ["clippy", "ethcore-rpc/dev", "ethcore-util/dev"]
|
dev = ["clippy", "ethcore-rpc/dev", "ethcore-util/dev"]
|
||||||
|
@ -42,11 +42,11 @@ pub struct EndpointInfo {
|
|||||||
pub trait Endpoint : Send + Sync {
|
pub trait Endpoint : Send + Sync {
|
||||||
fn info(&self) -> Option<&EndpointInfo> { None }
|
fn info(&self) -> Option<&EndpointInfo> { None }
|
||||||
|
|
||||||
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream>>;
|
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream> + Send>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
|
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
|
||||||
pub type Handler = server::Handler<HttpStream>;
|
pub type Handler = server::Handler<HttpStream> + Send;
|
||||||
|
|
||||||
pub struct ContentHandler {
|
pub struct ContentHandler {
|
||||||
content: String,
|
content: String,
|
||||||
@ -65,7 +65,7 @@ impl ContentHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for ContentHandler {
|
impl server::Handler<HttpStream> for ContentHandler {
|
||||||
fn on_request(&mut self, _request: server::Request) -> Next {
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
Next::write()
|
Next::write()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,9 +132,16 @@ impl Server {
|
|||||||
special.clone(),
|
special.clone(),
|
||||||
authorization.clone(),
|
authorization.clone(),
|
||||||
))
|
))
|
||||||
.map(|l| Server {
|
.map(|(l, srv)| {
|
||||||
|
|
||||||
|
::std::thread::spawn(move || {
|
||||||
|
srv.run();
|
||||||
|
});
|
||||||
|
|
||||||
|
Server {
|
||||||
server: Some(l),
|
server: Some(l),
|
||||||
panic_handler: panic_handler,
|
panic_handler: panic_handler,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.map_err(ServerError::from)
|
.map_err(ServerError::from)
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ impl<T: Dapp> PageHandler<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
|
impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
|
||||||
fn on_request(&mut self, req: server::Request) -> Next {
|
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
|
||||||
self.file = match *req.uri() {
|
self.file = match *req.uri() {
|
||||||
RequestUri::AbsolutePath(ref path) => {
|
RequestUri::AbsolutePath(ref path) => {
|
||||||
self.app.file(&self.extract_path(path))
|
self.app.file(&self.extract_path(path))
|
||||||
|
@ -27,13 +27,13 @@ pub enum Authorized {
|
|||||||
/// Authorization was successful.
|
/// Authorization was successful.
|
||||||
Yes,
|
Yes,
|
||||||
/// Unsuccessful authorization. Handler for further work is returned.
|
/// Unsuccessful authorization. Handler for further work is returned.
|
||||||
No(Box<server::Handler<HttpStream>>),
|
No(Box<server::Handler<HttpStream> + Send>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authorization interface
|
/// Authorization interface
|
||||||
pub trait Authorization : Send + Sync {
|
pub trait Authorization : Send + Sync {
|
||||||
/// Checks if authorization is valid.
|
/// Checks if authorization is valid.
|
||||||
fn is_authorized(&self, req: &server::Request)-> Authorized;
|
fn is_authorized(&self, req: &server::Request<HttpStream>)-> Authorized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HTTP Basic Authorization handler
|
/// HTTP Basic Authorization handler
|
||||||
@ -45,13 +45,13 @@ pub struct HttpBasicAuth {
|
|||||||
pub struct NoAuth;
|
pub struct NoAuth;
|
||||||
|
|
||||||
impl Authorization for NoAuth {
|
impl Authorization for NoAuth {
|
||||||
fn is_authorized(&self, _req: &server::Request)-> Authorized {
|
fn is_authorized(&self, _req: &server::Request<HttpStream>)-> Authorized {
|
||||||
Authorized::Yes
|
Authorized::Yes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Authorization for HttpBasicAuth {
|
impl Authorization for HttpBasicAuth {
|
||||||
fn is_authorized(&self, req: &server::Request) -> Authorized {
|
fn is_authorized(&self, req: &server::Request<HttpStream>) -> Authorized {
|
||||||
let auth = self.check_auth(&req);
|
let auth = self.check_auth(&req);
|
||||||
|
|
||||||
match auth {
|
match auth {
|
||||||
@ -89,7 +89,7 @@ impl HttpBasicAuth {
|
|||||||
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
|
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_auth(&self, req: &server::Request) -> Access {
|
fn check_auth(&self, req: &server::Request<HttpStream>) -> Access {
|
||||||
match req.headers().get::<header::Authorization<header::Basic>>() {
|
match req.headers().get::<header::Authorization<header::Basic>>() {
|
||||||
Some(&header::Authorization(
|
Some(&header::Authorization(
|
||||||
header::Basic { ref username, password: Some(ref password) }
|
header::Basic { ref username, password: Some(ref password) }
|
||||||
@ -105,7 +105,7 @@ pub struct UnauthorizedHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for UnauthorizedHandler {
|
impl server::Handler<HttpStream> for UnauthorizedHandler {
|
||||||
fn on_request(&mut self, _request: server::Request) -> Next {
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
Next::write()
|
Next::write()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ impl server::Handler<HttpStream> for UnauthorizedHandler {
|
|||||||
pub struct AuthRequiredHandler;
|
pub struct AuthRequiredHandler;
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for AuthRequiredHandler {
|
impl server::Handler<HttpStream> for AuthRequiredHandler {
|
||||||
fn on_request(&mut self, _request: server::Request) -> Next {
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
Next::write()
|
Next::write()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,12 +49,12 @@ pub struct Router<A: Authorization + 'static> {
|
|||||||
endpoints: Arc<Endpoints>,
|
endpoints: Arc<Endpoints>,
|
||||||
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
|
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
|
||||||
authorization: Arc<A>,
|
authorization: Arc<A>,
|
||||||
handler: Box<server::Handler<HttpStream>>,
|
handler: Box<server::Handler<HttpStream> + Send>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
|
impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
|
||||||
|
|
||||||
fn on_request(&mut self, req: server::Request) -> Next {
|
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
|
||||||
// Check authorization
|
// Check authorization
|
||||||
let auth = self.authorization.is_authorized(&req);
|
let auth = self.authorization.is_authorized(&req);
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ impl<A: Authorization> Router<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_url(req: &server::Request) -> Option<Url> {
|
fn extract_url(req: &server::Request<HttpStream>) -> Option<Url> {
|
||||||
match *req.uri() {
|
match *req.uri() {
|
||||||
uri::RequestUri::AbsoluteUri(ref url) => {
|
uri::RequestUri::AbsoluteUri(ref url) => {
|
||||||
match Url::from_generic_url(url.clone()) {
|
match Url::from_generic_url(url.clone()) {
|
||||||
|
@ -33,7 +33,7 @@ impl Redirection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for Redirection {
|
impl server::Handler<HttpStream> for Redirection {
|
||||||
fn on_request(&mut self, _request: server::Request) -> Next {
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
Next::write()
|
Next::write()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ description = "Ethcore Database"
|
|||||||
homepage = "http://ethcore.io"
|
homepage = "http://ethcore.io"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
name = "ethcore-db"
|
name = "ethcore-db"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
authors = ["Ethcore <admin@ethcore.io>"]
|
authors = ["Ethcore <admin@ethcore.io>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ syntex = "*"
|
|||||||
ethcore-ipc-codegen = { path = "../ipc/codegen" }
|
ethcore-ipc-codegen = { path = "../ipc/codegen" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clippy = { version = "0.0.67", optional = true}
|
clippy = { version = "0.0.77", 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" }
|
||||||
|
@ -3,7 +3,7 @@ description = "Ethcore development/test/build tools"
|
|||||||
homepage = "http://ethcore.io"
|
homepage = "http://ethcore.io"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
name = "ethcore-devtools"
|
name = "ethcore-devtools"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
authors = ["Ethcore <admin@ethcore.io>"]
|
authors = ["Ethcore <admin@ethcore.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
2
doc.sh
2
doc.sh
@ -2,6 +2,8 @@
|
|||||||
# generate documentation only for partiy and ethcore libraries
|
# generate documentation only for partiy and ethcore libraries
|
||||||
|
|
||||||
cargo doc --no-deps --verbose \
|
cargo doc --no-deps --verbose \
|
||||||
|
-p ethkey \
|
||||||
|
-p ethstore \
|
||||||
-p ethash \
|
-p ethash \
|
||||||
-p ethcore-util \
|
-p ethcore-util \
|
||||||
-p ethcore \
|
-p ethcore \
|
||||||
|
27
docker/centos/Dockerfile
Normal file
27
docker/centos/Dockerfile
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
FROM centos:latest
|
||||||
|
WORKDIR /build
|
||||||
|
# install tools and dependencies
|
||||||
|
RUN yum -y update&& \
|
||||||
|
yum install -y git make gcc-c++ gcc file binutils
|
||||||
|
# install rustup
|
||||||
|
RUN curl -sSf https://static.rust-lang.org/rustup.sh -o rustup.sh &&\
|
||||||
|
ls&&\
|
||||||
|
sh rustup.sh -s -- --disable-sudo
|
||||||
|
# show backtraces
|
||||||
|
ENV RUST_BACKTRACE 1
|
||||||
|
# set compiler
|
||||||
|
ENV CXX g++
|
||||||
|
ENV CC gcc
|
||||||
|
# show tools
|
||||||
|
RUN rustc -vV && \
|
||||||
|
cargo -V && \
|
||||||
|
gcc -v &&\
|
||||||
|
g++ -v
|
||||||
|
# build parity
|
||||||
|
RUN git clone https://github.com/ethcore/parity && \
|
||||||
|
cd parity&&\
|
||||||
|
ls -a&&\
|
||||||
|
cargo build --release --verbose && \
|
||||||
|
ls /build/parity/target/release/parity && \
|
||||||
|
strip /build/parity/target/release/parity
|
||||||
|
RUN file /build/parity/target/release/parity
|
47
docker/ubuntu-aarch64/Dockerfile
Normal file
47
docker/ubuntu-aarch64/Dockerfile
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
FROM ubuntu:14.04
|
||||||
|
WORKDIR /build
|
||||||
|
# install tools and dependencies
|
||||||
|
RUN apt-get -y update && \
|
||||||
|
apt-get install -y --force-yes --no-install-recommends \
|
||||||
|
curl git make g++ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \
|
||||||
|
libc6-arm64-cross libc6-dev-arm64-cross wget file ca-certificates \
|
||||||
|
binutils-aarch64-linux-gnu \
|
||||||
|
&& \
|
||||||
|
apt-get clean
|
||||||
|
|
||||||
|
# install rustup
|
||||||
|
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
|
|
||||||
|
# rustup directory
|
||||||
|
ENV PATH /root/.cargo/bin:$PATH
|
||||||
|
|
||||||
|
ENV RUST_TARGETS="aarch64-unknown-linux-gnu"
|
||||||
|
|
||||||
|
# multirust add arm--linux-gnuabhf toolchain
|
||||||
|
RUN rustup target add aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
# show backtraces
|
||||||
|
ENV RUST_BACKTRACE 1
|
||||||
|
|
||||||
|
# set compilers
|
||||||
|
ENV CXX aarch64-linux-gnu-g++
|
||||||
|
ENV CC aarch64-linux-gnu-gcc
|
||||||
|
|
||||||
|
# show tools
|
||||||
|
RUN rustc -vV && \
|
||||||
|
cargo -V && \
|
||||||
|
gcc -v &&\
|
||||||
|
g++ -v
|
||||||
|
|
||||||
|
# build parity
|
||||||
|
RUN git clone https://github.com/ethcore/parity && \
|
||||||
|
cd parity && \
|
||||||
|
mkdir -p .cargo && \
|
||||||
|
echo '[target.aarch64-unknown-linux-gnu]\n\
|
||||||
|
linker = "aarch64-linux-gnu-gcc"\n'\
|
||||||
|
>>.cargo/config && \
|
||||||
|
cat .cargo/config && \
|
||||||
|
cargo build --target aarch64-unknown-linux-gnu --release --verbose && \
|
||||||
|
ls /build/parity/target/aarch64-unknown-linux-gnu/release/parity && \
|
||||||
|
/usr/bin/aarch64-linux-gnu-strip /build/parity/target/aarch64-unknown-linux-gnu/release/parity
|
||||||
|
RUN file /build/parity/target/aarch64-unknown-linux-gnu/release/parity
|
@ -9,38 +9,39 @@ RUN apt-get -y update && \
|
|||||||
&& \
|
&& \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
|
||||||
# install multirust
|
# install rustup
|
||||||
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
|
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
|
|
||||||
|
# rustup directory
|
||||||
|
ENV PATH /root/.cargo/bin:$PATH
|
||||||
|
|
||||||
ENV RUST_TARGETS="arm-unknown-linux-gnueabihf"
|
ENV RUST_TARGETS="arm-unknown-linux-gnueabihf"
|
||||||
|
|
||||||
# multirust add arm--linux-gnuabhf toolchain
|
# multirust add arm--linux-gnuabhf toolchain
|
||||||
RUN multirust add-target stable arm-unknown-linux-gnueabihf
|
RUN rustup target add armv7-unknown-linux-gnueabihf
|
||||||
|
|
||||||
# show backtraces
|
# show backtraces
|
||||||
ENV RUST_BACKTRACE 1
|
ENV RUST_BACKTRACE 1
|
||||||
|
|
||||||
# set compilers
|
# set compilers
|
||||||
ENV CXX arm-linux-gnueabihf-g++
|
ENV CXX arm-linux-gnueabihf-g++
|
||||||
ENV CC arm-linux-gnueabihf-gcc
|
ENV CC arm-linux-gnueabihf-gcc
|
||||||
|
|
||||||
|
# show tools
|
||||||
|
RUN rustc -vV && \
|
||||||
|
cargo -V && \
|
||||||
|
gcc -v &&\
|
||||||
|
g++ -v
|
||||||
|
|
||||||
# build parity
|
# build parity
|
||||||
RUN git clone https://github.com/ethcore/parity && \
|
RUN git clone https://github.com/ethcore/parity && \
|
||||||
cd parity && \
|
cd parity && \
|
||||||
git checkout master && \
|
|
||||||
wget https://github.com/nix-rust/nix/archive/v0.5.0.tar.gz && \
|
|
||||||
tar -xf v0.5.0.tar.gz && \
|
|
||||||
rm -rf v0.5.0.tar.gz && \
|
|
||||||
wget https://github.com/thkaw/mio/archive/v0.5.x.tar.gz && \
|
|
||||||
tar -xf v0.5.x.tar.gz && \
|
|
||||||
rm -rf v0.5.x.tar.gz && \
|
|
||||||
mkdir -p .cargo && \
|
mkdir -p .cargo && \
|
||||||
echo 'paths = ["nix-0.5.0","mio-0.5.x"]\n\
|
echo '[target.armv7-unknown-linux-gnueabihf]\n\
|
||||||
[target.arm-unknown-linux-gnueabihf]\n\
|
|
||||||
linker = "arm-linux-gnueabihf-gcc"\n'\
|
linker = "arm-linux-gnueabihf-gcc"\n'\
|
||||||
>>.cargo/config && \
|
>>.cargo/config && \
|
||||||
cat .cargo/config && \
|
cat .cargo/config && \
|
||||||
rustc -vV && \
|
cargo build --target armv7-unknown-linux-gnueabihf --release --verbose && \
|
||||||
cargo -V && \
|
ls /build/parity/target/armv7-unknown-linux-gnueabihf/release/parity && \
|
||||||
cargo build --target arm-unknown-linux-gnueabihf --release --verbose && \
|
/usr/bin/arm-linux-gnueabihf-strip /build/parity/target/armv7-unknown-linux-gnueabihf/release/parity
|
||||||
ls /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
|
RUN file /build/parity/target/armv7-unknown-linux-gnueabihf/release/parity
|
||||||
file /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
|
|
||||||
/usr/bin/arm-linux-gnueabihf-strip /build/parity/target/arm-unknown-linux-gnueabihf/release/parity
|
|
||||||
RUN file /build/parity/target/arm-unknown-linux-gnueabihf/release/parity
|
|
||||||
|
@ -27,11 +27,11 @@ RUN git clone https://github.com/debris/evmjit && \
|
|||||||
mkdir build && cd build && \
|
mkdir build && cd build && \
|
||||||
cmake .. && make && make install && cd
|
cmake .. && make && make install && cd
|
||||||
|
|
||||||
# install multirust
|
# install rustup
|
||||||
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
|
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
|
|
||||||
# export rust LIBRARY_PATH
|
# rustup directory
|
||||||
ENV LIBRARY_PATH /usr/local/lib
|
ENV PATH /root/.cargo/bin:$PATH
|
||||||
|
|
||||||
# show backtraces
|
# show backtraces
|
||||||
ENV RUST_BACKTRACE 1
|
ENV RUST_BACKTRACE 1
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
FROM ubuntu:14.04
|
FROM ubuntu:14.04
|
||||||
|
WORKDIR /build
|
||||||
# install tools and dependencies
|
# install tools and dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y \
|
apt-get install -y \
|
||||||
@ -11,11 +11,13 @@ RUN apt-get update && \
|
|||||||
wget \
|
wget \
|
||||||
git \
|
git \
|
||||||
g++ \
|
g++ \
|
||||||
|
binutils \
|
||||||
|
file \
|
||||||
# evmjit dependencies
|
# evmjit dependencies
|
||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
libedit-dev
|
libedit-dev
|
||||||
|
|
||||||
# cmake, llvm and rocksdb ppas. then update ppas
|
# cmake and llvm ppas. then update ppas
|
||||||
RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \
|
RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \
|
||||||
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
|
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
@ -27,16 +29,25 @@ RUN git clone https://github.com/debris/evmjit && \
|
|||||||
mkdir build && cd build && \
|
mkdir build && cd build && \
|
||||||
cmake .. && make && make install && cd
|
cmake .. && make && make install && cd
|
||||||
|
|
||||||
# install multirust
|
# install rustup
|
||||||
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
|
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
|
|
||||||
# export rust LIBRARY_PATH
|
# rustup directory
|
||||||
ENV LIBRARY_PATH /usr/local/lib
|
ENV PATH /root/.cargo/bin:$PATH
|
||||||
|
|
||||||
# show backtraces
|
# show backtraces
|
||||||
ENV RUST_BACKTRACE 1
|
ENV RUST_BACKTRACE 1
|
||||||
|
|
||||||
|
# show tools
|
||||||
|
RUN rustc -vV && \
|
||||||
|
cargo -V && \
|
||||||
|
gcc -v &&\
|
||||||
|
g++ -v
|
||||||
|
|
||||||
# build parity
|
# build parity
|
||||||
RUN git clone https://github.com/ethcore/parity && \
|
RUN git clone https://github.com/ethcore/parity && \
|
||||||
cd parity && \
|
cd parity && \
|
||||||
cargo build --release --features ethcore/jit
|
cargo build --release --features ethcore/jit --verbose && \
|
||||||
|
ls /build/parity/target/release/parity && \
|
||||||
|
strip /build/parity/target/release/parity
|
||||||
|
RUN file /build/parity/target/release/parity
|
||||||
|
@ -1,23 +1,33 @@
|
|||||||
FROM ubuntu:14.04
|
FROM ubuntu:14.04
|
||||||
|
WORKDIR /build
|
||||||
# install tools and dependencies
|
# install tools and dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y \
|
apt-get install -y \
|
||||||
g++ \
|
g++ \
|
||||||
curl \
|
curl \
|
||||||
git \
|
git \
|
||||||
make
|
file \
|
||||||
|
binutils
|
||||||
|
|
||||||
# install multirust
|
# install rustup
|
||||||
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
|
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
|
|
||||||
# export rust LIBRARY_PATH
|
# rustup directory
|
||||||
ENV LIBRARY_PATH /usr/local/lib
|
ENV PATH /root/.cargo/bin:$PATH
|
||||||
|
|
||||||
# show backtraces
|
# show backtraces
|
||||||
ENV RUST_BACKTRACE 1
|
ENV RUST_BACKTRACE 1
|
||||||
|
|
||||||
|
# show tools
|
||||||
|
RUN rustc -vV && \
|
||||||
|
cargo -V && \
|
||||||
|
gcc -v &&\
|
||||||
|
g++ -v
|
||||||
|
|
||||||
# build parity
|
# build parity
|
||||||
RUN git clone https://github.com/ethcore/parity && \
|
RUN git clone https://github.com/ethcore/parity && \
|
||||||
cd parity && \
|
cd parity && \
|
||||||
cargo build --release
|
cargo build --release --verbose && \
|
||||||
|
ls /build/parity/target/release/parity && \
|
||||||
|
strip /build/parity/target/release/parity
|
||||||
|
RUN file /build/parity/target/release/parity
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ethash"
|
name = "ethash"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
authors = ["arkpar <arkadiy@ethcore.io"]
|
authors = ["arkpar <arkadiy@ethcore.io"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@ -3,7 +3,7 @@ description = "Ethcore library"
|
|||||||
homepage = "http://ethcore.io"
|
homepage = "http://ethcore.io"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
name = "ethcore"
|
name = "ethcore"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
authors = ["Ethcore <admin@ethcore.io>"]
|
authors = ["Ethcore <admin@ethcore.io>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
@ -22,14 +22,15 @@ ethcore-util = { path = "../util" }
|
|||||||
evmjit = { path = "../evmjit", optional = true }
|
evmjit = { path = "../evmjit", optional = true }
|
||||||
ethash = { path = "../ethash" }
|
ethash = { path = "../ethash" }
|
||||||
num_cpus = "0.2"
|
num_cpus = "0.2"
|
||||||
clippy = { version = "0.0.76", optional = true}
|
clippy = { version = "0.0.77", optional = true}
|
||||||
crossbeam = "0.2.9"
|
crossbeam = "0.2.9"
|
||||||
lazy_static = "0.1"
|
lazy_static = "0.2"
|
||||||
ethcore-devtools = { path = "../devtools" }
|
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"
|
rayon = "0.3.1"
|
||||||
|
ethstore = { path = "../ethstore" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
jit = ["evmjit"]
|
jit = ["evmjit"]
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0x118c30"
|
"frontierCompatibilityModeLimit": "0x118c30",
|
||||||
|
"daoRescueSoftFork": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
26729
ethcore/res/ethereum/frontier_dao_rescue.json
Normal file
26729
ethcore/res/ethereum/frontier_dao_rescue.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,8 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0x118c30"
|
"frontierCompatibilityModeLimit": "0x118c30",
|
||||||
|
"daoRescueSoftFork": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
43
ethcore/res/ethereum/frontier_like_test_dao_rescue.json
Normal file
43
ethcore/res/ethereum/frontier_like_test_dao_rescue.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "Frontier (Test)",
|
||||||
|
"engine": {
|
||||||
|
"Ethash": {
|
||||||
|
"params": {
|
||||||
|
"gasLimitBoundDivisor": "0x0400",
|
||||||
|
"minimumDifficulty": "0x020000",
|
||||||
|
"difficultyBoundDivisor": "0x0800",
|
||||||
|
"durationLimit": "0x0d",
|
||||||
|
"blockReward": "0x4563918244F40000",
|
||||||
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
|
"frontierCompatibilityModeLimit": "0x118c30",
|
||||||
|
"daoRescueSoftFork": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"accountStartNonce": "0x00",
|
||||||
|
"maximumExtraDataSize": "0x20",
|
||||||
|
"minGasLimit": "0x1388",
|
||||||
|
"networkID" : "0x1"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"seal": {
|
||||||
|
"ethereum": {
|
||||||
|
"nonce": "0x0000000000000042",
|
||||||
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"difficulty": "0x400000000",
|
||||||
|
"author": "0x0000000000000000000000000000000000000000",
|
||||||
|
"timestamp": "0x00",
|
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
|
||||||
|
"gasLimit": "0x1388"
|
||||||
|
},
|
||||||
|
"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 } } } }
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,8 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
|
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
|
||||||
|
"daoRescueSoftFork": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": 0
|
"frontierCompatibilityModeLimit": 0,
|
||||||
|
"daoRescueSoftFork": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
43
ethcore/res/ethereum/homestead_test_dao_rescue.json
Normal file
43
ethcore/res/ethereum/homestead_test_dao_rescue.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "Homestead (Test)",
|
||||||
|
"engine": {
|
||||||
|
"Ethash": {
|
||||||
|
"params": {
|
||||||
|
"gasLimitBoundDivisor": "0x0400",
|
||||||
|
"minimumDifficulty": "0x020000",
|
||||||
|
"difficultyBoundDivisor": "0x0800",
|
||||||
|
"durationLimit": "0x0d",
|
||||||
|
"blockReward": "0x4563918244F40000",
|
||||||
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
|
"frontierCompatibilityModeLimit": 0,
|
||||||
|
"daoRescueSoftFork": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"accountStartNonce": "0x00",
|
||||||
|
"maximumExtraDataSize": "0x20",
|
||||||
|
"minGasLimit": "0x1388",
|
||||||
|
"networkID" : "0x1"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"seal": {
|
||||||
|
"ethereum": {
|
||||||
|
"nonce": "0x0000000000000042",
|
||||||
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"difficulty": "0x400000000",
|
||||||
|
"author": "0x0000000000000000000000000000000000000000",
|
||||||
|
"timestamp": "0x00",
|
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
|
||||||
|
"gasLimit": "0x1388"
|
||||||
|
},
|
||||||
|
"accounts": {
|
||||||
|
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||||
|
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||||
|
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,8 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar": "",
|
"registrar": "",
|
||||||
"frontierCompatibilityModeLimit": "0x789b0"
|
"frontierCompatibilityModeLimit": "0x789b0",
|
||||||
|
"daoRescueSoftFork": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
"durationLimit": "0x08",
|
"durationLimit": "0x08",
|
||||||
"blockReward": "0x14D1120D7B160000",
|
"blockReward": "0x14D1120D7B160000",
|
||||||
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
|
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
|
||||||
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
|
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
|
||||||
|
"daoRescueSoftFork": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
33
ethcore/res/null.json
Normal file
33
ethcore/res/null.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "Morden",
|
||||||
|
"engine": {
|
||||||
|
"Null": null
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"accountStartNonce": "0x0",
|
||||||
|
"maximumExtraDataSize": "0x20",
|
||||||
|
"minGasLimit": "0x1388",
|
||||||
|
"networkID" : "0x2"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"seal": {
|
||||||
|
"ethereum": {
|
||||||
|
"nonce": "0x00006d6f7264656e",
|
||||||
|
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"difficulty": "0x20000",
|
||||||
|
"author": "0x0000000000000000000000000000000000000000",
|
||||||
|
"timestamp": "0x00",
|
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"extraData": "0x",
|
||||||
|
"gasLimit": "0x2fefd8"
|
||||||
|
},
|
||||||
|
"accounts": {
|
||||||
|
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "0", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "0", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||||
|
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "0", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||||
|
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "0", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||||
|
"9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "0" }
|
||||||
|
}
|
||||||
|
}
|
@ -166,16 +166,16 @@ impl Account {
|
|||||||
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == Some(SHA3_EMPTY))
|
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == Some(SHA3_EMPTY))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide a database to lookup `code_hash`. Should not be called if it is a contract without code.
|
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code.
|
||||||
pub fn cache_code(&mut self, db: &AccountDB) -> bool {
|
pub fn cache_code(&mut self, db: &AccountDB) -> bool {
|
||||||
// TODO: fill out self.code_cache;
|
// TODO: fill out self.code_cache;
|
||||||
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
||||||
self.is_cached() ||
|
self.is_cached() ||
|
||||||
match self.code_hash {
|
match self.code_hash {
|
||||||
Some(ref h) => match db.lookup(h) {
|
Some(ref h) => match db.get(h) {
|
||||||
Some(x) => { self.code_cache = x.to_vec(); true },
|
Some(x) => { self.code_cache = x.to_vec(); true },
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Failed reverse lookup of {}", h);
|
warn!("Failed reverse get of {}", h);
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -37,18 +37,18 @@ impl<'db> HashDB for AccountDB<'db>{
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup(&self, key: &H256) -> Option<&[u8]> {
|
fn get(&self, key: &H256) -> Option<&[u8]> {
|
||||||
if key == &SHA3_NULL_RLP {
|
if key == &SHA3_NULL_RLP {
|
||||||
return Some(&NULL_RLP_STATIC);
|
return Some(&NULL_RLP_STATIC);
|
||||||
}
|
}
|
||||||
self.db.lookup(&combine_key(&self.address_hash, key))
|
self.db.get(&combine_key(&self.address_hash, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, key: &H256) -> bool {
|
fn contains(&self, key: &H256) -> bool {
|
||||||
if key == &SHA3_NULL_RLP {
|
if key == &SHA3_NULL_RLP {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
self.db.exists(&combine_key(&self.address_hash, key))
|
self.db.contains(&combine_key(&self.address_hash, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, _value: &[u8]) -> H256 {
|
fn insert(&mut self, _value: &[u8]) -> H256 {
|
||||||
@ -59,7 +59,7 @@ impl<'db> HashDB for AccountDB<'db>{
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, _key: &H256) {
|
fn remove(&mut self, _key: &H256) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,18 +95,18 @@ impl<'db> HashDB for AccountDBMut<'db>{
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup(&self, key: &H256) -> Option<&[u8]> {
|
fn get(&self, key: &H256) -> Option<&[u8]> {
|
||||||
if key == &SHA3_NULL_RLP {
|
if key == &SHA3_NULL_RLP {
|
||||||
return Some(&NULL_RLP_STATIC);
|
return Some(&NULL_RLP_STATIC);
|
||||||
}
|
}
|
||||||
self.db.lookup(&combine_key(&self.address_hash, key))
|
self.db.get(&combine_key(&self.address_hash, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, key: &H256) -> bool {
|
fn contains(&self, key: &H256) -> bool {
|
||||||
if key == &SHA3_NULL_RLP {
|
if key == &SHA3_NULL_RLP {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
self.db.exists(&combine_key(&self.address_hash, key))
|
self.db.contains(&combine_key(&self.address_hash, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, value: &[u8]) -> H256 {
|
fn insert(&mut self, value: &[u8]) -> H256 {
|
||||||
@ -127,12 +127,12 @@ impl<'db> HashDB for AccountDBMut<'db>{
|
|||||||
self.db.emplace(key, value.to_vec())
|
self.db.emplace(key, value.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, key: &H256) {
|
fn remove(&mut self, key: &H256) {
|
||||||
if key == &SHA3_NULL_RLP {
|
if key == &SHA3_NULL_RLP {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let key = combine_key(&self.address_hash, key);
|
let key = combine_key(&self.address_hash, key);
|
||||||
self.db.kill(&key)
|
self.db.remove(&key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
272
ethcore/src/account_provider.rs
Normal file
272
ethcore/src/account_provider.rs
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Account management.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use util::{Address as H160, H256, H520};
|
||||||
|
use ethstore::{SecretStore, Error as SSError, SafeAccount, EthStore};
|
||||||
|
use ethstore::dir::{KeyDirectory};
|
||||||
|
use ethstore::ethkey::{Address as SSAddress, Message as SSMessage, Secret as SSSecret, Random, Generator};
|
||||||
|
|
||||||
|
/// Type of unlock.
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum Unlock {
|
||||||
|
/// If account is unlocked temporarily, it should be locked after first usage.
|
||||||
|
Temp,
|
||||||
|
/// Account unlocked permantently can always sign message.
|
||||||
|
/// Use with caution.
|
||||||
|
Perm,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data associated with account.
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AccountData {
|
||||||
|
unlock: Unlock,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `AccountProvider` errors.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Returned when account is not unlocked.
|
||||||
|
NotUnlocked,
|
||||||
|
/// Returned when signing fails.
|
||||||
|
SStore(SSError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
match *self {
|
||||||
|
Error::NotUnlocked => write!(f, "Account is locked"),
|
||||||
|
Error::SStore(ref e) => write!(f, "{}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SSError> for Error {
|
||||||
|
fn from(e: SSError) -> Self {
|
||||||
|
Error::SStore(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_bridge_type {
|
||||||
|
($name: ident, $size: expr, $core: ident, $store: ident) => {
|
||||||
|
/// Primitive
|
||||||
|
pub struct $name([u8; $size]);
|
||||||
|
|
||||||
|
impl From<[u8; $size]> for $name {
|
||||||
|
fn from(s: [u8; $size]) -> Self {
|
||||||
|
$name(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$core> for $name {
|
||||||
|
fn from(s: $core) -> Self {
|
||||||
|
$name(s.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$store> for $name {
|
||||||
|
fn from(s: $store) -> Self {
|
||||||
|
$name(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<$core> for $name {
|
||||||
|
fn into(self) -> $core {
|
||||||
|
$core(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<$store> for $name {
|
||||||
|
fn into(self) -> $store {
|
||||||
|
$store::from(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_bridge_type!(Secret, 32, H256, SSSecret);
|
||||||
|
impl_bridge_type!(Message, 32, H256, SSMessage);
|
||||||
|
impl_bridge_type!(Address, 20, H160, SSAddress);
|
||||||
|
|
||||||
|
|
||||||
|
struct NullDir;
|
||||||
|
|
||||||
|
impl KeyDirectory for NullDir {
|
||||||
|
fn load(&self) -> Result<Vec<SafeAccount>, SSError> {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&self, _account: SafeAccount) -> Result<(), SSError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&self, _address: &SSAddress) -> Result<(), SSError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Account management.
|
||||||
|
/// Responsible for unlocking accounts.
|
||||||
|
pub struct AccountProvider {
|
||||||
|
unlocked: RwLock<HashMap<SSAddress, AccountData>>,
|
||||||
|
sstore: Box<SecretStore>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AccountProvider {
|
||||||
|
/// Creates new account provider.
|
||||||
|
pub fn new(sstore: Box<SecretStore>) -> Self {
|
||||||
|
AccountProvider {
|
||||||
|
unlocked: RwLock::new(HashMap::new()),
|
||||||
|
sstore: sstore,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates not disk backed provider.
|
||||||
|
pub fn transient_provider() -> Self {
|
||||||
|
AccountProvider {
|
||||||
|
unlocked: RwLock::new(HashMap::new()),
|
||||||
|
sstore: Box::new(EthStore::open(Box::new(NullDir)).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates new random account.
|
||||||
|
pub fn new_account(&self, password: &str) -> Result<H160, Error> {
|
||||||
|
let secret = Random.generate().unwrap().secret().clone();
|
||||||
|
let address = try!(self.sstore.insert_account(secret, password));
|
||||||
|
Ok(Address::from(address).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts new account into underlying store.
|
||||||
|
/// Does not unlock account!
|
||||||
|
pub fn insert_account<S>(&self, secret: S, password: &str) -> Result<H160, Error> where Secret: From<S> {
|
||||||
|
let s = Secret::from(secret);
|
||||||
|
let address = try!(self.sstore.insert_account(s.into(), password));
|
||||||
|
Ok(Address::from(address).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns addresses of all accounts.
|
||||||
|
pub fn accounts(&self) -> Vec<H160> {
|
||||||
|
self.sstore.accounts().into_iter().map(|a| H160(a.into())).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper method used for unlocking accounts.
|
||||||
|
fn unlock_account<A>(&self, account: A, password: String, unlock: Unlock) -> Result<(), Error> where Address: From<A> {
|
||||||
|
let a = Address::from(account);
|
||||||
|
let account = a.into();
|
||||||
|
// verify password by signing dump message
|
||||||
|
// result may be discarded
|
||||||
|
let _ = try!(self.sstore.sign(&account, &password, &Default::default()));
|
||||||
|
|
||||||
|
// check if account is already unlocked pernamently, if it is, do nothing
|
||||||
|
{
|
||||||
|
let unlocked = self.unlocked.read().unwrap();
|
||||||
|
if let Some(data) = unlocked.get(&account) {
|
||||||
|
if let Unlock::Perm = data.unlock {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = AccountData {
|
||||||
|
unlock: unlock,
|
||||||
|
password: password,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut unlocked = self.unlocked.write().unwrap();
|
||||||
|
unlocked.insert(account, data);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlocks account permanently.
|
||||||
|
pub fn unlock_account_permanently<A>(&self, account: A, password: String) -> Result<(), Error> where Address: From<A> {
|
||||||
|
self.unlock_account(account, password, Unlock::Perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlocks account temporarily (for one signing).
|
||||||
|
pub fn unlock_account_temporarily<A>(&self, account: A, password: String) -> Result<(), Error> where Address: From<A> {
|
||||||
|
self.unlock_account(account, password, Unlock::Temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if given account is unlocked
|
||||||
|
pub fn is_unlocked<A>(&self, account: A) -> bool where Address: From<A> {
|
||||||
|
let account = Address::from(account).into();
|
||||||
|
let unlocked = self.unlocked.read().unwrap();
|
||||||
|
unlocked.get(&account).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Signs the message. Account must be unlocked.
|
||||||
|
pub fn sign<A, M>(&self, account: A, message: M) -> Result<H520, Error> where Address: From<A>, Message: From<M> {
|
||||||
|
let account = Address::from(account).into();
|
||||||
|
let message = Message::from(message).into();
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
let unlocked = self.unlocked.read().unwrap();
|
||||||
|
try!(unlocked.get(&account).ok_or(Error::NotUnlocked)).clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Unlock::Temp = data.unlock {
|
||||||
|
let mut unlocked = self.unlocked.write().unwrap();
|
||||||
|
unlocked.remove(&account).expect("data exists: so key must exist: qed");
|
||||||
|
}
|
||||||
|
|
||||||
|
let signature = try!(self.sstore.sign(&account, &data.password, &message));
|
||||||
|
Ok(H520(signature.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlocks an account, signs the message, and locks it again.
|
||||||
|
pub fn sign_with_password<A, M>(&self, account: A, password: String, message: M) -> Result<H520, Error> where Address: From<A>, Message: From<M> {
|
||||||
|
let account = Address::from(account).into();
|
||||||
|
let message = Message::from(message).into();
|
||||||
|
let signature = try!(self.sstore.sign(&account, &password, &message));
|
||||||
|
Ok(H520(signature.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::AccountProvider;
|
||||||
|
use ethstore::ethkey::{Generator, Random};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unlock_account_temp() {
|
||||||
|
let kp = Random.generate().unwrap();
|
||||||
|
let ap = AccountProvider::transient_provider();
|
||||||
|
assert!(ap.insert_account(kp.secret().clone(), "test").is_ok());
|
||||||
|
assert!(ap.unlock_account_temporarily(kp.address(), "test1".into()).is_err());
|
||||||
|
assert!(ap.unlock_account_temporarily(kp.address(), "test".into()).is_ok());
|
||||||
|
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
|
||||||
|
assert!(ap.sign(kp.address(), [0u8; 32]).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unlock_account_perm() {
|
||||||
|
let kp = Random.generate().unwrap();
|
||||||
|
let ap = AccountProvider::transient_provider();
|
||||||
|
assert!(ap.insert_account(kp.secret().clone(), "test").is_ok());
|
||||||
|
assert!(ap.unlock_account_permanently(kp.address(), "test1".into()).is_err());
|
||||||
|
assert!(ap.unlock_account_permanently(kp.address(), "test".into()).is_ok());
|
||||||
|
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
|
||||||
|
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
|
||||||
|
assert!(ap.unlock_account_temporarily(kp.address(), "test".into()).is_ok());
|
||||||
|
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
|
||||||
|
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@
|
|||||||
//! A blockchain engine that supports a basic, non-BFT proof-of-authority.
|
//! A blockchain engine that supports a basic, non-BFT proof-of-authority.
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use util::keys::store::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use block::*;
|
use block::*;
|
||||||
use spec::{CommonParams, Spec};
|
use spec::{CommonParams, Spec};
|
||||||
use engine::*;
|
use engine::*;
|
||||||
@ -80,7 +80,7 @@ impl Engine for BasicAuthority {
|
|||||||
Schedule::new_homestead()
|
Schedule::new_homestead()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256) {
|
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
|
||||||
header.difficulty = parent.difficulty;
|
header.difficulty = parent.difficulty;
|
||||||
header.gas_limit = {
|
header.gas_limit = {
|
||||||
let gas_limit = parent.gas_limit;
|
let gas_limit = parent.gas_limit;
|
||||||
@ -105,16 +105,14 @@ impl Engine for BasicAuthority {
|
|||||||
/// be returned.
|
/// be returned.
|
||||||
fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
|
fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
|
||||||
if let Some(ap) = accounts {
|
if let Some(ap) = accounts {
|
||||||
// check to see if author is contained in self.our_params.authorities
|
let header = block.header();
|
||||||
if self.our_params.authorities.contains(block.header().author()) {
|
let message = header.bare_hash();
|
||||||
if let Ok(secret) = ap.account_secret(block.header().author()) {
|
// account should be pernamently unlocked, otherwise sealing will fail
|
||||||
return Some(block.header().author_seal(&secret));
|
if let Ok(signature) = ap.sign(*block.header().author(), message) {
|
||||||
|
return Some(vec![encode(&signature).to_vec()]);
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable");
|
trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
trace!(target: "basicauthority", "generate_seal: FAIL: block author {} isn't one of the authorized accounts {:?}", block.header().author(), self.our_params.authorities);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "basicauthority", "generate_seal: FAIL: accounts not provided");
|
trace!(target: "basicauthority", "generate_seal: FAIL: accounts not provided");
|
||||||
}
|
}
|
||||||
@ -176,16 +174,6 @@ impl Header {
|
|||||||
pub fn signature(&self) -> H520 {
|
pub fn signature(&self) -> H520 {
|
||||||
decode(&self.seal()[0])
|
decode(&self.seal()[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a seal for the block with the given `secret`.
|
|
||||||
pub fn author_seal(&self, secret: &Secret) -> Vec<Bytes> {
|
|
||||||
vec![encode(&ec::sign(secret, &self.bare_hash()).unwrap_or(Signature::new())).to_vec()]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the nonce and mix hash fields of the header.
|
|
||||||
pub fn sign(&mut self, secret: &Secret) {
|
|
||||||
self.seal = self.author_seal(secret);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new test chain spec with `BasicAuthority` consensus engine.
|
/// Create a new test chain spec with `BasicAuthority` consensus engine.
|
||||||
@ -197,7 +185,7 @@ mod tests {
|
|||||||
use common::*;
|
use common::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use util::keys::{TestAccountProvider, TestAccount};
|
use account_provider::AccountProvider;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn has_valid_metadata() {
|
fn has_valid_metadata() {
|
||||||
@ -215,8 +203,9 @@ mod tests {
|
|||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
difficulty: 0.into(),
|
difficulty: 0.into(),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
|
dao_rescue_block_gas_limit: None,
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into()
|
gas_limit: 0.into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(schedule.stack_limit > 0);
|
assert!(schedule.stack_limit > 0);
|
||||||
@ -251,24 +240,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_do_signature_verification() {
|
|
||||||
let secret = "".sha3();
|
|
||||||
let addr = KeyPair::from_secret("".sha3()).unwrap().address();
|
|
||||||
|
|
||||||
let engine = new_test_authority().engine;
|
|
||||||
let mut header: Header = Header::default();
|
|
||||||
header.set_author(addr);
|
|
||||||
header.sign(&secret);
|
|
||||||
|
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_generate_seal() {
|
fn can_generate_seal() {
|
||||||
let addr = KeyPair::from_secret("".sha3()).unwrap().address();
|
let tap = AccountProvider::transient_provider();
|
||||||
let accounts = hash_map![addr => TestAccount{unlocked: true, password: Default::default(), secret: "".sha3()}];
|
let addr = tap.insert_account("".sha3(), "").unwrap();
|
||||||
let tap = TestAccountProvider::new(accounts);
|
tap.unlock_account_permanently(addr, "".into()).unwrap();
|
||||||
|
|
||||||
let spec = new_test_authority();
|
let spec = new_test_authority();
|
||||||
let engine = &spec.engine;
|
let engine = &spec.engine;
|
||||||
@ -278,10 +254,9 @@ 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(), 3141562.into(), vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
assert!(b.try_seal(engine.deref(), seal).is_ok());
|
assert!(b.try_seal(engine.deref(), seal).is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,6 +177,7 @@ pub struct OpenBlock<'x> {
|
|||||||
engine: &'x Engine,
|
engine: &'x Engine,
|
||||||
vm_factory: &'x EvmFactory,
|
vm_factory: &'x EvmFactory,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
|
dao_rescue_block_gas_limit: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
|
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
|
||||||
@ -188,6 +189,7 @@ pub struct ClosedBlock {
|
|||||||
block: ExecutedBlock,
|
block: ExecutedBlock,
|
||||||
uncle_bytes: Bytes,
|
uncle_bytes: Bytes,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
|
dao_rescue_block_gas_limit: Option<U256>,
|
||||||
unclosed_state: State,
|
unclosed_state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +200,6 @@ pub struct ClosedBlock {
|
|||||||
pub struct LockedBlock {
|
pub struct LockedBlock {
|
||||||
block: ExecutedBlock,
|
block: ExecutedBlock,
|
||||||
uncle_bytes: Bytes,
|
uncle_bytes: Bytes,
|
||||||
last_hashes: LastHashes,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A block that has a valid seal.
|
/// A block that has a valid seal.
|
||||||
@ -219,9 +220,10 @@ impl<'x> OpenBlock<'x> {
|
|||||||
db: Box<JournalDB>,
|
db: Box<JournalDB>,
|
||||||
parent: &Header,
|
parent: &Header,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
|
dao_rescue_block_gas_limit: Option<U256>,
|
||||||
author: Address,
|
author: Address,
|
||||||
gas_floor_target: U256,
|
gas_range_target: (U256, U256),
|
||||||
extra_data: Bytes
|
extra_data: Bytes,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
|
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
|
||||||
let mut r = OpenBlock {
|
let mut r = OpenBlock {
|
||||||
@ -229,6 +231,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
engine: engine,
|
engine: engine,
|
||||||
vm_factory: vm_factory,
|
vm_factory: vm_factory,
|
||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
|
dao_rescue_block_gas_limit: dao_rescue_block_gas_limit,
|
||||||
};
|
};
|
||||||
|
|
||||||
r.block.base.header.parent_hash = parent.hash();
|
r.block.base.header.parent_hash = parent.hash();
|
||||||
@ -238,7 +241,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
r.block.base.header.extra_data = extra_data;
|
r.block.base.header.extra_data = extra_data;
|
||||||
r.block.base.header.note_dirty();
|
r.block.base.header.note_dirty();
|
||||||
|
|
||||||
engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target);
|
engine.populate_from_parent(&mut r.block.base.header, parent, gas_range_target.0, gas_range_target.1);
|
||||||
engine.on_new_block(&mut r.block);
|
engine.on_new_block(&mut r.block);
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
@ -285,6 +288,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
/// Get the environment info concerning this block.
|
/// Get the environment info concerning this block.
|
||||||
pub fn env_info(&self) -> EnvInfo {
|
pub fn env_info(&self) -> EnvInfo {
|
||||||
// TODO: memoise.
|
// TODO: memoise.
|
||||||
|
const SOFT_FORK_BLOCK: u64 = 1_800_000;
|
||||||
EnvInfo {
|
EnvInfo {
|
||||||
number: self.block.base.header.number,
|
number: self.block.base.header.number,
|
||||||
author: self.block.base.header.author.clone(),
|
author: self.block.base.header.author.clone(),
|
||||||
@ -293,6 +297,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
|
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
|
||||||
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
|
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
|
||||||
gas_limit: self.block.base.header.gas_limit.clone(),
|
gas_limit: self.block.base.header.gas_limit.clone(),
|
||||||
|
dao_rescue_block_gas_limit: if self.block.base.header.number == SOFT_FORK_BLOCK { Some(self.block.base.header.gas_limit) } else { self.dao_rescue_block_gas_limit },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,6 +344,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
block: s.block,
|
block: s.block,
|
||||||
uncle_bytes: uncle_bytes,
|
uncle_bytes: uncle_bytes,
|
||||||
last_hashes: s.last_hashes,
|
last_hashes: s.last_hashes,
|
||||||
|
dao_rescue_block_gas_limit: s.dao_rescue_block_gas_limit,
|
||||||
unclosed_state: unclosed_state,
|
unclosed_state: unclosed_state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,7 +366,6 @@ impl<'x> OpenBlock<'x> {
|
|||||||
LockedBlock {
|
LockedBlock {
|
||||||
block: s.block,
|
block: s.block,
|
||||||
uncle_bytes: uncle_bytes,
|
uncle_bytes: uncle_bytes,
|
||||||
last_hashes: s.last_hashes,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,7 +391,6 @@ impl ClosedBlock {
|
|||||||
LockedBlock {
|
LockedBlock {
|
||||||
block: self.block,
|
block: self.block,
|
||||||
uncle_bytes: self.uncle_bytes,
|
uncle_bytes: self.uncle_bytes,
|
||||||
last_hashes: self.last_hashes,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,6 +404,7 @@ impl ClosedBlock {
|
|||||||
engine: engine,
|
engine: engine,
|
||||||
vm_factory: vm_factory,
|
vm_factory: vm_factory,
|
||||||
last_hashes: self.last_hashes,
|
last_hashes: self.last_hashes,
|
||||||
|
dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,7 +461,18 @@ impl IsBlock for SealedBlock {
|
|||||||
|
|
||||||
/// Enact the block given by block header, transactions and uncles
|
/// Enact the block given by block header, transactions and uncles
|
||||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||||
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
|
pub fn enact(
|
||||||
|
header: &Header,
|
||||||
|
transactions: &[SignedTransaction],
|
||||||
|
uncles: &[Header],
|
||||||
|
engine: &Engine,
|
||||||
|
tracing: bool,
|
||||||
|
db: Box<JournalDB>,
|
||||||
|
parent: &Header,
|
||||||
|
last_hashes: LastHashes,
|
||||||
|
dao_rescue_block_gas_limit: Option<U256>,
|
||||||
|
vm_factory: &EvmFactory
|
||||||
|
) -> Result<LockedBlock, Error> {
|
||||||
{
|
{
|
||||||
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
||||||
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
|
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
|
||||||
@ -464,7 +480,7 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone()));
|
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.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());
|
||||||
@ -474,22 +490,52 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
||||||
pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
|
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||||
|
pub fn enact_bytes(
|
||||||
|
block_bytes: &[u8],
|
||||||
|
engine: &Engine,
|
||||||
|
tracing: bool,
|
||||||
|
db: Box<JournalDB>,
|
||||||
|
parent: &Header,
|
||||||
|
last_hashes: LastHashes,
|
||||||
|
dao_rescue_block_gas_limit: Option<U256>,
|
||||||
|
vm_factory: &EvmFactory
|
||||||
|
) -> Result<LockedBlock, Error> {
|
||||||
let block = BlockView::new(block_bytes);
|
let block = BlockView::new(block_bytes);
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, vm_factory)
|
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
||||||
pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
|
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||||
|
pub fn enact_verified(
|
||||||
|
block: &PreverifiedBlock,
|
||||||
|
engine: &Engine,
|
||||||
|
tracing: bool,
|
||||||
|
db: Box<JournalDB>,
|
||||||
|
parent: &Header,
|
||||||
|
last_hashes: LastHashes,
|
||||||
|
dao_rescue_block_gas_limit: Option<U256>,
|
||||||
|
vm_factory: &EvmFactory
|
||||||
|
) -> Result<LockedBlock, Error> {
|
||||||
let view = BlockView::new(&block.bytes);
|
let view = BlockView::new(&block.bytes);
|
||||||
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, vm_factory)
|
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
|
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
|
||||||
pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<SealedBlock, Error> {
|
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||||
|
pub fn enact_and_seal(
|
||||||
|
block_bytes: &[u8],
|
||||||
|
engine: &Engine,
|
||||||
|
tracing: bool,
|
||||||
|
db: Box<JournalDB>,
|
||||||
|
parent: &Header,
|
||||||
|
last_hashes: LastHashes,
|
||||||
|
dao_rescue_block_gas_limit: Option<U256>,
|
||||||
|
vm_factory: &EvmFactory
|
||||||
|
) -> Result<SealedBlock, Error> {
|
||||||
let header = BlockView::new(block_bytes).header_view();
|
let header = BlockView::new(block_bytes).header_view();
|
||||||
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, vm_factory)).seal(engine, header.seal())))
|
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)).seal(engine, header.seal())))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -509,7 +555,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(), 3141562.into(), vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
let _ = b.seal(engine.deref(), vec![]);
|
let _ = b.seal(engine.deref(), vec![]);
|
||||||
}
|
}
|
||||||
@ -525,7 +571,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(), 3141562.into(), vec![]).unwrap()
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
|
||||||
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
|
.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();
|
||||||
@ -533,7 +579,7 @@ mod tests {
|
|||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
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 e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap();
|
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(e.rlp_bytes(), orig_bytes);
|
assert_eq!(e.rlp_bytes(), orig_bytes);
|
||||||
|
|
||||||
@ -553,7 +599,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(), 3141562.into(), vec![]).unwrap();
|
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
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();
|
||||||
@ -568,7 +614,7 @@ mod tests {
|
|||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
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 e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap();
|
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
|
||||||
|
|
||||||
let bytes = e.rlp_bytes();
|
let bytes = e.rlp_bytes();
|
||||||
assert_eq!(bytes, orig_bytes);
|
assert_eq!(bytes, orig_bytes);
|
||||||
|
@ -130,7 +130,9 @@ impl QueueSignal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
|
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
|
||||||
self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message");
|
if let Err(e) = self.message_channel.send(UserMessage(SyncMessage::BlockVerified)) {
|
||||||
|
debug!("Error sending BlockVerified message: {:?}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,12 +253,22 @@ impl BlockChain {
|
|||||||
// open extras db
|
// open extras db
|
||||||
let mut extras_path = path.to_path_buf();
|
let mut extras_path = path.to_path_buf();
|
||||||
extras_path.push("extras");
|
extras_path.push("extras");
|
||||||
let extras_db = Database::open_default(extras_path.to_str().unwrap()).unwrap();
|
let extras_db = match config.db_cache_size {
|
||||||
|
None => Database::open_default(extras_path.to_str().unwrap()).unwrap(),
|
||||||
|
Some(cache_size) => Database::open(
|
||||||
|
&DatabaseConfig::with_cache(cache_size/2),
|
||||||
|
extras_path.to_str().unwrap()).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
// open blocks db
|
// open blocks db
|
||||||
let mut blocks_path = path.to_path_buf();
|
let mut blocks_path = path.to_path_buf();
|
||||||
blocks_path.push("blocks");
|
blocks_path.push("blocks");
|
||||||
let blocks_db = Database::open_default(blocks_path.to_str().unwrap()).unwrap();
|
let blocks_db = match config.db_cache_size {
|
||||||
|
None => Database::open_default(blocks_path.to_str().unwrap()).unwrap(),
|
||||||
|
Some(cache_size) => Database::open(
|
||||||
|
&DatabaseConfig::with_cache(cache_size/2),
|
||||||
|
blocks_path.to_str().unwrap()).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
let mut cache_man = CacheManager{cache_usage: VecDeque::new(), in_use: HashSet::new()};
|
let mut cache_man = CacheManager{cache_usage: VecDeque::new(), in_use: HashSet::new()};
|
||||||
(0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new()));
|
(0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new()));
|
||||||
|
@ -23,6 +23,8 @@ pub struct Config {
|
|||||||
pub pref_cache_size: usize,
|
pub pref_cache_size: usize,
|
||||||
/// Maximum cache size in bytes.
|
/// Maximum cache size in bytes.
|
||||||
pub max_cache_size: usize,
|
pub max_cache_size: usize,
|
||||||
|
/// Backing db cache_size
|
||||||
|
pub db_cache_size: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -30,6 +32,7 @@ impl Default for Config {
|
|||||||
Config {
|
Config {
|
||||||
pref_cache_size: 1 << 14,
|
pref_cache_size: 1 << 14,
|
||||||
max_cache_size: 1 << 20,
|
max_cache_size: 1 << 20,
|
||||||
|
db_cache_size: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
//! Blockchain database client.
|
//! Blockchain database client.
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::fs::{create_dir, File};
|
use std::fs::{create_dir, File};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
use util::*;
|
use util::*;
|
||||||
use util::panics::*;
|
use util::panics::*;
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
@ -30,7 +30,8 @@ use engine::Engine;
|
|||||||
use views::HeaderView;
|
use views::HeaderView;
|
||||||
use service::{NetSyncMessage, SyncMessage};
|
use service::{NetSyncMessage, SyncMessage};
|
||||||
use env_info::LastHashes;
|
use env_info::LastHashes;
|
||||||
use verification::*;
|
use verification;
|
||||||
|
use verification::{PreverifiedBlock, Verifier};
|
||||||
use block::*;
|
use block::*;
|
||||||
use transaction::{LocalizedTransaction, SignedTransaction, Action};
|
use transaction::{LocalizedTransaction, SignedTransaction, Action};
|
||||||
use blockchain::extras::TransactionAddress;
|
use blockchain::extras::TransactionAddress;
|
||||||
@ -38,7 +39,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, MiningBlockChainClient, TraceFilter, CallAnalytics};
|
use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, DatabaseCompactionProfile, 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};
|
||||||
@ -51,6 +52,8 @@ pub use types::block_status::BlockStatus;
|
|||||||
use evm::Factory as EvmFactory;
|
use evm::Factory as EvmFactory;
|
||||||
use miner::{Miner, MinerService, TransactionImportResult, AccountDetails};
|
use miner::{Miner, MinerService, TransactionImportResult, AccountDetails};
|
||||||
|
|
||||||
|
const MAX_TX_QUEUE_SIZE: usize = 4096;
|
||||||
|
|
||||||
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 {
|
||||||
write!(f, "#{}.{}", self.best_block_number, self.best_block_hash)
|
write!(f, "#{}.{}", self.best_block_number, self.best_block_hash)
|
||||||
@ -81,7 +84,7 @@ impl ClientReport {
|
|||||||
|
|
||||||
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
|
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
|
||||||
/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
|
/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
|
||||||
pub struct Client<V = CanonVerifier> where V: Verifier {
|
pub struct Client {
|
||||||
chain: Arc<BlockChain>,
|
chain: Arc<BlockChain>,
|
||||||
tracedb: Arc<TraceDB<BlockChain>>,
|
tracedb: Arc<TraceDB<BlockChain>>,
|
||||||
engine: Arc<Box<Engine>>,
|
engine: Arc<Box<Engine>>,
|
||||||
@ -90,9 +93,11 @@ pub struct Client<V = CanonVerifier> where V: Verifier {
|
|||||||
report: RwLock<ClientReport>,
|
report: RwLock<ClientReport>,
|
||||||
import_lock: Mutex<()>,
|
import_lock: Mutex<()>,
|
||||||
panic_handler: Arc<PanicHandler>,
|
panic_handler: Arc<PanicHandler>,
|
||||||
verifier: PhantomData<V>,
|
verifier: Box<Verifier>,
|
||||||
vm_factory: Arc<EvmFactory>,
|
vm_factory: Arc<EvmFactory>,
|
||||||
miner: Arc<Miner>,
|
miner: Arc<Miner>,
|
||||||
|
io_channel: IoChannel<NetSyncMessage>,
|
||||||
|
queue_transactions: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
const HISTORY: u64 = 1200;
|
const HISTORY: u64 = 1200;
|
||||||
@ -103,13 +108,6 @@ const HISTORY: u64 = 1200;
|
|||||||
// of which you actually want force an upgrade.
|
// of which you actually want force an upgrade.
|
||||||
const CLIENT_DB_VER_STR: &'static str = "5.3";
|
const CLIENT_DB_VER_STR: &'static str = "5.3";
|
||||||
|
|
||||||
impl Client<CanonVerifier> {
|
|
||||||
/// Create a new client with given spec and root path.
|
|
||||||
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, miner, message_channel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the path for the databases given the root path and information on the databases.
|
/// Get the path for the databases given the root path and information on the databases.
|
||||||
pub fn get_db_path(path: &Path, pruning: journaldb::Algorithm, genesis_hash: H256) -> PathBuf {
|
pub fn get_db_path(path: &Path, pruning: journaldb::Algorithm, genesis_hash: H256) -> PathBuf {
|
||||||
let mut dir = path.to_path_buf();
|
let mut dir = path.to_path_buf();
|
||||||
@ -127,22 +125,35 @@ pub fn append_path(path: &Path, item: &str) -> String {
|
|||||||
p.to_str().unwrap().to_owned()
|
p.to_str().unwrap().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Client<V> where V: Verifier {
|
impl Client {
|
||||||
/// Create a new client with given spec and root path and custom verifier.
|
/// Create a new client with given spec and DB path and custom verifier.
|
||||||
pub fn new_with_verifier(
|
pub fn new(
|
||||||
config: ClientConfig,
|
config: ClientConfig,
|
||||||
spec: Spec,
|
spec: Spec,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
miner: Arc<Miner>,
|
miner: Arc<Miner>,
|
||||||
message_channel: IoChannel<NetSyncMessage>)
|
message_channel: IoChannel<NetSyncMessage>)
|
||||||
-> Result<Arc<Client<V>>, ClientError>
|
-> Result<Arc<Client>, 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));
|
||||||
let tracedb = Arc::new(try!(TraceDB::new(config.tracing, &path, chain.clone())));
|
let tracedb = Arc::new(try!(TraceDB::new(config.tracing, &path, chain.clone())));
|
||||||
|
|
||||||
let mut state_db = journaldb::new(&append_path(&path, "state"), config.pruning);
|
let mut state_db_config = match config.db_cache_size {
|
||||||
|
None => DatabaseConfig::default(),
|
||||||
|
Some(cache_size) => DatabaseConfig::with_cache(cache_size),
|
||||||
|
};
|
||||||
|
|
||||||
|
if config.db_compaction == DatabaseCompactionProfile::HDD {
|
||||||
|
state_db_config = state_db_config.compaction(CompactionProfile::hdd());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut state_db = journaldb::new(
|
||||||
|
&append_path(&path, "state"),
|
||||||
|
config.pruning,
|
||||||
|
state_db_config
|
||||||
|
);
|
||||||
|
|
||||||
if state_db.is_empty() && spec.ensure_db_good(state_db.as_hashdb_mut()) {
|
if state_db.is_empty() && spec.ensure_db_good(state_db.as_hashdb_mut()) {
|
||||||
state_db.commit(0, &spec.genesis_header().hash(), None).expect("Error commiting genesis state to state DB");
|
state_db.commit(0, &spec.genesis_header().hash(), None).expect("Error commiting genesis state to state DB");
|
||||||
@ -150,7 +161,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
|
|
||||||
let engine = Arc::new(spec.engine);
|
let engine = Arc::new(spec.engine);
|
||||||
|
|
||||||
let block_queue = BlockQueue::new(config.queue, engine.clone(), message_channel);
|
let block_queue = BlockQueue::new(config.queue, engine.clone(), message_channel.clone());
|
||||||
let panic_handler = PanicHandler::new_in_arc();
|
let panic_handler = PanicHandler::new_in_arc();
|
||||||
panic_handler.forward_from(&block_queue);
|
panic_handler.forward_from(&block_queue);
|
||||||
|
|
||||||
@ -163,9 +174,11 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
report: RwLock::new(Default::default()),
|
report: RwLock::new(Default::default()),
|
||||||
import_lock: Mutex::new(()),
|
import_lock: Mutex::new(()),
|
||||||
panic_handler: panic_handler,
|
panic_handler: panic_handler,
|
||||||
verifier: PhantomData,
|
verifier: verification::new(config.verifier_type),
|
||||||
vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
|
vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
|
||||||
miner: miner,
|
miner: miner,
|
||||||
|
io_channel: message_channel,
|
||||||
|
queue_transactions: AtomicUsize::new(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Arc::new(client))
|
Ok(Arc::new(client))
|
||||||
@ -203,7 +216,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify Block Family
|
// Verify Block Family
|
||||||
let verify_family_result = V::verify_block_family(&header, &block.bytes, engine, self.chain.deref());
|
let verify_family_result = self.verifier.verify_block_family(&header, &block.bytes, engine, self.chain.deref());
|
||||||
if let Err(e) = verify_family_result {
|
if let Err(e) = verify_family_result {
|
||||||
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
return Err(());
|
return Err(());
|
||||||
@ -221,7 +234,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
|
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
|
||||||
let db = self.state_db.lock().unwrap().boxed_clone();
|
let db = self.state_db.lock().unwrap().boxed_clone();
|
||||||
|
|
||||||
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory);
|
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory);
|
||||||
if let Err(e) = enact_result {
|
if let Err(e) = enact_result {
|
||||||
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
return Err(());
|
return Err(());
|
||||||
@ -229,7 +242,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
|
|
||||||
// Final Verification
|
// Final Verification
|
||||||
let locked_block = enact_result.unwrap();
|
let locked_block = enact_result.unwrap();
|
||||||
if let Err(e) = V::verify_block_final(&header, locked_block.block().header()) {
|
if let Err(e) = self.verifier.verify_block_final(&header, locked_block.block().header()) {
|
||||||
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@ -272,6 +285,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
let mut import_results = Vec::with_capacity(max_blocks_to_import);
|
let mut import_results = Vec::with_capacity(max_blocks_to_import);
|
||||||
|
|
||||||
let _import_lock = self.import_lock.lock();
|
let _import_lock = self.import_lock.lock();
|
||||||
|
let _timer = PerfTimer::new("import_verified_blocks");
|
||||||
let blocks = self.block_queue.drain(max_blocks_to_import);
|
let blocks = self.block_queue.drain(max_blocks_to_import);
|
||||||
|
|
||||||
let original_best = self.chain_info().best_block_hash;
|
let original_best = self.chain_info().best_block_hash;
|
||||||
@ -286,7 +300,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
let closed_block = self.check_and_close_block(&block);
|
let closed_block = self.check_and_close_block(&block);
|
||||||
if let Err(_) = closed_block {
|
if let Err(_) = closed_block {
|
||||||
invalid_blocks.insert(header.hash());
|
invalid_blocks.insert(header.hash());
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
imported_blocks.push(header.hash());
|
imported_blocks.push(header.hash());
|
||||||
|
|
||||||
@ -349,7 +363,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
invalid: invalid_blocks,
|
invalid: invalid_blocks,
|
||||||
enacted: enacted,
|
enacted: enacted,
|
||||||
retracted: retracted,
|
retracted: retracted,
|
||||||
})).unwrap();
|
})).unwrap_or_else(|e| warn!("Error sending IO notification: {:?}", e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,6 +376,19 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
imported
|
imported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Import transactions from the IO queue
|
||||||
|
pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize {
|
||||||
|
let _timer = PerfTimer::new("import_queued_transactions");
|
||||||
|
self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst);
|
||||||
|
let fetch_account = |a: &Address| AccountDetails {
|
||||||
|
nonce: self.latest_nonce(a),
|
||||||
|
balance: self.latest_balance(a),
|
||||||
|
};
|
||||||
|
let tx = transactions.iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
|
||||||
|
let results = self.miner.import_transactions(self, tx, fetch_account);
|
||||||
|
results.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempt to get a copy of a specific block's state.
|
/// Attempt to get a copy of a specific block's state.
|
||||||
///
|
///
|
||||||
/// This will not fail if given BlockID::Latest.
|
/// This will not fail if given BlockID::Latest.
|
||||||
@ -450,7 +477,7 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> BlockChainClient for Client<V> where V: Verifier {
|
impl BlockChainClient for Client {
|
||||||
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||||
let header = self.block_header(BlockID::Latest).unwrap();
|
let header = self.block_header(BlockID::Latest).unwrap();
|
||||||
let view = HeaderView::new(&header);
|
let view = HeaderView::new(&header);
|
||||||
@ -463,6 +490,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
|
dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit(view.parent_hash()),
|
||||||
};
|
};
|
||||||
// that's just a copy of the state.
|
// that's just a copy of the state.
|
||||||
let mut state = self.state();
|
let mut state = self.state();
|
||||||
@ -748,11 +776,27 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
nonce: self.latest_nonce(a),
|
nonce: self.latest_nonce(a),
|
||||||
balance: self.latest_balance(a),
|
balance: self.latest_balance(a),
|
||||||
};
|
};
|
||||||
self.miner.import_transactions(transactions, fetch_account)
|
self.miner.import_transactions(self, transactions, fetch_account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction> {
|
fn queue_transactions(&self, transactions: Vec<Bytes>) {
|
||||||
self.miner.all_transactions()
|
if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE {
|
||||||
|
debug!("Ignoring {} transactions: queue is full", transactions.len());
|
||||||
|
} else {
|
||||||
|
let len = transactions.len();
|
||||||
|
match self.io_channel.send(NetworkIoMessage::User(SyncMessage::NewTransactions(transactions))) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.queue_transactions.fetch_add(len, AtomicOrdering::SeqCst);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("Ignoring {} transactions: error queueing: {}", len, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
|
self.miner.pending_transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_snapshot(&self, root_dir: &Path) {
|
fn take_snapshot(&self, root_dir: &Path) {
|
||||||
@ -794,8 +838,8 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
|
impl MiningBlockChainClient for Client {
|
||||||
fn prepare_open_block(&self, author: Address, gas_floor_target: U256, extra_data: Bytes) -> OpenBlock {
|
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
|
||||||
let engine = self.engine.deref().deref();
|
let engine = self.engine.deref().deref();
|
||||||
let h = self.chain.best_block_hash();
|
let h = self.chain.best_block_hash();
|
||||||
|
|
||||||
@ -806,11 +850,11 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
|
|||||||
self.state_db.lock().unwrap().boxed_clone(),
|
self.state_db.lock().unwrap().boxed_clone(),
|
||||||
&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),
|
&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),
|
||||||
self.build_last_hashes(h.clone()),
|
self.build_last_hashes(h.clone()),
|
||||||
|
self.dao_rescue_block_gas_limit(h.clone()),
|
||||||
author,
|
author,
|
||||||
gas_floor_target,
|
gas_range_target,
|
||||||
extra_data,
|
extra_data,
|
||||||
).expect("OpenBlock::new only fails if parent state root invalid. State root of best block's header is never invalid. \
|
).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed");
|
||||||
Therefore creating an OpenBlock with the best block's header will not fail.");
|
|
||||||
|
|
||||||
// Add uncles
|
// Add uncles
|
||||||
self.chain
|
self.chain
|
||||||
@ -824,10 +868,6 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
|
|||||||
|
|
||||||
open_block
|
open_block
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -18,8 +18,22 @@ pub use block_queue::BlockQueueConfig;
|
|||||||
pub use blockchain::Config as BlockChainConfig;
|
pub use blockchain::Config as BlockChainConfig;
|
||||||
pub use trace::{Config as TraceConfig, Switch};
|
pub use trace::{Config as TraceConfig, Switch};
|
||||||
pub use evm::VMType;
|
pub use evm::VMType;
|
||||||
|
pub use verification::VerifierType;
|
||||||
use util::journaldb;
|
use util::journaldb;
|
||||||
|
|
||||||
|
/// Client state db compaction profile
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum DatabaseCompactionProfile {
|
||||||
|
/// Default compaction profile
|
||||||
|
Default,
|
||||||
|
/// HDD or other slow storage io compaction profile
|
||||||
|
HDD,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DatabaseCompactionProfile {
|
||||||
|
fn default() -> Self { DatabaseCompactionProfile::Default }
|
||||||
|
}
|
||||||
|
|
||||||
/// Client configuration. Includes configs for all sub-systems.
|
/// Client configuration. Includes configs for all sub-systems.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ClientConfig {
|
pub struct ClientConfig {
|
||||||
@ -35,4 +49,10 @@ pub struct ClientConfig {
|
|||||||
pub pruning: journaldb::Algorithm,
|
pub pruning: journaldb::Algorithm,
|
||||||
/// The name of the client instance.
|
/// The name of the client instance.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// State db cache-size if not default
|
||||||
|
pub db_cache_size: Option<usize>,
|
||||||
|
/// State db compaction profile
|
||||||
|
pub db_compaction: DatabaseCompactionProfile,
|
||||||
|
/// Type of block verifier used by client.
|
||||||
|
pub verifier_type: VerifierType,
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ mod test_client;
|
|||||||
mod trace;
|
mod trace;
|
||||||
|
|
||||||
pub use self::client::*;
|
pub use self::client::*;
|
||||||
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch, VMType};
|
pub use self::config::{ClientConfig, DatabaseCompactionProfile, BlockQueueConfig, BlockChainConfig, Switch, VMType};
|
||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
pub use types::ids::*;
|
pub use types::ids::*;
|
||||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||||
@ -35,13 +35,15 @@ use std::path::Path;
|
|||||||
use util::bytes::Bytes;
|
use util::bytes::Bytes;
|
||||||
use util::hash::{Address, H256, H2048};
|
use util::hash::{Address, H256, H2048};
|
||||||
use util::numbers::U256;
|
use util::numbers::U256;
|
||||||
|
use util::Itertools;
|
||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use block_queue::BlockQueueInfo;
|
use block_queue::BlockQueueInfo;
|
||||||
use block::{LockedBlock, SealedBlock, OpenBlock};
|
use block::OpenBlock;
|
||||||
use header::{BlockNumber, Header};
|
use header::{BlockNumber, Header};
|
||||||
use transaction::{LocalizedTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, SignedTransaction};
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
|
use views::{HeaderView, BlockView};
|
||||||
use error::{ImportResult, ExecutionError};
|
use error::{ImportResult, ExecutionError};
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
@ -192,20 +194,68 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
/// import transactions from network/other 3rd party
|
/// import transactions from network/other 3rd party
|
||||||
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, EthError>>;
|
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, EthError>>;
|
||||||
|
|
||||||
/// list all transactions
|
/// Queue transactions for importing.
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction>;
|
fn queue_transactions(&self, transactions: Vec<Bytes>);
|
||||||
|
|
||||||
/// Generate a PV64 snapshot for the current best block, saving it within the
|
/// Generate a PV64 snapshot for the current best block, saving it within the
|
||||||
/// root directory, whose path is given.
|
/// root directory, whose path is given.
|
||||||
fn take_snapshot(&self, root_dir: &Path);
|
fn take_snapshot(&self, root_dir: &Path);
|
||||||
|
|
||||||
|
/// list all transactions
|
||||||
|
fn pending_transactions(&self) -> Vec<SignedTransaction>;
|
||||||
|
|
||||||
|
/// Get the gas price distribution.
|
||||||
|
fn gas_price_statistics(&self, sample_size: usize, distribution_size: usize) -> Result<Vec<U256>, ()> {
|
||||||
|
let mut h = self.chain_info().best_block_hash;
|
||||||
|
let mut corpus = Vec::new();
|
||||||
|
for _ in 0..sample_size {
|
||||||
|
let block_bytes = self.block(BlockID::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
|
||||||
|
let block = BlockView::new(&block_bytes);
|
||||||
|
let header = block.header_view();
|
||||||
|
if header.number() == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block.transaction_views().iter().foreach(|t| corpus.push(t.gas_price()));
|
||||||
|
h = header.parent_hash().clone();
|
||||||
|
}
|
||||||
|
corpus.sort();
|
||||||
|
let n = corpus.len();
|
||||||
|
if n > 0 {
|
||||||
|
Ok((0..(distribution_size + 1))
|
||||||
|
.map(|i| corpus[i * (n - 1) / distribution_size])
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get `Some` gas limit of SOFT_FORK_BLOCK, or `None` if chain is not yet that long.
|
||||||
|
fn dao_rescue_block_gas_limit(&self, chain_hash: H256) -> Option<U256> {
|
||||||
|
const SOFT_FORK_BLOCK: u64 = 1800000;
|
||||||
|
// shortcut if the canon chain is already known.
|
||||||
|
if self.chain_info().best_block_number > SOFT_FORK_BLOCK + 1000 {
|
||||||
|
return self.block_header(BlockID::Number(SOFT_FORK_BLOCK)).map(|header| HeaderView::new(&header).gas_limit());
|
||||||
|
}
|
||||||
|
// otherwise check according to `chain_hash`.
|
||||||
|
if let Some(mut header) = self.block_header(BlockID::Hash(chain_hash)) {
|
||||||
|
if HeaderView::new(&header).number() < SOFT_FORK_BLOCK {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
while HeaderView::new(&header).number() != SOFT_FORK_BLOCK {
|
||||||
|
header = self.block_header(BlockID::Hash(HeaderView::new(&header).parent_hash())).expect("chain is complete; parent of chain entry must be in chain; qed");
|
||||||
|
}
|
||||||
|
Some(HeaderView::new(&header).gas_limit())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extended client interface used for mining
|
/// Extended client interface used for mining
|
||||||
pub trait MiningBlockChainClient : BlockChainClient {
|
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 OpenBlock prepared for closing.
|
/// Returns OpenBlock prepared for closing.
|
||||||
fn prepare_open_block(&self, author: Address, gas_floor_target: U256, extra_data: Bytes)
|
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes)
|
||||||
-> OpenBlock;
|
-> OpenBlock;
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,10 @@ 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 miner::{Miner, MinerService};
|
||||||
|
use spec::Spec;
|
||||||
|
|
||||||
use block_queue::BlockQueueInfo;
|
use block_queue::BlockQueueInfo;
|
||||||
use block::{SealedBlock, LockedBlock, OpenBlock};
|
use block::OpenBlock;
|
||||||
use executive::Executed;
|
use executive::Executed;
|
||||||
use error::{ExecutionError};
|
use error::{ExecutionError};
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
@ -105,7 +106,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()),
|
miner: Arc::new(Miner::with_spec(Spec::new_test())),
|
||||||
};
|
};
|
||||||
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();
|
||||||
@ -187,7 +188,7 @@ impl TestBlockChainClient {
|
|||||||
txs.append(&signed_tx);
|
txs.append(&signed_tx);
|
||||||
txs.out()
|
txs.out()
|
||||||
},
|
},
|
||||||
_ => rlp::NULL_RLP.to_vec()
|
_ => rlp::EMPTY_LIST_RLP.to_vec()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut rlp = RlpStream::new_list(3);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
@ -240,12 +241,7 @@ impl TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MiningBlockChainClient for TestBlockChainClient {
|
impl MiningBlockChainClient for TestBlockChainClient {
|
||||||
fn try_seal(&self, block: LockedBlock, _seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock> {
|
fn prepare_open_block(&self, _author: Address, _gas_range_target: (U256, U256), _extra_data: Bytes) -> OpenBlock {
|
||||||
Err(block)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn prepare_open_block(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes) -> OpenBlock {
|
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -495,11 +491,17 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
balance: balances[a],
|
balance: balances[a],
|
||||||
};
|
};
|
||||||
|
|
||||||
self.miner.import_transactions(transactions, &fetch_account)
|
self.miner.import_transactions(self, transactions, &fetch_account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction> {
|
fn queue_transactions(&self, transactions: Vec<Bytes>) {
|
||||||
self.miner.all_transactions()
|
// import right here
|
||||||
|
let tx = transactions.into_iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
|
||||||
|
self.import_transactions(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
|
self.miner.pending_transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_snapshot(&self, _root_dir: &Path) {
|
fn take_snapshot(&self, _root_dir: &Path) {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Consensus engine specification
|
//! Consensus engine specification
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use util::keys::store::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use block::ExecutedBlock;
|
use block::ExecutedBlock;
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
@ -96,7 +96,7 @@ pub trait Engine : Sync + Send {
|
|||||||
|
|
||||||
/// Don't forget to call Super::populate_from_parent when subclassing & overriding.
|
/// Don't forget to call Super::populate_from_parent when subclassing & overriding.
|
||||||
// TODO: consider including State in the params.
|
// TODO: consider including State in the params.
|
||||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256) {
|
fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256, _gas_ceil_target: U256) {
|
||||||
header.difficulty = parent.difficulty;
|
header.difficulty = parent.difficulty;
|
||||||
header.gas_limit = parent.gas_limit;
|
header.gas_limit = parent.gas_limit;
|
||||||
header.note_dirty();
|
header.note_dirty();
|
||||||
|
@ -39,6 +39,9 @@ pub struct EnvInfo {
|
|||||||
pub last_hashes: LastHashes,
|
pub last_hashes: LastHashes,
|
||||||
/// The gas used.
|
/// The gas used.
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
|
|
||||||
|
/// Block gas limit at DAO rescue block SOFT_FORK_BLOCK or None if not yet there.
|
||||||
|
pub dao_rescue_block_gas_limit: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EnvInfo {
|
impl Default for EnvInfo {
|
||||||
@ -51,6 +54,7 @@ impl Default for EnvInfo {
|
|||||||
gas_limit: 0.into(),
|
gas_limit: 0.into(),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
|
dao_rescue_block_gas_limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +70,7 @@ impl From<ethjson::vm::Env> for EnvInfo {
|
|||||||
timestamp: e.timestamp.into(),
|
timestamp: e.timestamp.into(),
|
||||||
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
|
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
|
dao_rescue_block_gas_limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,8 @@ pub enum TransactionError {
|
|||||||
},
|
},
|
||||||
/// Transaction's gas limit (aka gas) is invalid.
|
/// Transaction's gas limit (aka gas) is invalid.
|
||||||
InvalidGasLimit(OutOfBounds<U256>),
|
InvalidGasLimit(OutOfBounds<U256>),
|
||||||
|
/// Transaction is invalid for some other reason.
|
||||||
|
DAORescue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TransactionError {
|
impl fmt::Display for TransactionError {
|
||||||
@ -76,6 +78,7 @@ impl fmt::Display for TransactionError {
|
|||||||
GasLimitExceeded { limit, got } =>
|
GasLimitExceeded { limit, got } =>
|
||||||
format!("Gas limit exceeded. Limit={}, Given={}", limit, got),
|
format!("Gas limit exceeded. Limit={}, Given={}", limit, got),
|
||||||
InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err),
|
InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err),
|
||||||
|
DAORescue => "Transaction is invalid due to the DAO rescue.".into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
f.write_fmt(format_args!("Transaction error ({})", msg))
|
f.write_fmt(format_args!("Transaction error ({})", msg))
|
||||||
|
@ -41,6 +41,8 @@ pub struct EthashParams {
|
|||||||
pub registrar: Address,
|
pub registrar: Address,
|
||||||
/// Homestead transition block number.
|
/// Homestead transition block number.
|
||||||
pub frontier_compatibility_mode_limit: u64,
|
pub frontier_compatibility_mode_limit: u64,
|
||||||
|
/// Enable the soft-fork logic.
|
||||||
|
pub dao_rescue_soft_fork: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::EthashParams> for EthashParams {
|
impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||||
@ -53,6 +55,7 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
|
|||||||
block_reward: p.block_reward.into(),
|
block_reward: p.block_reward.into(),
|
||||||
registrar: p.registrar.into(),
|
registrar: p.registrar.into(),
|
||||||
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.into(),
|
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.into(),
|
||||||
|
dao_rescue_soft_fork: p.dao_rescue_soft_fork.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,19 +104,28 @@ impl Engine for Ethash {
|
|||||||
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit {
|
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit {
|
||||||
Schedule::new_frontier()
|
Schedule::new_frontier()
|
||||||
} else {
|
} else {
|
||||||
Schedule::new_homestead()
|
let mut s = Schedule::new_homestead();
|
||||||
|
if self.ethash_params.dao_rescue_soft_fork {
|
||||||
|
s.reject_dao_transactions = env_info.dao_rescue_block_gas_limit.map_or(false, |x| x <= 4_000_000.into());
|
||||||
|
}
|
||||||
|
s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256) {
|
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, gas_ceil_target: U256) {
|
||||||
header.difficulty = self.calculate_difficuty(header, parent);
|
header.difficulty = self.calculate_difficuty(header, parent);
|
||||||
header.gas_limit = {
|
header.gas_limit = {
|
||||||
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 - 1.into())
|
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
|
||||||
|
} else if gas_limit > gas_ceil_target {
|
||||||
|
max(gas_ceil_target, gas_limit - gas_limit / bound_divisor + 1.into())
|
||||||
} else {
|
} else {
|
||||||
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into() + (header.gas_used * 6.into() / 5.into()) / bound_divisor)
|
min(gas_ceil_target,
|
||||||
|
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();
|
||||||
@ -230,8 +242,7 @@ impl Ethash {
|
|||||||
let mut target = if header.number < frontier_limit {
|
let mut target = if header.number < frontier_limit {
|
||||||
if header.timestamp >= parent.timestamp + duration_limit {
|
if header.timestamp >= parent.timestamp + duration_limit {
|
||||||
parent.difficulty - (parent.difficulty / difficulty_bound_divisor)
|
parent.difficulty - (parent.difficulty / difficulty_bound_divisor)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
parent.difficulty + (parent.difficulty / difficulty_bound_divisor)
|
parent.difficulty + (parent.difficulty / difficulty_bound_divisor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,12 +266,21 @@ 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) / U256::from(boundary.as_slice()).into())
|
let d = U256::from(*boundary);
|
||||||
|
if d <= U256::one() {
|
||||||
|
U256::max_value()
|
||||||
|
} else {
|
||||||
|
((U256::one() << 255) / d) << 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 {
|
||||||
U256::from((U512::one() << 256) / difficulty.into()).into()
|
if *difficulty <= U256::one() {
|
||||||
|
U256::max_value().into()
|
||||||
|
} else {
|
||||||
|
(((U256::one() << 255) / *difficulty) << 1).into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_ethash(hash: H256) -> EH256 {
|
fn to_ethash(hash: H256) -> EH256 {
|
||||||
@ -291,12 +311,11 @@ impl Header {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
extern crate ethash;
|
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use super::super::new_morden;
|
use super::super::new_morden;
|
||||||
|
use super::Ethash;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn on_close_block() {
|
fn on_close_block() {
|
||||||
@ -308,7 +327,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(), 3141562.into(), vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
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 +342,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(), 3141562.into(), vec![]).unwrap();
|
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
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();
|
||||||
@ -351,7 +370,8 @@ mod tests {
|
|||||||
difficulty: 0.into(),
|
difficulty: 0.into(),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into()
|
gas_limit: 0.into(),
|
||||||
|
dao_rescue_block_gas_limit: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(schedule.stack_limit > 0);
|
assert!(schedule.stack_limit > 0);
|
||||||
@ -363,7 +383,8 @@ mod tests {
|
|||||||
difficulty: 0.into(),
|
difficulty: 0.into(),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into()
|
gas_limit: 0.into(),
|
||||||
|
dao_rescue_block_gas_limit: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(!schedule.have_delegate_call);
|
assert!(!schedule.have_delegate_call);
|
||||||
@ -509,5 +530,15 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_difficulty_to_boundary() {
|
||||||
|
// result of f(0) is undefined, so do not assert the result
|
||||||
|
let _ = Ethash::difficulty_to_boundary(&U256::from(0));
|
||||||
|
assert_eq!(Ethash::difficulty_to_boundary(&U256::from(1)), H256::from(U256::max_value()));
|
||||||
|
assert_eq!(Ethash::difficulty_to_boundary(&U256::from(2)), H256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||||
|
assert_eq!(Ethash::difficulty_to_boundary(&U256::from(4)), H256::from_str("4000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||||
|
assert_eq!(Ethash::difficulty_to_boundary(&U256::from(32)), H256::from_str("0800000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: difficulty test
|
// TODO: difficulty test
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,12 @@ use super::spec::*;
|
|||||||
pub fn new_olympic() -> Spec { Spec::load(include_bytes!("../../res/ethereum/olympic.json")) }
|
pub fn new_olympic() -> Spec { Spec::load(include_bytes!("../../res/ethereum/olympic.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier mainnet chain spec.
|
/// Create a new Frontier mainnet chain spec.
|
||||||
pub fn new_frontier() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier.json")) }
|
pub fn new_frontier(dao_rescue: bool) -> Spec {
|
||||||
|
Spec::load(match dao_rescue {
|
||||||
|
true => include_bytes!("../../res/ethereum/frontier_dao_rescue.json"),
|
||||||
|
false => include_bytes!("../../res/ethereum/frontier.json"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new Frontier chain spec as though it never changes to Homestead.
|
/// Create a new Frontier chain spec as though it never changes to Homestead.
|
||||||
pub fn new_frontier_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_test.json")) }
|
pub fn new_frontier_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_test.json")) }
|
||||||
@ -84,7 +89,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn frontier() {
|
fn frontier() {
|
||||||
let frontier = new_frontier();
|
let frontier = new_frontier(true);
|
||||||
|
|
||||||
assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap());
|
assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap());
|
||||||
let genesis = frontier.genesis_block();
|
let genesis = frontier.genesis_block();
|
||||||
|
@ -16,9 +16,8 @@
|
|||||||
|
|
||||||
//! Just in time compiler execution environment.
|
//! Just in time compiler execution environment.
|
||||||
use common::*;
|
use common::*;
|
||||||
use trace::VMTracer;
|
|
||||||
use evmjit;
|
use evmjit;
|
||||||
use evm::{self, Error, GasLeft};
|
use evm::{self, GasLeft};
|
||||||
|
|
||||||
/// Should be used to convert jit types to ethcore
|
/// Should be used to convert jit types to ethcore
|
||||||
trait FromJit<T>: Sized {
|
trait FromJit<T>: Sized {
|
||||||
@ -303,7 +302,7 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct JitEvm {
|
pub struct JitEvm {
|
||||||
ctxt: Option<evmjit::ContextHandle>,
|
context: Option<evmjit::ContextHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl evm::Evm for JitEvm {
|
impl evm::Evm for JitEvm {
|
||||||
@ -347,7 +346,7 @@ impl evm::Evm for JitEvm {
|
|||||||
data.timestamp = ext.env_info().timestamp as i64;
|
data.timestamp = ext.env_info().timestamp as i64;
|
||||||
|
|
||||||
self.context = Some(unsafe { evmjit::ContextHandle::new(data, schedule, &mut ext_handle) });
|
self.context = Some(unsafe { evmjit::ContextHandle::new(data, schedule, &mut ext_handle) });
|
||||||
let context = self.context.as_ref_mut().unwrap();
|
let mut context = self.context.as_mut().unwrap();
|
||||||
let res = context.exec();
|
let res = context.exec();
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
|
@ -80,6 +80,8 @@ pub struct Schedule {
|
|||||||
pub tx_data_non_zero_gas: usize,
|
pub tx_data_non_zero_gas: usize,
|
||||||
/// Gas price for copying memory
|
/// Gas price for copying memory
|
||||||
pub copy_gas: usize,
|
pub copy_gas: usize,
|
||||||
|
/// DAO Rescue softfork block
|
||||||
|
pub reject_dao_transactions: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Schedule {
|
impl Schedule {
|
||||||
@ -126,6 +128,7 @@ impl Schedule {
|
|||||||
tx_data_zero_gas: 4,
|
tx_data_zero_gas: 4,
|
||||||
tx_data_non_zero_gas: 68,
|
tx_data_non_zero_gas: 68,
|
||||||
copy_gas: 3,
|
copy_gas: 3,
|
||||||
|
reject_dao_transactions: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,8 @@ mod tests {
|
|||||||
difficulty: 0.into(),
|
difficulty: 0.into(),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into()
|
gas_limit: 0.into(),
|
||||||
|
dao_rescue_block_gas_limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ use tests::helpers::*;
|
|||||||
use devtools::*;
|
use devtools::*;
|
||||||
use spec::Genesis;
|
use spec::Genesis;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
|
use ethjson::blockchain::BlockChain;
|
||||||
use miner::Miner;
|
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> {
|
||||||
@ -41,20 +42,28 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
|||||||
|
|
||||||
flush!(" - {}...", name);
|
flush!(" - {}...", name);
|
||||||
|
|
||||||
|
let spec = |blockchain: &BlockChain| {
|
||||||
|
let genesis = Genesis::from(blockchain.genesis());
|
||||||
|
let state = From::from(blockchain.pre_state.clone());
|
||||||
let mut spec = match era {
|
let mut spec = match era {
|
||||||
ChainEra::Frontier => ethereum::new_frontier_test(),
|
ChainEra::Frontier => ethereum::new_frontier_test(),
|
||||||
ChainEra::Homestead => ethereum::new_homestead_test(),
|
ChainEra::Homestead => ethereum::new_homestead_test(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let genesis = Genesis::from(blockchain.genesis());
|
|
||||||
let state = From::from(blockchain.pre_state.clone());
|
|
||||||
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 temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
{
|
{
|
||||||
let client = Client::new(ClientConfig::default(), spec, temp.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
|
let client = Client::new(
|
||||||
|
ClientConfig::default(),
|
||||||
|
spec(&blockchain),
|
||||||
|
temp.as_path(),
|
||||||
|
Arc::new(Miner::with_spec(spec(&blockchain))),
|
||||||
|
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());
|
||||||
|
@ -91,10 +91,12 @@ 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;
|
extern crate rayon;
|
||||||
|
pub extern crate ethstore;
|
||||||
|
|
||||||
#[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;
|
||||||
|
|
||||||
|
pub mod account_provider;
|
||||||
pub mod basic_authority;
|
pub mod basic_authority;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod block_queue;
|
pub mod block_queue;
|
||||||
|
@ -18,7 +18,7 @@ use rayon::prelude::*;
|
|||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use util::keys::store::{AccountProvider};
|
use account_provider::AccountProvider;
|
||||||
use views::{BlockView, HeaderView};
|
use views::{BlockView, HeaderView};
|
||||||
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
|
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
|
||||||
use block::{ClosedBlock, IsBlock};
|
use block::{ClosedBlock, IsBlock};
|
||||||
@ -29,16 +29,59 @@ use spec::Spec;
|
|||||||
use engine::Engine;
|
use engine::Engine;
|
||||||
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
|
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
|
||||||
|
|
||||||
|
/// Different possible definitions for pending transaction set.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PendingSet {
|
||||||
|
/// Always just the transactions in the queue. These have had only cheap checks.
|
||||||
|
AlwaysQueue,
|
||||||
|
/// Always just the transactions in the sealing block. These have had full checks but
|
||||||
|
/// may be empty if the node is not actively mining or has force_sealing enabled.
|
||||||
|
AlwaysSealing,
|
||||||
|
/// Try the sealing block, but if it is not currently sealing, fallback to the queue.
|
||||||
|
SealingOrElseQueue,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configures the behaviour of the miner.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MinerOptions {
|
||||||
|
/// Force the miner to reseal, even when nobody has asked for work.
|
||||||
|
pub force_sealing: bool,
|
||||||
|
/// Reseal on receipt of new external transactions.
|
||||||
|
pub reseal_on_external_tx: bool,
|
||||||
|
/// Reseal on receipt of new local transactions.
|
||||||
|
pub reseal_on_own_tx: bool,
|
||||||
|
/// Maximum amount of gas to bother considering for block insertion.
|
||||||
|
pub tx_gas_limit: U256,
|
||||||
|
/// Maximum size of the transaction queue.
|
||||||
|
pub tx_queue_size: usize,
|
||||||
|
/// Whether we should fallback to providing all the queue's transactions or just pending.
|
||||||
|
pub pending_set: PendingSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MinerOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
MinerOptions {
|
||||||
|
force_sealing: false,
|
||||||
|
reseal_on_external_tx: true,
|
||||||
|
reseal_on_own_tx: true,
|
||||||
|
tx_gas_limit: !U256::zero(),
|
||||||
|
tx_queue_size: 1024,
|
||||||
|
pending_set: PendingSet::AlwaysQueue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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 {
|
||||||
|
// NOTE [ToDr] When locking always lock in this order!
|
||||||
transaction_queue: Mutex<TransactionQueue>,
|
transaction_queue: Mutex<TransactionQueue>,
|
||||||
|
sealing_work: Mutex<UsingQueue<ClosedBlock>>,
|
||||||
|
|
||||||
// for sealing...
|
// for sealing...
|
||||||
force_sealing: bool,
|
options: MinerOptions,
|
||||||
sealing_enabled: AtomicBool,
|
sealing_enabled: AtomicBool,
|
||||||
sealing_block_last_request: Mutex<u64>,
|
sealing_block_last_request: Mutex<u64>,
|
||||||
sealing_work: Mutex<UsingQueue<ClosedBlock>>,
|
gas_range_target: RwLock<(U256, U256)>,
|
||||||
gas_floor_target: RwLock<U256>,
|
|
||||||
author: RwLock<Address>,
|
author: RwLock<Address>,
|
||||||
extra_data: RwLock<Bytes>,
|
extra_data: RwLock<Bytes>,
|
||||||
spec: Spec,
|
spec: Spec,
|
||||||
@ -46,52 +89,35 @@ pub struct Miner {
|
|||||||
accounts: Option<Arc<AccountProvider>>,
|
accounts: Option<Arc<AccountProvider>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Miner {
|
impl Miner {
|
||||||
fn default() -> Miner {
|
/// Creates new instance of miner without accounts, but with given spec.
|
||||||
|
pub fn with_spec(spec: Spec) -> Miner {
|
||||||
Miner {
|
Miner {
|
||||||
transaction_queue: Mutex::new(TransactionQueue::new()),
|
transaction_queue: Mutex::new(TransactionQueue::new()),
|
||||||
force_sealing: false,
|
options: Default::default(),
|
||||||
sealing_enabled: AtomicBool::new(false),
|
sealing_enabled: AtomicBool::new(false),
|
||||||
sealing_block_last_request: Mutex::new(0),
|
sealing_block_last_request: Mutex::new(0),
|
||||||
sealing_work: Mutex::new(UsingQueue::new(5)),
|
sealing_work: Mutex::new(UsingQueue::new(5)),
|
||||||
gas_floor_target: RwLock::new(U256::zero()),
|
gas_range_target: RwLock::new((U256::zero(), U256::zero())),
|
||||||
author: RwLock::new(Address::default()),
|
|
||||||
extra_data: RwLock::new(Vec::new()),
|
|
||||||
accounts: None,
|
|
||||||
spec: Spec::new_test(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Miner {
|
|
||||||
/// Creates new instance of miner
|
|
||||||
pub fn new(force_sealing: bool, spec: Spec) -> Arc<Miner> {
|
|
||||||
Arc::new(Miner {
|
|
||||||
transaction_queue: Mutex::new(TransactionQueue::new()),
|
|
||||||
force_sealing: force_sealing,
|
|
||||||
sealing_enabled: AtomicBool::new(force_sealing),
|
|
||||||
sealing_block_last_request: Mutex::new(0),
|
|
||||||
sealing_work: Mutex::new(UsingQueue::new(5)),
|
|
||||||
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: 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<AccountProvider>) -> Arc<Miner> {
|
pub fn new(options: MinerOptions, spec: Spec, accounts: Option<Arc<AccountProvider>>) -> Arc<Miner> {
|
||||||
Arc::new(Miner {
|
Arc::new(Miner {
|
||||||
transaction_queue: Mutex::new(TransactionQueue::new()),
|
transaction_queue: Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, options.tx_gas_limit)),
|
||||||
force_sealing: force_sealing,
|
sealing_enabled: AtomicBool::new(options.force_sealing),
|
||||||
sealing_enabled: AtomicBool::new(force_sealing),
|
options: options,
|
||||||
sealing_block_last_request: Mutex::new(0),
|
sealing_block_last_request: Mutex::new(0),
|
||||||
sealing_work: Mutex::new(UsingQueue::new(5)),
|
sealing_work: Mutex::new(UsingQueue::new(5)),
|
||||||
gas_floor_target: RwLock::new(U256::zero()),
|
gas_range_target: RwLock::new((U256::zero(), 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: Some(accounts),
|
accounts: accounts,
|
||||||
spec: spec,
|
spec: spec,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -105,10 +131,11 @@ impl Miner {
|
|||||||
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
|
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
|
||||||
fn prepare_sealing(&self, chain: &MiningBlockChainClient) {
|
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, mut open_block) = {
|
||||||
|
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();
|
||||||
let best_hash = chain.best_block_header().sha3();
|
let best_hash = chain.best_block_header().sha3();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// check to see if last ClosedBlock in would_seals is actually same parent block.
|
// check to see if last ClosedBlock in would_seals is actually same parent block.
|
||||||
// if so
|
// if so
|
||||||
@ -117,7 +144,7 @@ impl Miner {
|
|||||||
// otherwise, leave everything alone.
|
// otherwise, leave everything alone.
|
||||||
// otherwise, author a fresh block.
|
// otherwise, author a fresh block.
|
||||||
*/
|
*/
|
||||||
let mut open_block = match sealing_work.pop_if(|b| b.block().fields().header.parent_hash() == &best_hash) {
|
let open_block = match sealing_work.pop_if(|b| b.block().fields().header.parent_hash() == &best_hash) {
|
||||||
Some(old_block) => {
|
Some(old_block) => {
|
||||||
trace!(target: "miner", "Already have previous work; updating and returning");
|
trace!(target: "miner", "Already have previous work; updating and returning");
|
||||||
// add transactions to old_block
|
// add transactions to old_block
|
||||||
@ -129,11 +156,13 @@ impl Miner {
|
|||||||
trace!(target: "miner", "No existing work - making new block");
|
trace!(target: "miner", "No existing work - making new block");
|
||||||
chain.prepare_open_block(
|
chain.prepare_open_block(
|
||||||
self.author(),
|
self.author(),
|
||||||
self.gas_floor_target(),
|
(self.gas_floor_target(), self.gas_ceil_target()),
|
||||||
self.extra_data()
|
self.extra_data()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
(transactions, open_block)
|
||||||
|
};
|
||||||
|
|
||||||
let mut invalid_transactions = HashSet::new();
|
let mut invalid_transactions = HashSet::new();
|
||||||
let block_number = open_block.block().fields().header.number();
|
let block_number = open_block.block().fields().header.number();
|
||||||
@ -162,15 +191,17 @@ impl Miner {
|
|||||||
|
|
||||||
let block = open_block.close();
|
let block = open_block.close();
|
||||||
|
|
||||||
let mut queue = self.transaction_queue.lock().unwrap();
|
|
||||||
let fetch_account = |a: &Address| AccountDetails {
|
let fetch_account = |a: &Address| AccountDetails {
|
||||||
nonce: chain.latest_nonce(a),
|
nonce: chain.latest_nonce(a),
|
||||||
balance: chain.latest_balance(a),
|
balance: chain.latest_balance(a),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut queue = self.transaction_queue.lock().unwrap();
|
||||||
for hash in invalid_transactions.into_iter() {
|
for hash in invalid_transactions.into_iter() {
|
||||||
queue.remove_invalid(&hash, &fetch_account);
|
queue.remove_invalid(&hash, &fetch_account);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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.");
|
||||||
@ -181,7 +212,7 @@ impl Miner {
|
|||||||
});
|
});
|
||||||
if let Some(seal) = s {
|
if let Some(seal) = s {
|
||||||
trace!(target: "miner", "prepare_sealing: managed internal seal. importing...");
|
trace!(target: "miner", "prepare_sealing: managed internal seal. importing...");
|
||||||
if let Ok(sealed) = chain.try_seal(block.lock(), seal) {
|
if let Ok(sealed) = block.lock().try_seal(self.engine(), seal) {
|
||||||
if let Ok(_) = chain.import_block(sealed.rlp_bytes()) {
|
if let Ok(_) = chain.import_block(sealed.rlp_bytes()) {
|
||||||
trace!(target: "miner", "prepare_sealing: sealed internally and imported. leaving.");
|
trace!(target: "miner", "prepare_sealing: sealed internally and imported. leaving.");
|
||||||
} else {
|
} else {
|
||||||
@ -195,6 +226,8 @@ impl Miner {
|
|||||||
trace!(target: "miner", "prepare_sealing: unable to generate seal internally");
|
trace!(target: "miner", "prepare_sealing: unable to generate seal internally");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut sealing_work = self.sealing_work.lock().unwrap();
|
||||||
if sealing_work.peek_last_ref().map_or(true, |pb| pb.block().fields().header.hash() != block.block().fields().header.hash()) {
|
if sealing_work.peek_last_ref().map_or(true, |pb| pb.block().fields().header.hash() != block.block().fields().header.hash()) {
|
||||||
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
|
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
|
||||||
sealing_work.push(block);
|
sealing_work.push(block);
|
||||||
@ -266,6 +299,7 @@ impl MinerService for Miner {
|
|||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
|
dao_rescue_block_gas_limit: chain.dao_rescue_block_gas_limit(header.parent_hash().clone()),
|
||||||
};
|
};
|
||||||
// that's just a copy of the state.
|
// that's just a copy of the state.
|
||||||
let mut state = block.state().clone();
|
let mut state = block.state().clone();
|
||||||
@ -332,7 +366,11 @@ impl MinerService for Miner {
|
|||||||
|
|
||||||
/// Set the gas limit we wish to target when sealing a new block.
|
/// Set the gas limit we wish to target when sealing a new block.
|
||||||
fn set_gas_floor_target(&self, target: U256) {
|
fn set_gas_floor_target(&self, target: U256) {
|
||||||
*self.gas_floor_target.write().unwrap() = target;
|
self.gas_range_target.write().unwrap().0 = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_gas_ceil_target(&self, target: U256) {
|
||||||
|
self.gas_range_target.write().unwrap().1 = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_minimal_gas_price(&self, min_gas_price: U256) {
|
fn set_minimal_gas_price(&self, min_gas_price: U256) {
|
||||||
@ -349,7 +387,7 @@ impl MinerService for Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sensible_gas_limit(&self) -> U256 {
|
fn sensible_gas_limit(&self) -> U256 {
|
||||||
*self.gas_floor_target.read().unwrap() / 5.into()
|
self.gas_range_target.read().unwrap().0 / 5.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transactions_limit(&self) -> usize {
|
fn transactions_limit(&self) -> usize {
|
||||||
@ -360,6 +398,10 @@ impl MinerService for Miner {
|
|||||||
self.transaction_queue.lock().unwrap().set_limit(limit)
|
self.transaction_queue.lock().unwrap().set_limit(limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_tx_gas_limit(&self, limit: U256) {
|
||||||
|
self.transaction_queue.lock().unwrap().set_tx_gas_limit(limit)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the author that we will seal blocks as.
|
/// Get the author that we will seal blocks as.
|
||||||
fn author(&self) -> Address {
|
fn author(&self) -> Address {
|
||||||
*self.author.read().unwrap()
|
*self.author.read().unwrap()
|
||||||
@ -372,21 +414,36 @@ impl MinerService for Miner {
|
|||||||
|
|
||||||
/// Get the gas limit we wish to target when sealing a new block.
|
/// Get the gas limit we wish to target when sealing a new block.
|
||||||
fn gas_floor_target(&self) -> U256 {
|
fn gas_floor_target(&self) -> U256 {
|
||||||
*self.gas_floor_target.read().unwrap()
|
self.gas_range_target.read().unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) ->
|
/// Get the gas limit we wish to target when sealing a new block.
|
||||||
|
fn gas_ceil_target(&self) -> U256 {
|
||||||
|
self.gas_range_target.read().unwrap().1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
|
||||||
Vec<Result<TransactionImportResult, Error>>
|
Vec<Result<TransactionImportResult, Error>>
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
|
let results: Vec<Result<TransactionImportResult, Error>> = {
|
||||||
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
transactions.into_iter()
|
transactions.into_iter()
|
||||||
.map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External))
|
.map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External))
|
||||||
.collect()
|
.collect()
|
||||||
|
};
|
||||||
|
if !results.is_empty() && self.options.reseal_on_external_tx {
|
||||||
|
self.update_sealing(chain);
|
||||||
|
}
|
||||||
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_own_transaction<T>(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, fetch_account: T) ->
|
fn import_own_transaction<T>(
|
||||||
Result<TransactionImportResult, Error>
|
&self,
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
chain: &MiningBlockChainClient,
|
||||||
|
transaction: SignedTransaction,
|
||||||
|
fetch_account: T
|
||||||
|
) -> Result<TransactionImportResult, Error> where T: Fn(&Address) -> AccountDetails {
|
||||||
|
|
||||||
let hash = transaction.hash();
|
let hash = transaction.hash();
|
||||||
trace!(target: "own_tx", "Importing transaction: {:?}", transaction);
|
trace!(target: "own_tx", "Importing transaction: {:?}", transaction);
|
||||||
|
|
||||||
@ -409,7 +466,7 @@ impl MinerService for Miner {
|
|||||||
import
|
import
|
||||||
};
|
};
|
||||||
|
|
||||||
if imported.is_ok() {
|
if imported.is_ok() && self.options.reseal_on_own_tx {
|
||||||
// Make sure to do it after transaction is imported and lock is droped.
|
// Make sure to do it after transaction is imported and lock is droped.
|
||||||
// We need to create pending block and enable sealing
|
// We need to create pending block and enable sealing
|
||||||
let prepared = self.enable_and_prepare_sealing(chain);
|
let prepared = self.enable_and_prepare_sealing(chain);
|
||||||
@ -423,40 +480,49 @@ impl MinerService for Miner {
|
|||||||
imported
|
imported
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions_hashes(&self) -> Vec<H256> {
|
|
||||||
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
|
|
||||||
(true, Some(pending)) => pending.transactions().iter().map(|t| t.hash()).collect(),
|
|
||||||
_ => {
|
|
||||||
let queue = self.transaction_queue.lock().unwrap();
|
|
||||||
queue.pending_hashes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
|
|
||||||
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
|
|
||||||
(true, Some(pending)) => pending.transactions().iter().find(|t| &t.hash() == hash).cloned(),
|
|
||||||
_ => {
|
|
||||||
let queue = self.transaction_queue.lock().unwrap();
|
|
||||||
queue.find(hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction> {
|
fn all_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
let queue = self.transaction_queue.lock().unwrap();
|
let queue = self.transaction_queue.lock().unwrap();
|
||||||
queue.top_transactions()
|
queue.top_transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
// TODO: should only use the sealing_work when it's current (it could be an old block)
|
|
||||||
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
|
|
||||||
(true, Some(pending)) => pending.transactions().clone(),
|
|
||||||
_ => {
|
|
||||||
let queue = self.transaction_queue.lock().unwrap();
|
let queue = self.transaction_queue.lock().unwrap();
|
||||||
queue.top_transactions()
|
let sw = self.sealing_work.lock().unwrap();
|
||||||
|
// TODO: should only use the sealing_work when it's current (it could be an old block)
|
||||||
|
let sealing_set = match self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
||||||
|
true => sw.peek_last_ref(),
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
|
match (&self.options.pending_set, sealing_set) {
|
||||||
|
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.top_transactions(),
|
||||||
|
(_, sealing) => sealing.map_or_else(Vec::new, |s| s.transactions().clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pending_transactions_hashes(&self) -> Vec<H256> {
|
||||||
|
let queue = self.transaction_queue.lock().unwrap();
|
||||||
|
let sw = self.sealing_work.lock().unwrap();
|
||||||
|
let sealing_set = match self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
||||||
|
true => sw.peek_last_ref(),
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
|
match (&self.options.pending_set, sealing_set) {
|
||||||
|
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.pending_hashes(),
|
||||||
|
(_, sealing) => sealing.map_or_else(Vec::new, |s| s.transactions().iter().map(|t| t.hash()).collect()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
|
||||||
|
let queue = self.transaction_queue.lock().unwrap();
|
||||||
|
let sw = self.sealing_work.lock().unwrap();
|
||||||
|
let sealing_set = match self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
||||||
|
true => sw.peek_last_ref(),
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
|
match (&self.options.pending_set, sealing_set) {
|
||||||
|
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.find(hash),
|
||||||
|
(_, sealing) => sealing.and_then(|s| s.transactions().iter().find(|t| &t.hash() == hash).cloned()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_receipts(&self) -> BTreeMap<H256, Receipt> {
|
fn pending_receipts(&self) -> BTreeMap<H256, Receipt> {
|
||||||
@ -483,7 +549,7 @@ impl MinerService for Miner {
|
|||||||
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();
|
||||||
let last_request = *self.sealing_block_last_request.lock().unwrap();
|
let last_request = *self.sealing_block_last_request.lock().unwrap();
|
||||||
let should_disable_sealing = !self.force_sealing
|
let should_disable_sealing = !self.options.force_sealing
|
||||||
&& !has_local_transactions
|
&& !has_local_transactions
|
||||||
&& current_no > last_request
|
&& current_no > last_request
|
||||||
&& current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS;
|
&& current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS;
|
||||||
@ -492,7 +558,7 @@ impl MinerService for Miner {
|
|||||||
trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request);
|
trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request);
|
||||||
self.sealing_enabled.store(false, atomic::Ordering::Relaxed);
|
self.sealing_enabled.store(false, atomic::Ordering::Relaxed);
|
||||||
self.sealing_work.lock().unwrap().reset();
|
self.sealing_work.lock().unwrap().reset();
|
||||||
} else if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
} else {
|
||||||
self.prepare_sealing(chain);
|
self.prepare_sealing(chain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -510,7 +576,7 @@ impl MinerService for Miner {
|
|||||||
|
|
||||||
fn submit_seal(&self, chain: &MiningBlockChainClient, 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 b.lock().try_seal(self.engine(), seal) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
info!(target: "miner", "Mined block rejected, PoW was invalid.");
|
info!(target: "miner", "Mined block rejected, PoW was invalid.");
|
||||||
Err(Error::PowInvalid)
|
Err(Error::PowInvalid)
|
||||||
@ -559,7 +625,7 @@ impl MinerService for Miner {
|
|||||||
for tx in &txs {
|
for tx in &txs {
|
||||||
let _sender = tx.sender();
|
let _sender = tx.sender();
|
||||||
}
|
}
|
||||||
let _ = self.import_transactions(txs, |a| AccountDetails {
|
let _ = self.import_transactions(chain, txs, |a| AccountDetails {
|
||||||
nonce: chain.latest_nonce(a),
|
nonce: chain.latest_nonce(a),
|
||||||
balance: chain.latest_balance(a),
|
balance: chain.latest_balance(a),
|
||||||
});
|
});
|
||||||
@ -598,6 +664,7 @@ mod tests {
|
|||||||
use util::*;
|
use util::*;
|
||||||
use client::{TestBlockChainClient, EachBlockWith};
|
use client::{TestBlockChainClient, EachBlockWith};
|
||||||
use block::*;
|
use block::*;
|
||||||
|
use spec::Spec;
|
||||||
|
|
||||||
// TODO [ToDr] To uncomment` when TestBlockChainClient can actually return a ClosedBlock.
|
// TODO [ToDr] To uncomment` when TestBlockChainClient can actually return a ClosedBlock.
|
||||||
#[ignore]
|
#[ignore]
|
||||||
@ -605,7 +672,7 @@ mod tests {
|
|||||||
fn should_prepare_block_to_seal() {
|
fn should_prepare_block_to_seal() {
|
||||||
// given
|
// given
|
||||||
let client = TestBlockChainClient::default();
|
let client = TestBlockChainClient::default();
|
||||||
let miner = Miner::default();
|
let miner = Miner::with_spec(Spec::new_test());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let sealing_work = miner.map_sealing_work(&client, |_| ());
|
let sealing_work = miner.map_sealing_work(&client, |_| ());
|
||||||
@ -617,7 +684,7 @@ mod tests {
|
|||||||
fn should_still_work_after_a_couple_of_blocks() {
|
fn should_still_work_after_a_couple_of_blocks() {
|
||||||
// given
|
// given
|
||||||
let client = TestBlockChainClient::default();
|
let client = TestBlockChainClient::default();
|
||||||
let miner = Miner::default();
|
let miner = Miner::with_spec(Spec::new_test());
|
||||||
|
|
||||||
let res = miner.map_sealing_work(&client, |b| b.block().fields().header.hash());
|
let res = miner.map_sealing_work(&client, |b| b.block().fields().header.hash());
|
||||||
assert!(res.is_some());
|
assert!(res.is_some());
|
||||||
|
@ -28,11 +28,12 @@
|
|||||||
//! extern crate ethcore;
|
//! extern crate ethcore;
|
||||||
//! use std::env;
|
//! use std::env;
|
||||||
//! use util::network::{NetworkService, NetworkConfiguration};
|
//! use util::network::{NetworkService, NetworkConfiguration};
|
||||||
|
//! use ethcore::ethereum;
|
||||||
//! use ethcore::client::{Client, ClientConfig};
|
//! use ethcore::client::{Client, ClientConfig};
|
||||||
//! use ethcore::miner::{Miner, MinerService};
|
//! use ethcore::miner::{Miner, MinerService};
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let miner: Miner = Miner::default();
|
//! let miner: Miner = Miner::with_spec(ethereum::new_frontier(true));
|
||||||
//! // get status
|
//! // get status
|
||||||
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
||||||
//!
|
//!
|
||||||
@ -46,7 +47,7 @@ mod external;
|
|||||||
mod transaction_queue;
|
mod transaction_queue;
|
||||||
|
|
||||||
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
|
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
|
||||||
pub use self::miner::{Miner};
|
pub use self::miner::{Miner, MinerOptions, PendingSet};
|
||||||
pub use self::external::{ExternalMiner, ExternalMinerService};
|
pub use self::external::{ExternalMiner, ExternalMinerService};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
@ -81,20 +82,30 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Set minimal gas price of transaction to be accepted for mining.
|
/// Set minimal gas price of transaction to be accepted for mining.
|
||||||
fn set_minimal_gas_price(&self, min_gas_price: U256);
|
fn set_minimal_gas_price(&self, min_gas_price: U256);
|
||||||
|
|
||||||
/// Get the gas limit we wish to target when sealing a new block.
|
/// Get the lower bound of the gas limit we wish to target when sealing a new block.
|
||||||
fn gas_floor_target(&self) -> U256;
|
fn gas_floor_target(&self) -> U256;
|
||||||
|
|
||||||
/// Set the gas limit we wish to target when sealing a new block.
|
/// Get the upper bound of the gas limit we wish to target when sealing a new block.
|
||||||
|
fn gas_ceil_target(&self) -> U256;
|
||||||
|
|
||||||
|
// TODO: coalesce into single set_range function.
|
||||||
|
/// Set the lower bound of gas limit we wish to target when sealing a new block.
|
||||||
fn set_gas_floor_target(&self, target: U256);
|
fn set_gas_floor_target(&self, target: U256);
|
||||||
|
|
||||||
|
/// Set the upper bound of gas limit we wish to target when sealing a new block.
|
||||||
|
fn set_gas_ceil_target(&self, target: U256);
|
||||||
|
|
||||||
/// Get current transactions limit in queue.
|
/// Get current transactions limit in queue.
|
||||||
fn transactions_limit(&self) -> usize;
|
fn transactions_limit(&self) -> usize;
|
||||||
|
|
||||||
/// Set maximal number of transactions kept in the queue (both current and future).
|
/// Set maximal number of transactions kept in the queue (both current and future).
|
||||||
fn set_transactions_limit(&self, limit: usize);
|
fn set_transactions_limit(&self, limit: usize);
|
||||||
|
|
||||||
|
/// Set maximum amount of gas allowed for any single transaction to mine.
|
||||||
|
fn set_tx_gas_limit(&self, limit: U256);
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) ->
|
fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
|
||||||
Vec<Result<TransactionImportResult, Error>>
|
Vec<Result<TransactionImportResult, Error>>
|
||||||
where T: Fn(&Address) -> AccountDetails, Self: Sized;
|
where T: Fn(&Address) -> AccountDetails, Self: Sized;
|
||||||
|
|
||||||
|
@ -167,16 +167,17 @@ impl PartialOrd for TransactionOrder {
|
|||||||
|
|
||||||
impl Ord for TransactionOrder {
|
impl Ord for TransactionOrder {
|
||||||
fn cmp(&self, b: &TransactionOrder) -> Ordering {
|
fn cmp(&self, b: &TransactionOrder) -> Ordering {
|
||||||
// Local transactions should always have priority
|
|
||||||
if self.origin != b.origin {
|
|
||||||
return self.origin.cmp(&b.origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// First check nonce_height
|
// First check nonce_height
|
||||||
if self.nonce_height != b.nonce_height {
|
if self.nonce_height != b.nonce_height {
|
||||||
return self.nonce_height.cmp(&b.nonce_height);
|
return self.nonce_height.cmp(&b.nonce_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Local transactions should always have priority
|
||||||
|
// NOTE nonce has to be checked first, cause otherwise the order might be wrong.
|
||||||
|
if self.origin != b.origin {
|
||||||
|
return self.origin.cmp(&b.origin);
|
||||||
|
}
|
||||||
|
|
||||||
// Then compare gas_prices
|
// Then compare gas_prices
|
||||||
let a_gas = self.gas_price;
|
let a_gas = self.gas_price;
|
||||||
let b_gas = b.gas_price;
|
let b_gas = b.gas_price;
|
||||||
@ -235,22 +236,22 @@ impl TransactionSet {
|
|||||||
self.by_priority.insert(order.clone());
|
self.by_priority.insert(order.clone());
|
||||||
let r = self.by_address.insert(sender, nonce, order);
|
let r = self.by_address.insert(sender, nonce, order);
|
||||||
// If transaction was replaced remove it from priority queue
|
// If transaction was replaced remove it from priority queue
|
||||||
if let Some(ref order) = r {
|
if let Some(ref old_order) = r {
|
||||||
self.by_priority.remove(order);
|
self.by_priority.remove(old_order);
|
||||||
}
|
}
|
||||||
|
assert_eq!(self.by_priority.len(), self.by_address.len());
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove low priority transactions if there is more then specified by given `limit`.
|
/// Remove low priority transactions if there is more then specified by given `limit`.
|
||||||
///
|
///
|
||||||
/// It drops transactions from this set but also removes associated `VerifiedTransaction`.
|
/// It drops transactions from this set but also removes associated `VerifiedTransaction`.
|
||||||
/// Returns addresses and highes nonces of transactions removed because of limit.
|
/// Returns addresses and lowest nonces of transactions removed because of limit.
|
||||||
fn enforce_limit(&mut self, by_hash: &mut HashMap<H256, VerifiedTransaction>) -> Option<HashMap<Address, U256>> {
|
fn enforce_limit(&mut self, by_hash: &mut HashMap<H256, VerifiedTransaction>) -> Option<HashMap<Address, U256>> {
|
||||||
let len = self.by_priority.len();
|
let len = self.by_priority.len();
|
||||||
if len <= self.limit {
|
if len <= self.limit {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let to_drop : Vec<(Address, U256)> = {
|
let to_drop : Vec<(Address, U256)> = {
|
||||||
self.by_priority
|
self.by_priority
|
||||||
.iter()
|
.iter()
|
||||||
@ -269,8 +270,8 @@ impl TransactionSet {
|
|||||||
by_hash.remove(&order.hash)
|
by_hash.remove(&order.hash)
|
||||||
.expect("Hash found in `by_priorty` matches the one dropped; so it is included in `by_hash`");
|
.expect("Hash found in `by_priorty` matches the one dropped; so it is included in `by_hash`");
|
||||||
|
|
||||||
let max = removed.get(&sender).map_or(nonce, |val| cmp::max(*val, nonce));
|
let min = removed.get(&sender).map_or(nonce, |val| cmp::min(*val, nonce));
|
||||||
removed.insert(sender, max);
|
removed.insert(sender, min);
|
||||||
removed
|
removed
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -279,8 +280,10 @@ impl TransactionSet {
|
|||||||
fn drop(&mut self, sender: &Address, nonce: &U256) -> Option<TransactionOrder> {
|
fn drop(&mut self, sender: &Address, nonce: &U256) -> Option<TransactionOrder> {
|
||||||
if let Some(tx_order) = self.by_address.remove(sender, nonce) {
|
if let Some(tx_order) = self.by_address.remove(sender, nonce) {
|
||||||
self.by_priority.remove(&tx_order);
|
self.by_priority.remove(&tx_order);
|
||||||
|
assert_eq!(self.by_priority.len(), self.by_address.len());
|
||||||
return Some(tx_order);
|
return Some(tx_order);
|
||||||
}
|
}
|
||||||
|
assert_eq!(self.by_priority.len(), self.by_address.len());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +334,8 @@ const GAS_LIMIT_HYSTERESIS: usize = 10; // %
|
|||||||
pub struct TransactionQueue {
|
pub struct TransactionQueue {
|
||||||
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
|
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
|
||||||
minimal_gas_price: U256,
|
minimal_gas_price: U256,
|
||||||
|
/// The maximum amount of gas any individual transaction may use.
|
||||||
|
tx_gas_limit: U256,
|
||||||
/// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0)
|
/// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0)
|
||||||
gas_limit: U256,
|
gas_limit: U256,
|
||||||
/// Priority queue for transactions that can go to block
|
/// Priority queue for transactions that can go to block
|
||||||
@ -352,11 +357,11 @@ impl Default for TransactionQueue {
|
|||||||
impl TransactionQueue {
|
impl TransactionQueue {
|
||||||
/// Creates new instance of this Queue
|
/// Creates new instance of this Queue
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::with_limit(1024)
|
Self::with_limits(1024, !U256::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create new instance of this Queue with specified limits
|
/// Create new instance of this Queue with specified limits
|
||||||
pub fn with_limit(limit: usize) -> Self {
|
pub fn with_limits(limit: usize, tx_gas_limit: U256) -> Self {
|
||||||
let current = TransactionSet {
|
let current = TransactionSet {
|
||||||
by_priority: BTreeSet::new(),
|
by_priority: BTreeSet::new(),
|
||||||
by_address: Table::new(),
|
by_address: Table::new(),
|
||||||
@ -371,6 +376,7 @@ impl TransactionQueue {
|
|||||||
|
|
||||||
TransactionQueue {
|
TransactionQueue {
|
||||||
minimal_gas_price: U256::zero(),
|
minimal_gas_price: U256::zero(),
|
||||||
|
tx_gas_limit: tx_gas_limit,
|
||||||
gas_limit: !U256::zero(),
|
gas_limit: !U256::zero(),
|
||||||
current: current,
|
current: current,
|
||||||
future: future,
|
future: future,
|
||||||
@ -415,6 +421,12 @@ impl TransactionQueue {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the new limit for the amount of gas any individual transaction may have.
|
||||||
|
/// Any transaction already imported to the queue is not affected.
|
||||||
|
pub fn set_tx_gas_limit(&mut self, limit: U256) {
|
||||||
|
self.tx_gas_limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns current status for this queue
|
/// Returns current status for this queue
|
||||||
pub fn status(&self) -> TransactionQueueStatus {
|
pub fn status(&self) -> TransactionQueueStatus {
|
||||||
TransactionQueueStatus {
|
TransactionQueueStatus {
|
||||||
@ -432,7 +444,9 @@ impl TransactionQueue {
|
|||||||
if tx.gas_price < self.minimal_gas_price {
|
if tx.gas_price < self.minimal_gas_price {
|
||||||
trace!(target: "miner",
|
trace!(target: "miner",
|
||||||
"Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})",
|
"Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})",
|
||||||
tx.hash(), tx.gas_price, self.minimal_gas_price
|
tx.hash(),
|
||||||
|
tx.gas_price,
|
||||||
|
self.minimal_gas_price
|
||||||
);
|
);
|
||||||
|
|
||||||
return Err(Error::Transaction(TransactionError::InsufficientGasPrice {
|
return Err(Error::Transaction(TransactionError::InsufficientGasPrice {
|
||||||
@ -443,10 +457,13 @@ impl TransactionQueue {
|
|||||||
|
|
||||||
try!(tx.check_low_s());
|
try!(tx.check_low_s());
|
||||||
|
|
||||||
if tx.gas > self.gas_limit {
|
if tx.gas > self.gas_limit || tx.gas > self.tx_gas_limit {
|
||||||
trace!(target: "miner",
|
trace!(target: "miner",
|
||||||
"Dropping transaction above gas limit: {:?} ({} > {})",
|
"Dropping transaction above gas limit: {:?} ({} > min({}, {}))",
|
||||||
tx.hash(), tx.gas, self.gas_limit
|
tx.hash(),
|
||||||
|
tx.gas,
|
||||||
|
self.gas_limit,
|
||||||
|
self.tx_gas_limit
|
||||||
);
|
);
|
||||||
|
|
||||||
return Err(Error::Transaction(TransactionError::GasLimitExceeded {
|
return Err(Error::Transaction(TransactionError::GasLimitExceeded {
|
||||||
@ -460,15 +477,22 @@ impl TransactionQueue {
|
|||||||
|
|
||||||
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
|
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
|
||||||
if client_account.balance < cost {
|
if client_account.balance < cost {
|
||||||
trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})",
|
trace!(target: "miner",
|
||||||
vtx.hash(), client_account.balance, cost);
|
"Dropping transaction without sufficient balance: {:?} ({} < {})",
|
||||||
|
vtx.hash(),
|
||||||
|
client_account.balance,
|
||||||
|
cost
|
||||||
|
);
|
||||||
|
|
||||||
return Err(Error::Transaction(TransactionError::InsufficientBalance {
|
return Err(Error::Transaction(TransactionError::InsufficientBalance {
|
||||||
cost: cost,
|
cost: cost,
|
||||||
balance: client_account.balance
|
balance: client_account.balance
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.import_tx(vtx, client_account.nonce).map_err(Error::Transaction)
|
let r = self.import_tx(vtx, client_account.nonce).map_err(Error::Transaction);
|
||||||
|
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
||||||
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all transactions from particular sender up to (excluding) given client (state) nonce.
|
/// Removes all transactions from particular sender up to (excluding) given client (state) nonce.
|
||||||
@ -484,6 +508,7 @@ impl TransactionQueue {
|
|||||||
// And now lets check if there is some batch of transactions in future
|
// And now lets check if there is some batch of transactions in future
|
||||||
// that should be placed in current. It should also update last_nonces.
|
// that should be placed in current. It should also update last_nonces.
|
||||||
self.move_matching_future_to_current(sender, client_nonce, client_nonce);
|
self.move_matching_future_to_current(sender, client_nonce, client_nonce);
|
||||||
|
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes invalid transaction identified by hash from queue.
|
/// Removes invalid transaction identified by hash from queue.
|
||||||
@ -493,6 +518,8 @@ impl TransactionQueue {
|
|||||||
/// If gap is introduced marks subsequent transactions as future
|
/// If gap is introduced marks subsequent transactions as future
|
||||||
pub fn remove_invalid<T>(&mut self, transaction_hash: &H256, fetch_account: &T)
|
pub fn remove_invalid<T>(&mut self, transaction_hash: &H256, fetch_account: &T)
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
|
|
||||||
|
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
||||||
let transaction = self.by_hash.remove(transaction_hash);
|
let transaction = self.by_hash.remove(transaction_hash);
|
||||||
if transaction.is_none() {
|
if transaction.is_none() {
|
||||||
// We don't know this transaction
|
// We don't know this transaction
|
||||||
@ -511,22 +538,17 @@ impl TransactionQueue {
|
|||||||
// And now lets check if there is some chain of transactions in future
|
// And now lets check if there is some chain of transactions in future
|
||||||
// that should be placed in current
|
// that should be placed in current
|
||||||
self.move_matching_future_to_current(sender, current_nonce, current_nonce);
|
self.move_matching_future_to_current(sender, current_nonce, current_nonce);
|
||||||
|
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from current
|
// Remove from current
|
||||||
let order = self.current.drop(&sender, &nonce);
|
let order = self.current.drop(&sender, &nonce);
|
||||||
if order.is_some() {
|
if order.is_some() {
|
||||||
// We will either move transaction to future or remove it completely
|
// This will keep consistency in queue
|
||||||
// so there will be no transactions from this sender in current
|
// Moves all to future and then promotes a batch from current:
|
||||||
self.last_nonces.remove(&sender);
|
self.remove_all(sender, current_nonce);
|
||||||
// First update height of transactions in future to avoid collisions
|
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
||||||
self.update_future(&sender, current_nonce);
|
|
||||||
// This should move all current transactions to future and remove old transactions
|
|
||||||
self.move_all_to_future(&sender, current_nonce);
|
|
||||||
// And now lets check if there is some chain of transactions in future
|
|
||||||
// that should be placed in current. It should also update last_nonces.
|
|
||||||
self.move_matching_future_to_current(sender, current_nonce, current_nonce);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -545,7 +567,7 @@ impl TransactionQueue {
|
|||||||
} else {
|
} else {
|
||||||
trace!(target: "miner", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
|
trace!(target: "miner", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
|
||||||
// Remove the transaction completely
|
// Remove the transaction completely
|
||||||
self.by_hash.remove(&order.hash);
|
self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -565,7 +587,7 @@ impl TransactionQueue {
|
|||||||
self.future.insert(*sender, k, order.update_height(k, current_nonce));
|
self.future.insert(*sender, k, order.update_height(k, current_nonce));
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "miner", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
|
trace!(target: "miner", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
|
||||||
self.by_hash.remove(&order.hash);
|
self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.future.enforce_limit(&mut self.by_hash);
|
self.future.enforce_limit(&mut self.by_hash);
|
||||||
@ -664,21 +686,27 @@ impl TransactionQueue {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.map_or(state_nonce, |n| n + U256::one());
|
.map_or(state_nonce, |n| n + U256::one());
|
||||||
|
|
||||||
// Check height
|
// The transaction might be old, let's check that.
|
||||||
if nonce > next_nonce {
|
// This has to be the first test, otherwise calculating
|
||||||
// We have a gap - put to future
|
// nonce height would result in overflow.
|
||||||
try!(check_too_cheap(Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash)));
|
if nonce < state_nonce {
|
||||||
try!(check_if_removed(&address, &nonce, self.future.enforce_limit(&mut self.by_hash)));
|
|
||||||
return Ok(TransactionImportResult::Future);
|
|
||||||
} else if nonce < state_nonce {
|
|
||||||
// Droping transaction
|
// Droping transaction
|
||||||
trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
|
trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
|
||||||
return Err(TransactionError::Old);
|
return Err(TransactionError::Old);
|
||||||
|
} else if nonce > next_nonce {
|
||||||
|
// We have a gap - put to future.
|
||||||
|
// Update nonces of transactions in future (remove old transactions)
|
||||||
|
self.update_future(&address, state_nonce);
|
||||||
|
// Insert transaction (or replace old one with lower gas price)
|
||||||
|
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.future, &mut self.by_hash)));
|
||||||
|
// Return an error if this transaction is not imported because of limit.
|
||||||
|
try!(check_if_removed(&address, &nonce, self.future.enforce_limit(&mut self.by_hash)));
|
||||||
|
return Ok(TransactionImportResult::Future);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash)));
|
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash)));
|
||||||
// Keep track of highest nonce stored in current
|
// Keep track of highest nonce stored in current
|
||||||
self.last_nonces.insert(address, nonce);
|
let new_max = self.last_nonces.get(&address).map_or(nonce, |n| cmp::max(nonce, *n));
|
||||||
|
self.last_nonces.insert(address, new_max);
|
||||||
// Update nonces of transactions in future
|
// Update nonces of transactions in future
|
||||||
self.update_future(&address, state_nonce);
|
self.update_future(&address, state_nonce);
|
||||||
// Maybe there are some more items waiting in future?
|
// Maybe there are some more items waiting in future?
|
||||||
@ -687,15 +715,16 @@ impl TransactionQueue {
|
|||||||
// same (sender, nonce), but above function would not move it.
|
// same (sender, nonce), but above function would not move it.
|
||||||
if let Some(order) = self.future.drop(&address, &nonce) {
|
if let Some(order) = self.future.drop(&address, &nonce) {
|
||||||
// Let's insert that transaction to current (if it has higher gas_price)
|
// Let's insert that transaction to current (if it has higher gas_price)
|
||||||
let future_tx = self.by_hash.remove(&order.hash).unwrap();
|
let future_tx = self.by_hash.remove(&order.hash).expect("All transactions in `future` are always in `by_hash`.");
|
||||||
try!(check_too_cheap(Self::replace_transaction(future_tx, state_nonce, &mut self.current, &mut self.by_hash)));
|
// if transaction in `current` (then one we are importing) is replaced it means that it has to low gas_price
|
||||||
|
try!(check_too_cheap(!Self::replace_transaction(future_tx, state_nonce, &mut self.current, &mut self.by_hash)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also enforce the limit
|
// Also enforce the limit
|
||||||
let removed = self.current.enforce_limit(&mut self.by_hash);
|
let removed = self.current.enforce_limit(&mut self.by_hash);
|
||||||
// If some transaction were removed because of limit we need to update last_nonces also.
|
// If some transaction were removed because of limit we need to update last_nonces also.
|
||||||
self.update_last_nonces(&removed);
|
self.update_last_nonces(&removed);
|
||||||
// Trigger error if we were removed.
|
// Trigger error if the transaction we are importing was removed.
|
||||||
try!(check_if_removed(&address, &nonce, removed));
|
try!(check_if_removed(&address, &nonce, removed));
|
||||||
|
|
||||||
trace!(target: "miner", "status: {:?}", self.status());
|
trace!(target: "miner", "status: {:?}", self.status());
|
||||||
@ -703,9 +732,9 @@ impl TransactionQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Updates
|
/// Updates
|
||||||
fn update_last_nonces(&mut self, removed_max_nonces: &Option<HashMap<Address, U256>>) {
|
fn update_last_nonces(&mut self, removed_min_nonces: &Option<HashMap<Address, U256>>) {
|
||||||
if let Some(ref max_nonces) = *removed_max_nonces {
|
if let Some(ref min_nonces) = *removed_min_nonces {
|
||||||
for (sender, nonce) in max_nonces.iter() {
|
for (sender, nonce) in min_nonces.iter() {
|
||||||
if *nonce == U256::zero() {
|
if *nonce == U256::zero() {
|
||||||
self.last_nonces.remove(sender);
|
self.last_nonces.remove(sender);
|
||||||
} else {
|
} else {
|
||||||
@ -728,7 +757,9 @@ impl TransactionQueue {
|
|||||||
let address = tx.sender();
|
let address = tx.sender();
|
||||||
let nonce = tx.nonce();
|
let nonce = tx.nonce();
|
||||||
|
|
||||||
by_hash.insert(hash, tx);
|
let old_hash = by_hash.insert(hash, tx);
|
||||||
|
assert!(old_hash.is_none(), "Each hash has to be inserted exactly once.");
|
||||||
|
|
||||||
|
|
||||||
if let Some(old) = set.insert(address, nonce, order.clone()) {
|
if let Some(old) = set.insert(address, nonce, order.clone()) {
|
||||||
// There was already transaction in queue. Let's check which one should stay
|
// There was already transaction in queue. Let's check which one should stay
|
||||||
@ -738,11 +769,11 @@ impl TransactionQueue {
|
|||||||
// Put back old transaction since it has greater priority (higher gas_price)
|
// Put back old transaction since it has greater priority (higher gas_price)
|
||||||
set.insert(address, nonce, old);
|
set.insert(address, nonce, old);
|
||||||
// and remove new one
|
// and remove new one
|
||||||
by_hash.remove(&hash);
|
by_hash.remove(&hash).expect("The hash has been just inserted and no other line is altering `by_hash`.");
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
// Make sure we remove old transaction entirely
|
// Make sure we remove old transaction entirely
|
||||||
by_hash.remove(&old.hash);
|
by_hash.remove(&old.hash).expect("The hash is coming from `future` so it has to be in `by_hash`.");
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -762,7 +793,7 @@ fn check_too_cheap(is_in: bool) -> Result<(), TransactionError> {
|
|||||||
fn check_if_removed(sender: &Address, nonce: &U256, dropped: Option<HashMap<Address, U256>>) -> Result<(), TransactionError> {
|
fn check_if_removed(sender: &Address, nonce: &U256, dropped: Option<HashMap<Address, U256>>) -> Result<(), TransactionError> {
|
||||||
match dropped {
|
match dropped {
|
||||||
Some(ref dropped) => match dropped.get(sender) {
|
Some(ref dropped) => match dropped.get(sender) {
|
||||||
Some(max) if nonce <= max => {
|
Some(min) if nonce >= min => {
|
||||||
Err(TransactionError::LimitReached)
|
Err(TransactionError::LimitReached)
|
||||||
},
|
},
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
@ -939,7 +970,7 @@ mod test {
|
|||||||
let res = txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External);
|
let res = txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External);
|
||||||
|
|
||||||
// and then there should be only one transaction in current (the one with higher gas_price)
|
// and then there should be only one transaction in current (the one with higher gas_price)
|
||||||
assert_eq!(unwrap_tx_err(res), TransactionError::TooCheapToReplace);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
assert_eq!(txq.status().pending, 1);
|
assert_eq!(txq.status().pending, 1);
|
||||||
assert_eq!(txq.status().future, 0);
|
assert_eq!(txq.status().future, 0);
|
||||||
assert_eq!(txq.current.by_priority.len(), 1);
|
assert_eq!(txq.current.by_priority.len(), 1);
|
||||||
@ -1087,7 +1118,28 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_prioritize_local_transactions() {
|
fn should_prioritize_local_transactions_within_same_nonce_height() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::new();
|
||||||
|
let tx = new_tx();
|
||||||
|
// the second one has same nonce but higher `gas_price`
|
||||||
|
let (_, tx2) = new_similar_txs();
|
||||||
|
|
||||||
|
// when
|
||||||
|
// first insert the one with higher gas price
|
||||||
|
txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External).unwrap();
|
||||||
|
// then the one with lower gas price, but local
|
||||||
|
txq.add(tx.clone(), &default_nonce, TransactionOrigin::Local).unwrap();
|
||||||
|
|
||||||
|
// then
|
||||||
|
let top = txq.top_transactions();
|
||||||
|
assert_eq!(top[0], tx); // local should be first
|
||||||
|
assert_eq!(top[1], tx2);
|
||||||
|
assert_eq!(top.len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_not_prioritize_local_transactions_with_different_nonce_height() {
|
||||||
// given
|
// given
|
||||||
let mut txq = TransactionQueue::new();
|
let mut txq = TransactionQueue::new();
|
||||||
let (tx, tx2) = new_txs(U256::from(1));
|
let (tx, tx2) = new_txs(U256::from(1));
|
||||||
@ -1098,8 +1150,8 @@ mod test {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
let top = txq.top_transactions();
|
let top = txq.top_transactions();
|
||||||
assert_eq!(top[0], tx2);
|
assert_eq!(top[0], tx);
|
||||||
assert_eq!(top[1], tx);
|
assert_eq!(top[1], tx2);
|
||||||
assert_eq!(top.len(), 2);
|
assert_eq!(top.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,7 +1307,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_drop_old_transactions_when_hitting_the_limit() {
|
fn should_drop_old_transactions_when_hitting_the_limit() {
|
||||||
// given
|
// given
|
||||||
let mut txq = TransactionQueue::with_limit(1);
|
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
|
||||||
let (tx, tx2) = new_txs(U256::one());
|
let (tx, tx2) = new_txs(U256::one());
|
||||||
let sender = tx.sender().unwrap();
|
let sender = tx.sender().unwrap();
|
||||||
let nonce = tx.nonce;
|
let nonce = tx.nonce;
|
||||||
@ -1277,7 +1329,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_correct_nonces_when_dropped_because_of_limit() {
|
fn should_return_correct_nonces_when_dropped_because_of_limit() {
|
||||||
// given
|
// given
|
||||||
let mut txq = TransactionQueue::with_limit(2);
|
let mut txq = TransactionQueue::with_limits(2, !U256::zero());
|
||||||
let tx = new_tx();
|
let tx = new_tx();
|
||||||
let (tx1, tx2) = new_txs(U256::one());
|
let (tx1, tx2) = new_txs(U256::one());
|
||||||
let sender = tx1.sender().unwrap();
|
let sender = tx1.sender().unwrap();
|
||||||
@ -1298,7 +1350,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_limit_future_transactions() {
|
fn should_limit_future_transactions() {
|
||||||
let mut txq = TransactionQueue::with_limit(1);
|
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
|
||||||
txq.current.set_limit(10);
|
txq.current.set_limit(10);
|
||||||
let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(4), U256::from(1));
|
let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(4), U256::from(1));
|
||||||
let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(4), U256::from(2));
|
let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(4), U256::from(2));
|
||||||
@ -1555,4 +1607,54 @@ mod test {
|
|||||||
assert_eq!(txq.has_local_pending_transactions(), true);
|
assert_eq!(txq.has_local_pending_transactions(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_keep_right_order_in_future() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
|
||||||
|
let (tx1, tx2) = new_txs(U256::from(1));
|
||||||
|
let prev_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce - U256::one(), balance:
|
||||||
|
default_nonce(a).balance };
|
||||||
|
|
||||||
|
// when
|
||||||
|
assert_eq!(txq.add(tx2, &prev_nonce, TransactionOrigin::External).unwrap(), TransactionImportResult::Future);
|
||||||
|
assert_eq!(txq.add(tx1.clone(), &prev_nonce, TransactionOrigin::External).unwrap(), TransactionImportResult::Future);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(txq.future.by_priority.len(), 1);
|
||||||
|
assert_eq!(txq.future.by_priority.iter().next().unwrap().hash, tx1.hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_correct_last_nonce() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::new();
|
||||||
|
let (tx1, tx2, tx2_2, tx3) = {
|
||||||
|
let keypair = KeyPair::create().unwrap();
|
||||||
|
let secret = &keypair.secret();
|
||||||
|
let nonce = U256::from(123);
|
||||||
|
let tx = new_unsigned_tx(nonce);
|
||||||
|
let tx2 = new_unsigned_tx(nonce + 1.into());
|
||||||
|
let mut tx2_2 = new_unsigned_tx(nonce + 1.into());
|
||||||
|
tx2_2.gas_price = U256::from(5);
|
||||||
|
let tx3 = new_unsigned_tx(nonce + 2.into());
|
||||||
|
|
||||||
|
|
||||||
|
(tx.sign(secret), tx2.sign(secret), tx2_2.sign(secret), tx3.sign(secret))
|
||||||
|
};
|
||||||
|
let sender = tx1.sender().unwrap();
|
||||||
|
txq.add(tx1, &default_nonce, TransactionOrigin::Local).unwrap();
|
||||||
|
txq.add(tx2, &default_nonce, TransactionOrigin::Local).unwrap();
|
||||||
|
txq.add(tx3, &default_nonce, TransactionOrigin::Local).unwrap();
|
||||||
|
assert_eq!(txq.future.by_priority.len(), 0);
|
||||||
|
assert_eq!(txq.current.by_priority.len(), 3);
|
||||||
|
|
||||||
|
// when
|
||||||
|
let res = txq.add(tx2_2, &default_nonce, TransactionOrigin::Local);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into());
|
||||||
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
|
assert_eq!(txq.current.by_priority.len(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,12 @@ pub enum SyncMessage {
|
|||||||
NewChainHead,
|
NewChainHead,
|
||||||
/// A block is ready
|
/// A block is ready
|
||||||
BlockVerified,
|
BlockVerified,
|
||||||
|
/// New transaction RLPs are ready to be imported
|
||||||
|
NewTransactions(Vec<Bytes>),
|
||||||
|
/// Start network command.
|
||||||
|
StartNetwork,
|
||||||
|
/// Stop network command.
|
||||||
|
StopNetwork,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IO Message type used for Network service
|
/// IO Message type used for Network service
|
||||||
@ -48,17 +54,20 @@ pub type NetSyncMessage = NetworkIoMessage<SyncMessage>;
|
|||||||
|
|
||||||
/// Client service setup. Creates and registers client and network services with the IO subsystem.
|
/// Client service setup. Creates and registers client and network services with the IO subsystem.
|
||||||
pub struct ClientService {
|
pub struct ClientService {
|
||||||
net_service: NetworkService<SyncMessage>,
|
net_service: Arc<NetworkService<SyncMessage>>,
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
panic_handler: Arc<PanicHandler>
|
panic_handler: Arc<PanicHandler>
|
||||||
}
|
}
|
||||||
|
|
||||||
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, miner: Arc<Miner>) -> Result<ClientService, Error> {
|
pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path, miner: Arc<Miner>, enable_network: bool) -> 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 net_service = try!(NetworkService::new(net_config));
|
||||||
panic_handler.forward_from(&net_service);
|
panic_handler.forward_from(&net_service);
|
||||||
|
if enable_network {
|
||||||
|
try!(net_service.start());
|
||||||
|
}
|
||||||
|
|
||||||
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());
|
||||||
@ -70,7 +79,7 @@ impl ClientService {
|
|||||||
try!(net_service.io().register_handler(client_io));
|
try!(net_service.io().register_handler(client_io));
|
||||||
|
|
||||||
Ok(ClientService {
|
Ok(ClientService {
|
||||||
net_service: net_service,
|
net_service: Arc::new(net_service),
|
||||||
client: client,
|
client: client,
|
||||||
panic_handler: panic_handler,
|
panic_handler: panic_handler,
|
||||||
})
|
})
|
||||||
@ -82,8 +91,8 @@ impl ClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get general IO interface
|
/// Get general IO interface
|
||||||
pub fn io(&mut self) -> &mut IoService<NetSyncMessage> {
|
pub fn register_io_handler(&self, handler: Arc<IoHandler<NetSyncMessage> + Send>) -> Result<(), IoError> {
|
||||||
self.net_service.io()
|
self.net_service.io().register_handler(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get client interface
|
/// Get client interface
|
||||||
@ -92,8 +101,8 @@ impl ClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get network service component
|
/// Get network service component
|
||||||
pub fn network(&mut self) -> &mut NetworkService<SyncMessage> {
|
pub fn network(&mut self) -> Arc<NetworkService<SyncMessage>> {
|
||||||
&mut self.net_service
|
self.net_service.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +138,9 @@ impl IoHandler<NetSyncMessage> for ClientIoHandler {
|
|||||||
SyncMessage::BlockVerified => {
|
SyncMessage::BlockVerified => {
|
||||||
self.client.import_verified_blocks(&io.channel());
|
self.client.import_verified_blocks(&io.channel());
|
||||||
},
|
},
|
||||||
|
SyncMessage::NewTransactions(ref transactions) => {
|
||||||
|
self.client.import_queued_transactions(&transactions);
|
||||||
|
},
|
||||||
_ => {}, // ignore other messages
|
_ => {}, // ignore other messages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,9 +159,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_can_be_started() {
|
fn it_can_be_started() {
|
||||||
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(), Arc::new(Miner::default()));
|
let service = ClientService::start(
|
||||||
|
ClientConfig::default(),
|
||||||
|
get_test_spec(),
|
||||||
|
NetworkConfiguration::new_local(),
|
||||||
|
&temp_path.as_path(),
|
||||||
|
Arc::new(Miner::with_spec(get_test_spec())),
|
||||||
|
false
|
||||||
|
);
|
||||||
assert!(service.is_ok());
|
assert!(service.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ impl Account {
|
|||||||
if self.code_hash == SHA3_EMPTY {
|
if self.code_hash == SHA3_EMPTY {
|
||||||
account_stream.append(&false).append_empty_data();
|
account_stream.append(&false).append_empty_data();
|
||||||
} else {
|
} else {
|
||||||
match acct_db.lookup(&self.code_hash) {
|
match acct_db.get(&self.code_hash) {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
account_stream.append(&true).append(&c);
|
account_stream.append(&true).append(&c);
|
||||||
}
|
}
|
||||||
|
@ -244,6 +244,11 @@ impl Spec {
|
|||||||
pub fn new_test() -> Spec {
|
pub fn new_test() -> Spec {
|
||||||
Spec::load(include_bytes!("../../res/null_morden.json"))
|
Spec::load(include_bytes!("../../res/null_morden.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new Spec which is a NullEngine consensus with a premine of address whose secret is sha3('').
|
||||||
|
pub fn new_null() -> Spec {
|
||||||
|
Spec::load(include_bytes!("../../res/null.json"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -222,6 +222,30 @@ impl State {
|
|||||||
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
|
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
|
||||||
let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options));
|
let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options));
|
||||||
|
|
||||||
|
let broken_dao = H256::from("6a5d24750f78441e56fec050dc52fe8e911976485b7472faac7464a176a67caa");
|
||||||
|
|
||||||
|
// dao attack soft fork
|
||||||
|
if engine.schedule(&env_info).reject_dao_transactions {
|
||||||
|
let whitelisted = if let Action::Call(to) = t.action {
|
||||||
|
to == Address::from("Da4a4626d3E16e094De3225A751aAb7128e96526") ||
|
||||||
|
to == Address::from("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334")
|
||||||
|
} else { false };
|
||||||
|
if !whitelisted {
|
||||||
|
// collect all the addresses which have changed.
|
||||||
|
let addresses = self.cache.borrow().iter().map(|(addr, _)| addr.clone()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for a in &addresses {
|
||||||
|
if self.code(a).map_or(false, |c| c.sha3() == broken_dao) {
|
||||||
|
// Figure out if the balance has been reduced.
|
||||||
|
let maybe_original = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR).get(&a).map(Account::from_rlp);
|
||||||
|
if maybe_original.map_or(false, |original| *original.balance() > self.balance(a)) {
|
||||||
|
return Err(Error::Transaction(TransactionError::DAORescue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO uncomment once to_pod() works correctly.
|
// TODO uncomment once to_pod() works correctly.
|
||||||
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
|
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
|
||||||
self.commit();
|
self.commit();
|
||||||
|
@ -24,7 +24,7 @@ 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(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
|
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), IoChannel::disconnected()).unwrap();
|
||||||
client.import_verified_blocks(&IoChannel::disconnected());
|
client.import_verified_blocks(&IoChannel::disconnected());
|
||||||
client.flush_queue();
|
client.flush_queue();
|
||||||
}
|
}
|
||||||
@ -42,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(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
|
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), 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");
|
||||||
@ -57,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(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
|
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), 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());
|
||||||
@ -112,6 +112,19 @@ fn can_collect_garbage() {
|
|||||||
assert!(client.blockchain_cache_info().blocks < 100 * 1024);
|
assert!(client.blockchain_cache_info().blocks < 100 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(feature="dev", allow(useless_vec))]
|
||||||
|
fn can_generate_gas_price_statistics() {
|
||||||
|
let client_result = generate_dummy_client_with_data(16, 1, &vec_into![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
|
||||||
|
let client = client_result.reference();
|
||||||
|
let s = client.gas_price_statistics(8, 8).unwrap();
|
||||||
|
assert_eq!(s, vec_into![8, 8, 9, 10, 11, 12, 13, 14, 15]);
|
||||||
|
let s = client.gas_price_statistics(16, 8).unwrap();
|
||||||
|
assert_eq!(s, vec_into![0, 1, 3, 5, 7, 9, 11, 13, 15]);
|
||||||
|
let s = client.gas_price_statistics(32, 8).unwrap();
|
||||||
|
assert_eq!(s, vec_into![0, 1, 3, 5, 7, 9, 11, 13, 15]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_handle_long_fork() {
|
fn can_handle_long_fork() {
|
||||||
let client_result = generate_dummy_client(1200);
|
let client_result = generate_dummy_client(1200);
|
||||||
@ -137,8 +150,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_open_block(Address::default(), 31415926.into(), vec![]).close();
|
let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).close();
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
use client::{BlockChainClient, Client, ClientConfig};
|
use client::{BlockChainClient, Client, ClientConfig};
|
||||||
use common::*;
|
use common::*;
|
||||||
use spec::*;
|
use spec::*;
|
||||||
|
use block::{OpenBlock};
|
||||||
use blockchain::{BlockChain, Config as BlockChainConfig};
|
use blockchain::{BlockChain, Config as BlockChainConfig};
|
||||||
use state::*;
|
use state::*;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
@ -85,6 +86,7 @@ impl Engine for TestEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move everything over to get_null_spec.
|
||||||
pub fn get_test_spec() -> Spec {
|
pub fn get_test_spec() -> Spec {
|
||||||
Spec::new_test()
|
Spec::new_test()
|
||||||
}
|
}
|
||||||
@ -126,7 +128,7 @@ fn create_unverifiable_block(order: u32, parent_hash: H256) -> Bytes {
|
|||||||
create_test_block(&create_unverifiable_block_header(order, parent_hash))
|
create_test_block(&create_unverifiable_block_header(order, parent_hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTransaction], uncles: &[Header]) -> Bytes {
|
pub fn create_test_block_with_data(header: &Header, transactions: &[SignedTransaction], uncles: &[Header]) -> Bytes {
|
||||||
let mut rlp = RlpStream::new_list(3);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
rlp.append(header);
|
rlp.append(header);
|
||||||
rlp.begin_list(transactions.len());
|
rlp.begin_list(transactions.len());
|
||||||
@ -138,33 +140,75 @@ 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>> {
|
||||||
|
generate_dummy_client_with_spec_and_data(Spec::new_test, block_number, 0, &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_dummy_client_with_data(block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult<Arc<Client>> {
|
||||||
|
generate_dummy_client_with_spec_and_data(Spec::new_null, block_number, txs_per_block, tx_gas_prices)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult<Arc<Client>> where F: Fn()->Spec {
|
||||||
let dir = RandomTempPath::new();
|
let dir = RandomTempPath::new();
|
||||||
|
|
||||||
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 client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), IoChannel::disconnected()).unwrap();
|
||||||
let test_engine = &test_spec.engine;
|
let test_engine = &test_spec.engine;
|
||||||
let state_root = test_spec.genesis_header().state_root;
|
|
||||||
let mut rolling_hash = test_spec.genesis_header().hash();
|
let mut db_result = get_temp_journal_db();
|
||||||
let mut rolling_block_number = 1;
|
let mut db = db_result.take();
|
||||||
|
test_spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
|
let vm_factory = Default::default();
|
||||||
|
let genesis_header = test_spec.genesis_header();
|
||||||
|
|
||||||
let mut rolling_timestamp = 40;
|
let mut rolling_timestamp = 40;
|
||||||
|
let mut last_hashes = vec![];
|
||||||
|
let mut last_header = genesis_header.clone();
|
||||||
|
|
||||||
|
let kp = KeyPair::from_secret("".sha3()).unwrap() ;
|
||||||
|
let author = kp.address();
|
||||||
|
|
||||||
|
let mut n = 0;
|
||||||
for _ in 0..block_number {
|
for _ in 0..block_number {
|
||||||
let mut header = Header::new();
|
last_hashes.push(last_header.hash());
|
||||||
|
|
||||||
header.gas_limit = test_engine.params().min_gas_limit;
|
// forge block.
|
||||||
header.difficulty = U256::from(0x20000);
|
let mut b = OpenBlock::new(
|
||||||
header.timestamp = rolling_timestamp;
|
test_engine.deref(),
|
||||||
header.number = rolling_block_number;
|
&vm_factory,
|
||||||
header.parent_hash = rolling_hash;
|
false,
|
||||||
header.state_root = state_root.clone();
|
db,
|
||||||
|
&last_header,
|
||||||
|
last_hashes.clone(),
|
||||||
|
None,
|
||||||
|
author.clone(),
|
||||||
|
(3141562.into(), 31415620.into()),
|
||||||
|
vec![]
|
||||||
|
).unwrap();
|
||||||
|
b.set_difficulty(U256::from(0x20000));
|
||||||
|
rolling_timestamp += 10;
|
||||||
|
b.set_timestamp(rolling_timestamp);
|
||||||
|
|
||||||
rolling_hash = header.hash();
|
// first block we don't have any balance, so can't send any transactions.
|
||||||
rolling_block_number = rolling_block_number + 1;
|
for _ in 0..txs_per_block {
|
||||||
rolling_timestamp = rolling_timestamp + 10;
|
b.push_transaction(Transaction {
|
||||||
|
nonce: n.into(),
|
||||||
|
gas_price: tx_gas_prices[n % tx_gas_prices.len()],
|
||||||
|
gas: 100000.into(),
|
||||||
|
action: Action::Create,
|
||||||
|
data: vec![],
|
||||||
|
value: U256::zero(),
|
||||||
|
}.sign(kp.secret()), None).unwrap();
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = client.import_block(create_test_block(&header)) {
|
let b = b.close_and_lock().seal(test_engine.deref(), vec![]).unwrap();
|
||||||
|
|
||||||
|
if let Err(e) = client.import_block(b.rlp_bytes()) {
|
||||||
panic!("error importing block which is valid by definition: {:?}", e);
|
panic!("error importing block which is valid by definition: {:?}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_header = BlockView::new(&b.rlp_bytes()).header();
|
||||||
|
db = b.drain();
|
||||||
}
|
}
|
||||||
client.flush_queue();
|
client.flush_queue();
|
||||||
client.import_verified_blocks(&IoChannel::disconnected());
|
client.import_verified_blocks(&IoChannel::disconnected());
|
||||||
@ -206,7 +250,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(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
|
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), 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");
|
||||||
@ -259,7 +303,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult<BlockChain> {
|
|||||||
|
|
||||||
pub fn get_temp_journal_db() -> GuardedTempResult<Box<JournalDB>> {
|
pub fn get_temp_journal_db() -> GuardedTempResult<Box<JournalDB>> {
|
||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let journal_db = journaldb::new(temp.as_str(), journaldb::Algorithm::EarlyMerge);
|
let journal_db = journaldb::new(temp.as_str(), journaldb::Algorithm::EarlyMerge, DatabaseConfig::default());
|
||||||
GuardedTempResult {
|
GuardedTempResult {
|
||||||
_temp: temp,
|
_temp: temp,
|
||||||
result: Some(journal_db)
|
result: Some(journal_db)
|
||||||
@ -276,7 +320,7 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_temp_journal_db_in(path: &Path) -> Box<JournalDB> {
|
pub fn get_temp_journal_db_in(path: &Path) -> Box<JournalDB> {
|
||||||
journaldb::new(path.to_str().unwrap(), journaldb::Algorithm::EarlyMerge)
|
journaldb::new(path.to_str().unwrap(), journaldb::Algorithm::EarlyMerge, DatabaseConfig::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_temp_state_in(path: &Path) -> State {
|
pub fn get_temp_state_in(path: &Path) -> State {
|
||||||
|
@ -48,6 +48,8 @@ pub struct Config {
|
|||||||
pub enabled: Switch,
|
pub enabled: Switch,
|
||||||
/// Traces blooms configuration.
|
/// Traces blooms configuration.
|
||||||
pub blooms: BloomConfig,
|
pub blooms: BloomConfig,
|
||||||
|
/// Database cache-size if not default
|
||||||
|
pub db_cache_size: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -57,7 +59,8 @@ impl Default for Config {
|
|||||||
blooms: BloomConfig {
|
blooms: BloomConfig {
|
||||||
levels: 3,
|
levels: 3,
|
||||||
elements_per_index: 16,
|
elements_per_index: 16,
|
||||||
}
|
},
|
||||||
|
db_cache_size: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use std::sync::{RwLock, Arc};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use bloomchain::{Number, Config as BloomConfig};
|
use bloomchain::{Number, Config as BloomConfig};
|
||||||
use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, BloomGroup};
|
use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, BloomGroup};
|
||||||
use util::{H256, H264, Database, DBTransaction};
|
use util::{H256, H264, Database, DatabaseConfig, DBTransaction};
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use trace::{BlockTraces, LocalizedTrace, Config, Switch, Filter, Database as TraceDatabase, ImportRequest,
|
use trace::{BlockTraces, LocalizedTrace, Config, Switch, Filter, Database as TraceDatabase, ImportRequest,
|
||||||
DatabaseExtras, Error};
|
DatabaseExtras, Error};
|
||||||
@ -118,7 +118,12 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
|
|||||||
pub fn new(config: Config, path: &Path, extras: Arc<T>) -> Result<Self, Error> {
|
pub fn new(config: Config, path: &Path, extras: Arc<T>) -> Result<Self, Error> {
|
||||||
let mut tracedb_path = path.to_path_buf();
|
let mut tracedb_path = path.to_path_buf();
|
||||||
tracedb_path.push("tracedb");
|
tracedb_path.push("tracedb");
|
||||||
let tracesdb = Database::open_default(tracedb_path.to_str().unwrap()).unwrap();
|
let tracesdb = match config.db_cache_size {
|
||||||
|
None => Database::open_default(tracedb_path.to_str().unwrap()).unwrap(),
|
||||||
|
Some(db_cache) => Database::open(
|
||||||
|
&DatabaseConfig::with_cache(db_cache),
|
||||||
|
tracedb_path.to_str().unwrap()).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
// check if in previously tracing was enabled
|
// check if in previously tracing was enabled
|
||||||
let old_tracing = match tracesdb.get(b"enabled").unwrap() {
|
let old_tracing = match tracesdb.get(b"enabled").unwrap() {
|
||||||
|
@ -140,8 +140,13 @@ impl Transaction {
|
|||||||
|
|
||||||
/// Signs the transaction as coming from `sender`.
|
/// Signs the transaction as coming from `sender`.
|
||||||
pub fn sign(self, secret: &Secret) -> SignedTransaction {
|
pub fn sign(self, secret: &Secret) -> SignedTransaction {
|
||||||
let sig = ec::sign(secret, &self.hash());
|
let sig = ec::sign(secret, &self.hash()).unwrap();
|
||||||
let (r, s, v) = sig.unwrap().to_rsv();
|
self.with_signature(sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Signs the transaction with signature.
|
||||||
|
pub fn with_signature(self, sig: H520) -> SignedTransaction {
|
||||||
|
let (r, s, v) = sig.to_rsv();
|
||||||
SignedTransaction {
|
SignedTransaction {
|
||||||
unsigned: self,
|
unsigned: self,
|
||||||
r: r,
|
r: r,
|
||||||
|
@ -24,11 +24,11 @@ use super::verification;
|
|||||||
pub struct CanonVerifier;
|
pub struct CanonVerifier;
|
||||||
|
|
||||||
impl Verifier for CanonVerifier {
|
impl Verifier for CanonVerifier {
|
||||||
fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> {
|
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> {
|
||||||
verification::verify_block_family(header, bytes, engine, bc)
|
verification::verify_block_family(header, bytes, engine, bc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> {
|
fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error> {
|
||||||
verification::verify_block_final(expected, got)
|
verification::verify_block_final(expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,32 @@
|
|||||||
pub mod verification;
|
pub mod verification;
|
||||||
pub mod verifier;
|
pub mod verifier;
|
||||||
mod canon_verifier;
|
mod canon_verifier;
|
||||||
#[cfg(test)]
|
|
||||||
mod noop_verifier;
|
mod noop_verifier;
|
||||||
|
|
||||||
pub use self::verification::*;
|
pub use self::verification::*;
|
||||||
pub use self::verifier::Verifier;
|
pub use self::verifier::Verifier;
|
||||||
pub use self::canon_verifier::CanonVerifier;
|
pub use self::canon_verifier::CanonVerifier;
|
||||||
#[cfg(test)]
|
|
||||||
pub use self::noop_verifier::NoopVerifier;
|
pub use self::noop_verifier::NoopVerifier;
|
||||||
|
|
||||||
|
/// Verifier type.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum VerifierType {
|
||||||
|
/// Verifies block normally.
|
||||||
|
Canon,
|
||||||
|
/// Does not verify block at all.
|
||||||
|
/// Used in tests.
|
||||||
|
Noop,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VerifierType {
|
||||||
|
fn default() -> Self {
|
||||||
|
VerifierType::Canon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(v: VerifierType) -> Box<Verifier> {
|
||||||
|
match v {
|
||||||
|
VerifierType::Canon => Box::new(CanonVerifier),
|
||||||
|
VerifierType::Noop => Box::new(NoopVerifier),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,11 +24,11 @@ use super::Verifier;
|
|||||||
pub struct NoopVerifier;
|
pub struct NoopVerifier;
|
||||||
|
|
||||||
impl Verifier for NoopVerifier {
|
impl Verifier for NoopVerifier {
|
||||||
fn verify_block_family(_header: &Header, _bytes: &[u8], _engine: &Engine, _bc: &BlockProvider) -> Result<(), Error> {
|
fn verify_block_family(&self, _header: &Header, _bytes: &[u8], _engine: &Engine, _bc: &BlockProvider) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_final(_expected: &Header, _got: &Header) -> Result<(), Error> {
|
fn verify_block_final(&self, _expected: &Header, _got: &Header) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,7 +361,7 @@ mod tests {
|
|||||||
nonce: U256::from(2)
|
nonce: U256::from(2)
|
||||||
}.sign(&keypair.secret());
|
}.sign(&keypair.secret());
|
||||||
|
|
||||||
let good_transactions = [ &tr1, &tr2 ];
|
let good_transactions = [ tr1.clone(), tr2.clone() ];
|
||||||
|
|
||||||
let diff_inc = U256::from(0x40);
|
let diff_inc = U256::from(0x40);
|
||||||
|
|
||||||
|
@ -21,6 +21,6 @@ use header::Header;
|
|||||||
|
|
||||||
/// Should be used to verify blocks.
|
/// Should be used to verify blocks.
|
||||||
pub trait Verifier: Send + Sync {
|
pub trait Verifier: Send + Sync {
|
||||||
fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
|
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
|
||||||
fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>;
|
fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
@ -1,339 +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/>.
|
|
||||||
|
|
||||||
//! Block oriented views onto rlp.
|
|
||||||
use util::*;
|
|
||||||
use header::*;
|
|
||||||
use transaction::*;
|
|
||||||
|
|
||||||
/// View onto transaction rlp.
|
|
||||||
pub struct TransactionView<'a> {
|
|
||||||
rlp: Rlp<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TransactionView<'a> {
|
|
||||||
/// Creates new view onto block from raw bytes.
|
|
||||||
pub fn new(bytes: &'a [u8]) -> TransactionView<'a> {
|
|
||||||
TransactionView {
|
|
||||||
rlp: Rlp::new(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates new view onto block from rlp.
|
|
||||||
pub fn new_from_rlp(rlp: Rlp<'a>) -> TransactionView<'a> {
|
|
||||||
TransactionView {
|
|
||||||
rlp: rlp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return reference to underlaying rlp.
|
|
||||||
pub fn rlp(&self) -> &Rlp<'a> {
|
|
||||||
&self.rlp
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the nonce field of the transaction.
|
|
||||||
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
|
|
||||||
|
|
||||||
/// Get the gas_price field of the transaction.
|
|
||||||
pub fn gas_price(&self) -> U256 { self.rlp.val_at(1) }
|
|
||||||
|
|
||||||
/// Get the gas field of the transaction.
|
|
||||||
pub fn gas(&self) -> U256 { self.rlp.val_at(2) }
|
|
||||||
|
|
||||||
/// Get the value field of the transaction.
|
|
||||||
pub fn value(&self) -> U256 { self.rlp.val_at(4) }
|
|
||||||
|
|
||||||
/// Get the data field of the transaction.
|
|
||||||
pub fn data(&self) -> Bytes { self.rlp.val_at(5) }
|
|
||||||
|
|
||||||
/// Get the v field of the transaction.
|
|
||||||
pub fn v(&self) -> u8 { let r: u16 = self.rlp.val_at(6); r as u8 }
|
|
||||||
|
|
||||||
/// Get the r field of the transaction.
|
|
||||||
pub fn r(&self) -> U256 { self.rlp.val_at(7) }
|
|
||||||
|
|
||||||
/// Get the s field of the transaction.
|
|
||||||
pub fn s(&self) -> U256 { self.rlp.val_at(8) }
|
|
||||||
|
|
||||||
// TODO: something like pub fn action(&self) -> Action { self.rlp.val_at(3) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Hashable for TransactionView<'a> {
|
|
||||||
fn sha3(&self) -> H256 {
|
|
||||||
self.rlp.as_raw().sha3()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// View onto transaction rlp.
|
|
||||||
pub struct AccountView<'a> {
|
|
||||||
rlp: Rlp<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> AccountView<'a> {
|
|
||||||
/// Creates new view onto block from raw bytes.
|
|
||||||
pub fn new(bytes: &'a [u8]) -> AccountView<'a> {
|
|
||||||
AccountView {
|
|
||||||
rlp: Rlp::new(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates new view onto block from rlp.
|
|
||||||
pub fn new_from_rlp(rlp: Rlp<'a>) -> AccountView<'a> {
|
|
||||||
AccountView {
|
|
||||||
rlp: rlp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return reference to underlaying rlp.
|
|
||||||
pub fn rlp(&self) -> &Rlp<'a> {
|
|
||||||
&self.rlp
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the nonce field of the transaction.
|
|
||||||
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
|
|
||||||
|
|
||||||
/// Get the gas_price field of the transaction.
|
|
||||||
pub fn balance(&self) -> U256 { self.rlp.val_at(1) }
|
|
||||||
|
|
||||||
/// Get the gas field of the transaction.
|
|
||||||
pub fn storage_root(&self) -> H256 { self.rlp.val_at(2) }
|
|
||||||
|
|
||||||
/// Get the value field of the transaction.
|
|
||||||
pub fn code_hash(&self) -> H256 { self.rlp.val_at(3) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// View onto block rlp.
|
|
||||||
pub struct BlockView<'a> {
|
|
||||||
rlp: Rlp<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> BlockView<'a> {
|
|
||||||
/// Creates new view onto block from raw bytes.
|
|
||||||
pub fn new(bytes: &'a [u8]) -> BlockView<'a> {
|
|
||||||
BlockView {
|
|
||||||
rlp: Rlp::new(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates new view onto block from rlp.
|
|
||||||
pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> {
|
|
||||||
BlockView {
|
|
||||||
rlp: rlp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return reference to underlaying rlp.
|
|
||||||
pub fn rlp(&self) -> &Rlp<'a> {
|
|
||||||
&self.rlp
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create new Header object from header rlp.
|
|
||||||
pub fn header(&self) -> Header {
|
|
||||||
self.rlp.val_at(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create new header view onto block head rlp.
|
|
||||||
pub fn header_view(&self) -> HeaderView<'a> {
|
|
||||||
HeaderView::new_from_rlp(self.rlp.at(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
|
||||||
pub fn transactions(&self) -> Vec<SignedTransaction> {
|
|
||||||
self.rlp.val_at(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return List of transactions with additional localization info.
|
|
||||||
pub fn localized_transactions(&self) -> Vec<LocalizedTransaction> {
|
|
||||||
let header = self.header_view();
|
|
||||||
let block_hash = header.sha3();
|
|
||||||
let block_number = header.number();
|
|
||||||
self.transactions()
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, t)| LocalizedTransaction {
|
|
||||||
signed: t,
|
|
||||||
block_hash: block_hash.clone(),
|
|
||||||
block_number: block_number,
|
|
||||||
transaction_index: i
|
|
||||||
}).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return number of transactions in given block, without deserializing them.
|
|
||||||
pub fn transactions_count(&self) -> usize {
|
|
||||||
self.rlp.at(1).iter().count()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
|
||||||
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
|
||||||
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return transaction hashes.
|
|
||||||
pub fn transaction_hashes(&self) -> Vec<H256> {
|
|
||||||
self.rlp.at(1).iter().map(|rlp| rlp.as_raw().sha3()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns transaction at given index without deserializing unnecessary data.
|
|
||||||
pub fn transaction_at(&self, index: usize) -> Option<SignedTransaction> {
|
|
||||||
self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns localized transaction at given index.
|
|
||||||
pub fn localized_transaction_at(&self, index: usize) -> Option<LocalizedTransaction> {
|
|
||||||
let header = self.header_view();
|
|
||||||
let block_hash = header.sha3();
|
|
||||||
let block_number = header.number();
|
|
||||||
self.transaction_at(index).map(|t| LocalizedTransaction {
|
|
||||||
signed: t,
|
|
||||||
block_hash: block_hash,
|
|
||||||
block_number: block_number,
|
|
||||||
transaction_index: index
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return list of uncles of given block.
|
|
||||||
pub fn uncles(&self) -> Vec<Header> {
|
|
||||||
self.rlp.val_at(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return number of uncles in given block, without deserializing them.
|
|
||||||
pub fn uncles_count(&self) -> usize {
|
|
||||||
self.rlp.at(2).iter().count()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
|
||||||
pub fn uncle_views(&self) -> Vec<HeaderView> {
|
|
||||||
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return list of uncle hashes of given block.
|
|
||||||
pub fn uncle_hashes(&self) -> Vec<H256> {
|
|
||||||
self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return nth uncle.
|
|
||||||
pub fn uncle_at(&self, index: usize) -> Option<Header> {
|
|
||||||
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Hashable for BlockView<'a> {
|
|
||||||
fn sha3(&self) -> H256 {
|
|
||||||
self.header_view().sha3()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// View onto block header rlp.
|
|
||||||
pub struct HeaderView<'a> {
|
|
||||||
rlp: Rlp<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HeaderView<'a> {
|
|
||||||
/// Creates new view onto header from raw bytes.
|
|
||||||
pub fn new(bytes: &'a [u8]) -> HeaderView<'a> {
|
|
||||||
HeaderView {
|
|
||||||
rlp: Rlp::new(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates new view onto header from rlp.
|
|
||||||
pub fn new_from_rlp(rlp: Rlp<'a>) -> HeaderView<'a> {
|
|
||||||
HeaderView {
|
|
||||||
rlp: rlp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns header hash.
|
|
||||||
pub fn hash(&self) -> H256 { self.sha3() }
|
|
||||||
|
|
||||||
/// Returns raw rlp.
|
|
||||||
pub fn rlp(&self) -> &Rlp<'a> { &self.rlp }
|
|
||||||
|
|
||||||
/// Returns parent hash.
|
|
||||||
pub fn parent_hash(&self) -> H256 { self.rlp.val_at(0) }
|
|
||||||
|
|
||||||
/// Returns uncles hash.
|
|
||||||
pub fn uncles_hash(&self) -> H256 { self.rlp.val_at(1) }
|
|
||||||
|
|
||||||
/// Returns author.
|
|
||||||
pub fn author(&self) -> Address { self.rlp.val_at(2) }
|
|
||||||
|
|
||||||
/// Returns state root.
|
|
||||||
pub fn state_root(&self) -> H256 { self.rlp.val_at(3) }
|
|
||||||
|
|
||||||
/// Returns transactions root.
|
|
||||||
pub fn transactions_root(&self) -> H256 { self.rlp.val_at(4) }
|
|
||||||
|
|
||||||
/// Returns block receipts root.
|
|
||||||
pub fn receipts_root(&self) -> H256 { self.rlp.val_at(5) }
|
|
||||||
|
|
||||||
/// Returns block log bloom.
|
|
||||||
pub fn log_bloom(&self) -> H2048 { self.rlp.val_at(6) }
|
|
||||||
|
|
||||||
/// Returns block difficulty.
|
|
||||||
pub fn difficulty(&self) -> U256 { self.rlp.val_at(7) }
|
|
||||||
|
|
||||||
/// Returns block number.
|
|
||||||
pub fn number(&self) -> BlockNumber { self.rlp.val_at(8) }
|
|
||||||
|
|
||||||
/// Returns block gas limit.
|
|
||||||
pub fn gas_limit(&self) -> U256 { self.rlp.val_at(9) }
|
|
||||||
|
|
||||||
/// Returns block gas used.
|
|
||||||
pub fn gas_used(&self) -> U256 { self.rlp.val_at(10) }
|
|
||||||
|
|
||||||
/// Returns timestamp.
|
|
||||||
pub fn timestamp(&self) -> u64 { self.rlp.val_at(11) }
|
|
||||||
|
|
||||||
/// Returns block extra data.
|
|
||||||
pub fn extra_data(&self) -> Bytes { self.rlp.val_at(12) }
|
|
||||||
|
|
||||||
/// Returns a vector of post-RLP-encoded seal fields.
|
|
||||||
pub fn seal(&self) -> Vec<Bytes> {
|
|
||||||
let mut seal = vec![];
|
|
||||||
for i in 13..self.rlp.item_count() {
|
|
||||||
seal.push(self.rlp.at(i).as_raw().to_vec());
|
|
||||||
}
|
|
||||||
seal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Hashable for HeaderView<'a> {
|
|
||||||
fn sha3(&self) -> H256 {
|
|
||||||
self.rlp.as_raw().sha3()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use rustc_serialize::hex::FromHex;
|
|
||||||
use super::BlockView;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_header_view_seal_fields() {
|
|
||||||
// that's rlp of block created with ethash engine.
|
|
||||||
let block_rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap();
|
|
||||||
let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap();
|
|
||||||
let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap();
|
|
||||||
|
|
||||||
let block_view = BlockView::new(&block_rlp);
|
|
||||||
let header_view = block_view.header_view();
|
|
||||||
let seal_fields = header_view.seal();
|
|
||||||
assert_eq!(seal_fields.len(), 2);
|
|
||||||
assert_eq!(seal_fields[0], mix_hash);
|
|
||||||
assert_eq!(seal_fields[1], nonce);
|
|
||||||
}
|
|
||||||
}
|
|
167
ethcore/src/views/block.rs
Normal file
167
ethcore/src/views/block.rs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! View onto block rlp.
|
||||||
|
|
||||||
|
use util::*;
|
||||||
|
use header::*;
|
||||||
|
use transaction::*;
|
||||||
|
use super::{TransactionView, HeaderView};
|
||||||
|
|
||||||
|
/// View onto block rlp.
|
||||||
|
pub struct BlockView<'a> {
|
||||||
|
rlp: Rlp<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BlockView<'a> {
|
||||||
|
/// Creates new view onto block from raw bytes.
|
||||||
|
pub fn new(bytes: &'a [u8]) -> BlockView<'a> {
|
||||||
|
BlockView {
|
||||||
|
rlp: Rlp::new(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates new view onto block from rlp.
|
||||||
|
pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> {
|
||||||
|
BlockView {
|
||||||
|
rlp: rlp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Block header hash.
|
||||||
|
pub fn hash(&self) -> H256 {
|
||||||
|
self.sha3()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return reference to underlaying rlp.
|
||||||
|
pub fn rlp(&self) -> &Rlp<'a> {
|
||||||
|
&self.rlp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create new Header object from header rlp.
|
||||||
|
pub fn header(&self) -> Header {
|
||||||
|
self.rlp.val_at(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create new header view obto block head rlp.
|
||||||
|
pub fn header_view(&self) -> HeaderView<'a> {
|
||||||
|
HeaderView::new_from_rlp(self.rlp.at(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return List of transactions in given block.
|
||||||
|
pub fn transactions(&self) -> Vec<SignedTransaction> {
|
||||||
|
self.rlp.val_at(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return List of transactions with additional localization info.
|
||||||
|
pub fn localized_transactions(&self) -> Vec<LocalizedTransaction> {
|
||||||
|
let header = self.header_view();
|
||||||
|
let block_hash = header.sha3();
|
||||||
|
let block_number = header.number();
|
||||||
|
self.transactions()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, t)| LocalizedTransaction {
|
||||||
|
signed: t,
|
||||||
|
block_hash: block_hash.clone(),
|
||||||
|
block_number: block_number,
|
||||||
|
transaction_index: i
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return number of transactions in given block, without deserializing them.
|
||||||
|
pub fn transactions_count(&self) -> usize {
|
||||||
|
self.rlp.at(1).iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return List of transactions in given block.
|
||||||
|
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
||||||
|
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return transaction hashes.
|
||||||
|
pub fn transaction_hashes(&self) -> Vec<H256> {
|
||||||
|
self.rlp.at(1).iter().map(|rlp| rlp.as_raw().sha3()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns transaction at given index without deserializing unnecessary data.
|
||||||
|
pub fn transaction_at(&self, index: usize) -> Option<SignedTransaction> {
|
||||||
|
self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns localized transaction at given index.
|
||||||
|
pub fn localized_transaction_at(&self, index: usize) -> Option<LocalizedTransaction> {
|
||||||
|
let header = self.header_view();
|
||||||
|
let block_hash = header.sha3();
|
||||||
|
let block_number = header.number();
|
||||||
|
self.transaction_at(index).map(|t| LocalizedTransaction {
|
||||||
|
signed: t,
|
||||||
|
block_hash: block_hash,
|
||||||
|
block_number: block_number,
|
||||||
|
transaction_index: index
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return list of uncles of given block.
|
||||||
|
pub fn uncles(&self) -> Vec<Header> {
|
||||||
|
self.rlp.val_at(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return number of uncles in given block, without deserializing them.
|
||||||
|
pub fn uncles_count(&self) -> usize {
|
||||||
|
self.rlp.at(2).iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return List of transactions in given block.
|
||||||
|
pub fn uncle_views(&self) -> Vec<HeaderView> {
|
||||||
|
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return list of uncle hashes of given block.
|
||||||
|
pub fn uncle_hashes(&self) -> Vec<H256> {
|
||||||
|
self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return nth uncle.
|
||||||
|
pub fn uncle_at(&self, index: usize) -> Option<Header> {
|
||||||
|
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Hashable for BlockView<'a> {
|
||||||
|
fn sha3(&self) -> H256 {
|
||||||
|
self.header_view().sha3()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use rustc_serialize::hex::FromHex;
|
||||||
|
use util::H256;
|
||||||
|
use super::BlockView;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_block_view() {
|
||||||
|
// that's rlp of block created with ethash engine.
|
||||||
|
let rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap();
|
||||||
|
|
||||||
|
let view = BlockView::new(&rlp);
|
||||||
|
assert_eq!(view.hash(), H256::from_str("2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259").unwrap());
|
||||||
|
assert_eq!(view.transactions_count(), 1);
|
||||||
|
assert_eq!(view.uncles_count(), 0);
|
||||||
|
}
|
||||||
|
}
|
134
ethcore/src/views/header.rs
Normal file
134
ethcore/src/views/header.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! View onto block header rlp
|
||||||
|
|
||||||
|
use util::{Rlp, U256, Bytes, Hashable, H256, Address, H2048, View};
|
||||||
|
use header::BlockNumber;
|
||||||
|
|
||||||
|
/// View onto block header rlp.
|
||||||
|
pub struct HeaderView<'a> {
|
||||||
|
rlp: Rlp<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HeaderView<'a> {
|
||||||
|
/// Creates new view onto header from raw bytes.
|
||||||
|
pub fn new(bytes: &'a [u8]) -> HeaderView<'a> {
|
||||||
|
HeaderView {
|
||||||
|
rlp: Rlp::new(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates new view onto header from rlp.
|
||||||
|
pub fn new_from_rlp(rlp: Rlp<'a>) -> HeaderView<'a> {
|
||||||
|
HeaderView {
|
||||||
|
rlp: rlp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns header hash.
|
||||||
|
pub fn hash(&self) -> H256 { self.sha3() }
|
||||||
|
|
||||||
|
/// Returns raw rlp.
|
||||||
|
pub fn rlp(&self) -> &Rlp<'a> { &self.rlp }
|
||||||
|
|
||||||
|
/// Returns parent hash.
|
||||||
|
pub fn parent_hash(&self) -> H256 { self.rlp.val_at(0) }
|
||||||
|
|
||||||
|
/// Returns uncles hash.
|
||||||
|
pub fn uncles_hash(&self) -> H256 { self.rlp.val_at(1) }
|
||||||
|
|
||||||
|
/// Returns author.
|
||||||
|
pub fn author(&self) -> Address { self.rlp.val_at(2) }
|
||||||
|
|
||||||
|
/// Returns state root.
|
||||||
|
pub fn state_root(&self) -> H256 { self.rlp.val_at(3) }
|
||||||
|
|
||||||
|
/// Returns transactions root.
|
||||||
|
pub fn transactions_root(&self) -> H256 { self.rlp.val_at(4) }
|
||||||
|
|
||||||
|
/// Returns block receipts root.
|
||||||
|
pub fn receipts_root(&self) -> H256 { self.rlp.val_at(5) }
|
||||||
|
|
||||||
|
/// Returns block log bloom.
|
||||||
|
pub fn log_bloom(&self) -> H2048 { self.rlp.val_at(6) }
|
||||||
|
|
||||||
|
/// Returns block difficulty.
|
||||||
|
pub fn difficulty(&self) -> U256 { self.rlp.val_at(7) }
|
||||||
|
|
||||||
|
/// Returns block number.
|
||||||
|
pub fn number(&self) -> BlockNumber { self.rlp.val_at(8) }
|
||||||
|
|
||||||
|
/// Returns block gas limit.
|
||||||
|
pub fn gas_limit(&self) -> U256 { self.rlp.val_at(9) }
|
||||||
|
|
||||||
|
/// Returns block gas used.
|
||||||
|
pub fn gas_used(&self) -> U256 { self.rlp.val_at(10) }
|
||||||
|
|
||||||
|
/// Returns timestamp.
|
||||||
|
pub fn timestamp(&self) -> u64 { self.rlp.val_at(11) }
|
||||||
|
|
||||||
|
/// Returns block extra data.
|
||||||
|
pub fn extra_data(&self) -> Bytes { self.rlp.val_at(12) }
|
||||||
|
|
||||||
|
/// Returns a vector of post-RLP-encoded seal fields.
|
||||||
|
pub fn seal(&self) -> Vec<Bytes> {
|
||||||
|
let mut seal = vec![];
|
||||||
|
for i in 13..self.rlp.item_count() {
|
||||||
|
seal.push(self.rlp.at(i).as_raw().to_vec());
|
||||||
|
}
|
||||||
|
seal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Hashable for HeaderView<'a> {
|
||||||
|
fn sha3(&self) -> H256 {
|
||||||
|
self.rlp.as_raw().sha3()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use rustc_serialize::hex::FromHex;
|
||||||
|
use util::{H256, Address, H2048, U256};
|
||||||
|
use super::HeaderView;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_header_view() {
|
||||||
|
// that's rlp of block header created with ethash engine.
|
||||||
|
let rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||||
|
let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap();
|
||||||
|
let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||||
|
|
||||||
|
let view = HeaderView::new(&rlp);
|
||||||
|
assert_eq!(view.hash(), H256::from_str("2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259").unwrap());
|
||||||
|
assert_eq!(view.parent_hash(), H256::from_str("d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7").unwrap());
|
||||||
|
assert_eq!(view.uncles_hash(), H256::from_str("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").unwrap());
|
||||||
|
assert_eq!(view.author(), Address::from_str("8888f1f195afa192cfee860698584c030f4c9db1").unwrap());
|
||||||
|
assert_eq!(view.state_root(), H256::from_str("5fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25").unwrap());
|
||||||
|
assert_eq!(view.transactions_root(), H256::from_str("88d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158").unwrap());
|
||||||
|
assert_eq!(view.receipts_root(), H256::from_str("07c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1").unwrap());
|
||||||
|
assert_eq!(view.log_bloom(), H2048::default());
|
||||||
|
assert_eq!(view.difficulty(), U256::from(0x02_00_80));
|
||||||
|
assert_eq!(view.number(), 3);
|
||||||
|
assert_eq!(view.gas_limit(), U256::from(0x2f_ef_ba));
|
||||||
|
assert_eq!(view.gas_used(), U256::from(0x52_4d));
|
||||||
|
assert_eq!(view.timestamp(), 0x56_8e_93_2a);
|
||||||
|
assert_eq!(view.extra_data(), vec![] as Vec<u8>);
|
||||||
|
assert_eq!(view.seal(), vec![mix_hash, nonce]);
|
||||||
|
}
|
||||||
|
}
|
@ -14,13 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Key management module
|
//! Block oriented views onto rlp.
|
||||||
|
|
||||||
pub mod directory;
|
mod block;
|
||||||
pub mod store;
|
mod header;
|
||||||
mod geth_import;
|
mod transaction;
|
||||||
mod test_account_provider;
|
|
||||||
|
|
||||||
pub use self::store::AccountProvider;
|
pub use self::block::BlockView;
|
||||||
pub use self::test_account_provider::{TestAccount, TestAccountProvider};
|
pub use self::header::HeaderView;
|
||||||
pub use self::geth_import::import_keys_paths;
|
pub use self::transaction::TransactionView;
|
97
ethcore/src/views/transaction.rs
Normal file
97
ethcore/src/views/transaction.rs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! View onto transaction rlp
|
||||||
|
use util::{Rlp, U256, Bytes, Hashable, H256, View};
|
||||||
|
|
||||||
|
/// View onto transaction rlp.
|
||||||
|
pub struct TransactionView<'a> {
|
||||||
|
rlp: Rlp<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TransactionView<'a> {
|
||||||
|
/// Creates new view onto block from raw bytes.
|
||||||
|
pub fn new(bytes: &'a [u8]) -> TransactionView<'a> {
|
||||||
|
TransactionView {
|
||||||
|
rlp: Rlp::new(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates new view onto block from rlp.
|
||||||
|
pub fn new_from_rlp(rlp: Rlp<'a>) -> TransactionView<'a> {
|
||||||
|
TransactionView {
|
||||||
|
rlp: rlp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return reference to underlaying rlp.
|
||||||
|
pub fn rlp(&self) -> &Rlp<'a> {
|
||||||
|
&self.rlp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the nonce field of the transaction.
|
||||||
|
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
|
||||||
|
|
||||||
|
/// Get the gas_price field of the transaction.
|
||||||
|
pub fn gas_price(&self) -> U256 { self.rlp.val_at(1) }
|
||||||
|
|
||||||
|
/// Get the gas field of the transaction.
|
||||||
|
pub fn gas(&self) -> U256 { self.rlp.val_at(2) }
|
||||||
|
|
||||||
|
/// Get the value field of the transaction.
|
||||||
|
pub fn value(&self) -> U256 { self.rlp.val_at(4) }
|
||||||
|
|
||||||
|
/// Get the data field of the transaction.
|
||||||
|
pub fn data(&self) -> Bytes { self.rlp.val_at(5) }
|
||||||
|
|
||||||
|
/// Get the v field of the transaction.
|
||||||
|
pub fn v(&self) -> u8 { let r: u16 = self.rlp.val_at(6); r as u8 }
|
||||||
|
|
||||||
|
/// Get the r field of the transaction.
|
||||||
|
pub fn r(&self) -> U256 { self.rlp.val_at(7) }
|
||||||
|
|
||||||
|
/// Get the s field of the transaction.
|
||||||
|
pub fn s(&self) -> U256 { self.rlp.val_at(8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Hashable for TransactionView<'a> {
|
||||||
|
fn sha3(&self) -> H256 {
|
||||||
|
self.rlp.as_raw().sha3()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use rustc_serialize::hex::FromHex;
|
||||||
|
use util::U256;
|
||||||
|
use super::TransactionView;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transaction_view() {
|
||||||
|
let rlp = "f87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804".from_hex().unwrap();
|
||||||
|
|
||||||
|
let view = TransactionView::new(&rlp);
|
||||||
|
assert_eq!(view.nonce(), U256::from(0));
|
||||||
|
assert_eq!(view.gas_price(), U256::from(1));
|
||||||
|
assert_eq!(view.gas(), U256::from(0x61a8));
|
||||||
|
assert_eq!(view.value(), U256::from(0xa));
|
||||||
|
assert_eq!(view.data(), "0000000000000000000000000000000000000000000000000000000000".from_hex().unwrap());
|
||||||
|
assert_eq!(view.r(), U256::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353").unwrap());
|
||||||
|
assert_eq!(view.s(), U256::from_str("efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
|
||||||
|
assert_eq!(view.v(), 0x1b);
|
||||||
|
}
|
||||||
|
}
|
2
ethkey/.gitignore
vendored
Normal file
2
ethkey/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
target
|
||||||
|
*.swp
|
23
ethkey/.travis.yml
Normal file
23
ethkey/.travis.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
sudo: false
|
||||||
|
language: rust
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
matrix:
|
||||||
|
fast_finish: false
|
||||||
|
include:
|
||||||
|
- rust: stable
|
||||||
|
- rust: beta
|
||||||
|
- rust: nightly
|
||||||
|
after_success: |
|
||||||
|
[ $TRAVIS_BRANCH = master ] &&
|
||||||
|
[ $TRAVIS_PULL_REQUEST = false ] &&
|
||||||
|
[ $TRAVIS_RUST_VERSION = stable ] &&
|
||||||
|
cargo doc --no-deps --verbose &&
|
||||||
|
echo '<meta http-equiv=refresh content=0;url=ethkey/index.html>' > target/doc/index.html &&
|
||||||
|
pip install --user ghp-import &&
|
||||||
|
/home/travis/.local/bin/ghp-import -n target/doc &&
|
||||||
|
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- secure: LBkFAH5fAhzHRP7kYQZnOCavOuPS2vEDv49KGfTsY/7MmW0De4c0sz0a3/0IdFqqIMLYLV2uMO86S0p6FBaq6/GIdobLsGZZ3cFReYFI+vb8sylYF/+D/aQ/UOjpEOD8HP6G3YmV5buSyL8uiPlmYbqwBAe4z6ELEbh/16gRuIqQLYQtpYPxMCD3tZzSux81b45K2khETZ7E+ap3LUG3rFTXxjEgx9leIZlVY+Qk4U5D9gFnJnjmxDPyIqzn2dORnw5jcpp3eSUEvSvSgjz4TAVg7Gw789jDl2dyr26U1wp1E5bB9AqZVYOb4l8vcQ6QiHrCvu7Wgl32O6XYkwMjDaDUB68bm5MTsUrwDWgKGx4xeurIBil5doHFlCGZ98RrzPxdgoCd6hCI459dA8jEwdXAfOkZ80RycZlryHCwn68x3dlnJoqVyg8viYo6H6G0GdH/dIhuwbnLDdWZsODehN8eJEy9KKQ4tPp+PjBcgKm1Wz5MzKFSIwfFInic7hjTVXGozHSvgvXJE0BI2bPbjVNCdZa5kGAAUAhBNXyTn7PbC7hYbmwAalzaOIjoYcdQLmUEz2J2gSOK8xW2gMU0Z2I+IylA0oh8xB/r2Q5sqLHT3LPLdzoETsyzaQjWFcFdXdsbbcG59DnFC9s2Jq7KqeODp6EJG4cw0ofKpBuDRes=
|
21
ethkey/Cargo.toml
Normal file
21
ethkey/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "ethkey"
|
||||||
|
version = "0.2.0"
|
||||||
|
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.3.14"
|
||||||
|
lazy_static = "0.2.1"
|
||||||
|
tiny-keccak = "1.0"
|
||||||
|
eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" }
|
||||||
|
rustc-serialize = "0.3"
|
||||||
|
docopt = { version = "0.6", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
cli = ["docopt"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "ethkey"
|
||||||
|
path = "src/bin/main.rs"
|
||||||
|
doc = false
|
168
ethkey/README.md
Normal file
168
ethkey/README.md
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
# ethkey
|
||||||
|
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
|
||||||
|
[travis-image]: https://travis-ci.org/ethcore/ethkey.svg?branch=master
|
||||||
|
[travis-url]: https://travis-ci.org/ethcore/ethkey
|
||||||
|
|
||||||
|
Ethereum keys generator.
|
||||||
|
|
||||||
|
[Documentation](http://ethcore.github.io/ethkey/ethkey/index.html)
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Ethereum keys generator.
|
||||||
|
Copyright 2016 Ethcore (UK) Limited
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
ethkey info <secret> [options]
|
||||||
|
ethkey generate random [options]
|
||||||
|
ethkey generate prefix <prefix> <iterations> [options]
|
||||||
|
ethkey generate brain <seed> [options]
|
||||||
|
ethkey sign <secret> <message>
|
||||||
|
ethkey verify public <public> <signature> <message>
|
||||||
|
ethkey verify address <address> <signature> <message>
|
||||||
|
ethkey [-h | --help]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Display this message and exit.
|
||||||
|
-s, --secret Display only the secret.
|
||||||
|
-p, --public Display only the public.
|
||||||
|
-a, --address Display only the address.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
info Display public and address of the secret.
|
||||||
|
generate Generates new ethereum key.
|
||||||
|
random Random generation.
|
||||||
|
prefix Random generation, but address must start with a prefix
|
||||||
|
brain Generate new key from string seed.
|
||||||
|
sign Sign message using secret.
|
||||||
|
verify Verify signer of the signature.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### `info <secret>`
|
||||||
|
*Display info about private key.*
|
||||||
|
|
||||||
|
- `<secret>` - ethereum secret, 32 bytes long
|
||||||
|
|
||||||
|
```
|
||||||
|
ethkey info 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
|
||||||
|
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
|
||||||
|
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `generate brain <seed>`
|
||||||
|
*Generate new brain-wallet keypair using 16384 iterations.*
|
||||||
|
|
||||||
|
- `<seed>` - brain-wallet seed, any string
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
ethkey generate brain "this is sparta"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
|
||||||
|
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
|
||||||
|
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `generate random`
|
||||||
|
*Generate new keypair randomly.*
|
||||||
|
|
||||||
|
```
|
||||||
|
ethkey generate random
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
secret: 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5
|
||||||
|
public: 35f222d88b80151857a2877826d940104887376a94c1cbd2c8c7c192eb701df88a18a4ecb8b05b1466c5b3706042027b5e079fe3a3683e66d822b0e047aa3418
|
||||||
|
address: a8fa5dd30a87bb9e3288d604eb74949c515ab66e
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `generate prefix <prefix> <iterations>`
|
||||||
|
*Generate new keypair randomly with address starting with prefix.*
|
||||||
|
|
||||||
|
- `<prefix>` - desired address prefix, 0 - 32 bytes long.
|
||||||
|
- `<iterations>` - maximum number of tries before generation is assumed to be a failure.
|
||||||
|
|
||||||
|
```
|
||||||
|
ethkey generate prefix ff 1000
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
secret: 2075b1d9c124ea673de7273758ed6de14802a9da8a73ceb74533d7c312ff6acd
|
||||||
|
public: 48dbce4508566a05509980a5dd1335599fcdac6f9858ba67018cecb9f09b8c4066dc4c18ae2722112fd4d9ac36d626793fffffb26071dfeb0c2300df994bd173
|
||||||
|
address: fff7e25dff2aa60f61f9d98130c8646a01f31649
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `sign <secret> <message>`
|
||||||
|
*Sign a message with a secret.*
|
||||||
|
|
||||||
|
- `<secret>` - ethereum secret, 32 bytes long
|
||||||
|
- `<message>` - message to sign, 32 bytes long
|
||||||
|
|
||||||
|
```
|
||||||
|
ethkey sign 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55 bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `verify public <public> <signature> <message>`
|
||||||
|
*Verify the signature.*
|
||||||
|
|
||||||
|
- `<public>` - ethereum public, 64 bytes long
|
||||||
|
- `<signature>` - message signature, 65 bytes long
|
||||||
|
- `<message>` - message, 32 bytes long
|
||||||
|
|
||||||
|
```
|
||||||
|
ethkey verify public 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124 c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200 bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `verify address <address> <signature> <message>`
|
||||||
|
*Verify the signature.*
|
||||||
|
|
||||||
|
- `<address>` - ethereum address, 20 bytes long
|
||||||
|
- `<signature>` - message signature, 65 bytes long
|
||||||
|
- `<message>` - message, 32 bytes long
|
||||||
|
|
||||||
|
```
|
||||||
|
ethkey verify address 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124 c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200 bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Ethcore toolchain
|
||||||
|
*this project is a part of the ethcore toolchain*
|
||||||
|
|
||||||
|
- [**ethkey**](https://github.com/ethcore/ethkey) - Ethereum keys generator and signer.
|
||||||
|
- [**ethstore**](https://github.com/ethcore/ethstore) - Ethereum key management.
|
||||||
|
- [**ethabi**](https://github.com/ethcore/ethabi) - Ethereum function calls encoding.
|
312
ethkey/src/bin/ethkey.rs
Normal file
312
ethkey/src/bin/ethkey.rs
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
// 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 docopt;
|
||||||
|
extern crate rustc_serialize;
|
||||||
|
extern crate ethkey;
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::{env, fmt, process};
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use docopt::Docopt;
|
||||||
|
use rustc_serialize::hex::{FromHex, FromHexError};
|
||||||
|
use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, Secret, Message, Public, Signature, Address, sign, verify_public, verify_address};
|
||||||
|
|
||||||
|
pub const USAGE: &'static str = r#"
|
||||||
|
Ethereum keys generator.
|
||||||
|
Copyright 2016 Ethcore (UK) Limited
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
ethkey info <secret> [options]
|
||||||
|
ethkey generate random [options]
|
||||||
|
ethkey generate prefix <prefix> <iterations> [options]
|
||||||
|
ethkey generate brain <seed> [options]
|
||||||
|
ethkey sign <secret> <message>
|
||||||
|
ethkey verify public <public> <signature> <message>
|
||||||
|
ethkey verify address <address> <signature> <message>
|
||||||
|
ethkey [-h | --help]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Display this message and exit.
|
||||||
|
-s, --secret Display only the secret.
|
||||||
|
-p, --public Display only the public.
|
||||||
|
-a, --address Display only the address.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
info Display public and address of the secret.
|
||||||
|
generate Generates new ethereum key.
|
||||||
|
random Random generation.
|
||||||
|
prefix Random generation, but address must start with a prefix
|
||||||
|
brain Generate new key from string seed.
|
||||||
|
sign Sign message using secret.
|
||||||
|
verify Verify signer of the signature.
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[derive(Debug, RustcDecodable)]
|
||||||
|
struct Args {
|
||||||
|
cmd_info: bool,
|
||||||
|
cmd_generate: bool,
|
||||||
|
cmd_random: bool,
|
||||||
|
cmd_prefix: bool,
|
||||||
|
cmd_brain: bool,
|
||||||
|
cmd_sign: bool,
|
||||||
|
cmd_verify: bool,
|
||||||
|
cmd_public: bool,
|
||||||
|
cmd_address: bool,
|
||||||
|
arg_prefix: String,
|
||||||
|
arg_iterations: String,
|
||||||
|
arg_seed: String,
|
||||||
|
arg_secret: String,
|
||||||
|
arg_message: String,
|
||||||
|
arg_public: String,
|
||||||
|
arg_address: String,
|
||||||
|
arg_signature: String,
|
||||||
|
flag_secret: bool,
|
||||||
|
flag_public: bool,
|
||||||
|
flag_address: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Error {
|
||||||
|
Ethkey(EthkeyError),
|
||||||
|
FromHex(FromHexError),
|
||||||
|
ParseInt(ParseIntError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EthkeyError> for Error {
|
||||||
|
fn from(err: EthkeyError) -> Self {
|
||||||
|
Error::Ethkey(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FromHexError> for Error {
|
||||||
|
fn from(err: FromHexError) -> Self {
|
||||||
|
Error::FromHex(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseIntError> for Error {
|
||||||
|
fn from(err: ParseIntError) -> Self {
|
||||||
|
Error::ParseInt(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
match *self {
|
||||||
|
Error::Ethkey(ref e) => write!(f, "{}", e),
|
||||||
|
Error::FromHex(ref e) => write!(f, "{}", e),
|
||||||
|
Error::ParseInt(ref e) => write!(f, "{}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DisplayMode {
|
||||||
|
KeyPair,
|
||||||
|
Secret,
|
||||||
|
Public,
|
||||||
|
Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayMode {
|
||||||
|
fn new(args: &Args) -> Self {
|
||||||
|
if args.flag_secret {
|
||||||
|
DisplayMode::Secret
|
||||||
|
} else if args.flag_public {
|
||||||
|
DisplayMode::Public
|
||||||
|
} else if args.flag_address {
|
||||||
|
DisplayMode::Address
|
||||||
|
} else {
|
||||||
|
DisplayMode::KeyPair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match execute(env::args()) {
|
||||||
|
Ok(ok) => println!("{}", ok),
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err);
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(keypair: KeyPair, mode: DisplayMode) -> String {
|
||||||
|
match mode {
|
||||||
|
DisplayMode::KeyPair => format!("{}", keypair),
|
||||||
|
DisplayMode::Secret => format!("{}", keypair.secret()),
|
||||||
|
DisplayMode::Public => format!("{}", keypair.public()),
|
||||||
|
DisplayMode::Address => format!("{}", keypair.address()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item=S>, S: AsRef<str> {
|
||||||
|
let args: Args = Docopt::new(USAGE)
|
||||||
|
.and_then(|d| d.argv(command).decode())
|
||||||
|
.unwrap_or_else(|e| e.exit());
|
||||||
|
|
||||||
|
return if args.cmd_info {
|
||||||
|
let display_mode = DisplayMode::new(&args);
|
||||||
|
let secret = try!(Secret::from_str(&args.arg_secret));
|
||||||
|
let keypair = try!(KeyPair::from_secret(secret));
|
||||||
|
Ok(display(keypair, display_mode))
|
||||||
|
} else if args.cmd_generate {
|
||||||
|
let display_mode = DisplayMode::new(&args);
|
||||||
|
let keypair = if args.cmd_random {
|
||||||
|
Random.generate()
|
||||||
|
} else if args.cmd_prefix {
|
||||||
|
let prefix = try!(args.arg_prefix.from_hex());
|
||||||
|
let iterations = try!(usize::from_str_radix(&args.arg_iterations, 10));
|
||||||
|
Prefix::new(prefix, iterations).generate()
|
||||||
|
} else if args.cmd_brain {
|
||||||
|
Brain::new(args.arg_seed).generate()
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
Ok(display(try!(keypair), display_mode))
|
||||||
|
} else if args.cmd_sign {
|
||||||
|
let secret = try!(Secret::from_str(&args.arg_secret));
|
||||||
|
let message = try!(Message::from_str(&args.arg_message));
|
||||||
|
let signature = try!(sign(&secret, &message));
|
||||||
|
Ok(format!("{}", signature))
|
||||||
|
} else if args.cmd_verify {
|
||||||
|
let signature = try!(Signature::from_str(&args.arg_signature));
|
||||||
|
let message = try!(Message::from_str(&args.arg_message));
|
||||||
|
let ok = if args.cmd_public {
|
||||||
|
let public = try!(Public::from_str(&args.arg_public));
|
||||||
|
try!(verify_public(&public, &signature, &message))
|
||||||
|
} else if args.cmd_address {
|
||||||
|
let address = try!(Address::from_str(&args.arg_address));
|
||||||
|
try!(verify_address(&address, &signature, &message))
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
Ok(format!("{}", ok))
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::execute;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn info() {
|
||||||
|
let command = vec!["ethkey", "info", "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
"secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
|
||||||
|
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
|
||||||
|
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn brain() {
|
||||||
|
let command = vec!["ethkey", "generate", "brain", "this is sparta"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
"secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
|
||||||
|
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
|
||||||
|
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn secret() {
|
||||||
|
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--secret"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected = "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn public() {
|
||||||
|
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--public"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected = "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn address() {
|
||||||
|
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--address"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected = "26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sign() {
|
||||||
|
let command = vec!["ethkey", "sign", "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected = "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_valid_public() {
|
||||||
|
let command = vec!["ethkey", "verify", "public", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected = "true".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_valid_address() {
|
||||||
|
let command = vec!["ethkey", "verify", "address", "26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected = "true".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_invalid() {
|
||||||
|
let command = vec!["ethkey", "verify", "public", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec986"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let expected = "false".to_owned();
|
||||||
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
|
}
|
||||||
|
}
|
21
ethkey/src/bin/main.rs
Normal file
21
ethkey/src/bin/main.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#[cfg(feature = "cli")]
|
||||||
|
include!("ethkey.rs");
|
||||||
|
|
||||||
|
#[cfg(not(feature = "cli"))]
|
||||||
|
fn main() {}
|
62
ethkey/src/brain.rs
Normal file
62
ethkey/src/brain.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// 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 keccak::Keccak256;
|
||||||
|
use super::{KeyPair, Error, Generator, Secret};
|
||||||
|
|
||||||
|
/// Simple brainwallet.
|
||||||
|
pub struct Brain(String);
|
||||||
|
|
||||||
|
impl Brain {
|
||||||
|
pub fn new(s: String) -> Self {
|
||||||
|
Brain(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Generator for Brain {
|
||||||
|
fn generate(self) -> Result<KeyPair, Error> {
|
||||||
|
let seed = self.0;
|
||||||
|
let mut secret = seed.bytes().collect::<Vec<u8>>().keccak256();
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
secret = secret.keccak256();
|
||||||
|
|
||||||
|
match i > 16384 {
|
||||||
|
false => i += 1,
|
||||||
|
true => {
|
||||||
|
let result = KeyPair::from_secret(Secret::from(secret.clone()));
|
||||||
|
if result.is_ok() {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use {Brain, Generator};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_brain() {
|
||||||
|
let words = "this is sparta!".to_owned();
|
||||||
|
let first_keypair = Brain(words.clone()).generate().unwrap();
|
||||||
|
let second_keypair = Brain(words.clone()).generate().unwrap();
|
||||||
|
assert_eq!(first_keypair.secret(), second_keypair.secret());
|
||||||
|
}
|
||||||
|
}
|
69
ethkey/src/error.rs
Normal file
69
ethkey/src/error.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// 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::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Crypto error
|
||||||
|
pub enum Error {
|
||||||
|
/// Invalid secret key
|
||||||
|
InvalidSecret,
|
||||||
|
/// Invalid public key
|
||||||
|
InvalidPublic,
|
||||||
|
/// Invalid address
|
||||||
|
InvalidAddress,
|
||||||
|
/// Invalid EC signature
|
||||||
|
InvalidSignature,
|
||||||
|
/// Invalid AES message
|
||||||
|
InvalidMessage,
|
||||||
|
/// IO Error
|
||||||
|
Io(::std::io::Error),
|
||||||
|
/// Custom
|
||||||
|
Custom(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = match *self {
|
||||||
|
Error::InvalidSecret => "Invalid secret key".into(),
|
||||||
|
Error::InvalidPublic => "Invalid public key".into(),
|
||||||
|
Error::InvalidAddress => "Invalid address".into(),
|
||||||
|
Error::InvalidSignature => "Invalid EC signature".into(),
|
||||||
|
Error::InvalidMessage => "Invalid AES message".into(),
|
||||||
|
Error::Io(ref err) => format!("I/O error: {}", err),
|
||||||
|
Error::Custom(ref s) => s.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
f.write_fmt(format_args!("Crypto error ({})", msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<::secp256k1::Error> for Error {
|
||||||
|
fn from(e: ::secp256k1::Error) -> Error {
|
||||||
|
match e {
|
||||||
|
::secp256k1::Error::InvalidMessage => Error::InvalidMessage,
|
||||||
|
::secp256k1::Error::InvalidPublicKey => Error::InvalidPublic,
|
||||||
|
::secp256k1::Error::InvalidSecretKey => Error::InvalidSecret,
|
||||||
|
_ => Error::InvalidSignature,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<::std::io::Error> for Error {
|
||||||
|
fn from(err: ::std::io::Error) -> Error {
|
||||||
|
Error::Io(err)
|
||||||
|
}
|
||||||
|
}
|
31
ethkey/src/keccak.rs
Normal file
31
ethkey/src/keccak.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// 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 tiny_keccak::Keccak;
|
||||||
|
|
||||||
|
pub trait Keccak256<T> {
|
||||||
|
fn keccak256(&self) -> T where T: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keccak256<[u8; 32]> for [u8] {
|
||||||
|
fn keccak256(&self) -> [u8; 32] {
|
||||||
|
let mut keccak = Keccak::new_keccak256();
|
||||||
|
let mut result = [0u8; 32];
|
||||||
|
keccak.update(self);
|
||||||
|
keccak.finalize(&mut result);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
111
ethkey/src/keypair.rs
Normal file
111
ethkey/src/keypair.rs
Normal 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/>.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use secp256k1::key;
|
||||||
|
use rustc_serialize::hex::ToHex;
|
||||||
|
use keccak::Keccak256;
|
||||||
|
use super::{Secret, Public, Address, SECP256K1, Error};
|
||||||
|
|
||||||
|
pub fn public_to_address(public: &Public) -> Address {
|
||||||
|
let hash = public.keccak256();
|
||||||
|
let mut result = Address::default();
|
||||||
|
result.copy_from_slice(&hash[12..]);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// secp256k1 key pair
|
||||||
|
pub struct KeyPair {
|
||||||
|
secret: Secret,
|
||||||
|
public: Public,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for KeyPair {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
try!(writeln!(f, "secret: {}", self.secret.to_hex()));
|
||||||
|
try!(writeln!(f, "public: {}", self.public.to_hex()));
|
||||||
|
write!(f, "address: {}", self.address().to_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyPair {
|
||||||
|
/// Create a pair from secret key
|
||||||
|
pub fn from_secret(secret: Secret) -> Result<KeyPair, Error> {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
let s: key::SecretKey = try!(key::SecretKey::from_slice(context, &secret[..]));
|
||||||
|
let pub_key = try!(key::PublicKey::from_secret_key(context, &s));
|
||||||
|
let serialized = pub_key.serialize_vec(context, false);
|
||||||
|
|
||||||
|
let mut public = Public::default();
|
||||||
|
public.copy_from_slice(&serialized[1..65]);
|
||||||
|
|
||||||
|
let keypair = KeyPair {
|
||||||
|
secret: secret,
|
||||||
|
public: public,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(keypair)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
let serialized = publ.serialize_vec(context, false);
|
||||||
|
let mut secret = Secret::default();
|
||||||
|
secret.copy_from_slice(&sec[0..32]);
|
||||||
|
let mut public = Public::default();
|
||||||
|
public.copy_from_slice(&serialized[1..65]);
|
||||||
|
|
||||||
|
KeyPair {
|
||||||
|
secret: secret,
|
||||||
|
public: public,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn secret(&self) -> &Secret {
|
||||||
|
&self.secret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn public(&self) -> &Public {
|
||||||
|
&self.public
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn address(&self) -> Address {
|
||||||
|
public_to_address(&self.public)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use {KeyPair, Secret};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_secret() {
|
||||||
|
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
|
||||||
|
let _ = KeyPair::from_secret(secret).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keypair_display() {
|
||||||
|
let expected =
|
||||||
|
"secret: a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65
|
||||||
|
public: 8ce0db0b0359ffc5866ba61903cc2518c3675ef2cf380a7e54bde7ea20e6fa1ab45b7617346cd11b7610001ee6ae5b0155c41cad9527cbcdff44ec67848943a4
|
||||||
|
address: 5b073e9233944b5e729e46d618f0d8edf3d9c34a".to_owned();
|
||||||
|
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
|
||||||
|
let kp = KeyPair::from_secret(secret).unwrap();
|
||||||
|
assert_eq!(format!("{}", kp), expected);
|
||||||
|
}
|
||||||
|
}
|
49
ethkey/src/lib.rs
Normal file
49
ethkey/src/lib.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// 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 rand;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
extern crate tiny_keccak;
|
||||||
|
extern crate secp256k1;
|
||||||
|
extern crate rustc_serialize;
|
||||||
|
|
||||||
|
mod brain;
|
||||||
|
mod error;
|
||||||
|
mod keypair;
|
||||||
|
mod keccak;
|
||||||
|
mod prefix;
|
||||||
|
mod primitive;
|
||||||
|
mod random;
|
||||||
|
mod signature;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates new keypair.
|
||||||
|
pub trait Generator {
|
||||||
|
/// Should be called to generate new keypair.
|
||||||
|
fn generate(self) -> Result<KeyPair, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::brain::Brain;
|
||||||
|
pub use self::error::Error;
|
||||||
|
pub use self::keypair::{KeyPair, public_to_address};
|
||||||
|
pub use self::primitive::{Secret, Public, Address, Message};
|
||||||
|
pub use self::prefix::Prefix;
|
||||||
|
pub use self::random::Random;
|
||||||
|
pub use self::signature::{sign, verify_public, verify_address, recover, Signature};
|
57
ethkey/src/prefix.rs
Normal file
57
ethkey/src/prefix.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// 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 super::{Random, Generator, KeyPair, Error};
|
||||||
|
|
||||||
|
/// Tries to find keypair with address starting with given prefix.
|
||||||
|
pub struct Prefix {
|
||||||
|
prefix: Vec<u8>,
|
||||||
|
iterations: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Prefix {
|
||||||
|
pub fn new(prefix: Vec<u8>, iterations: usize) -> Self {
|
||||||
|
Prefix {
|
||||||
|
prefix: prefix,
|
||||||
|
iterations: iterations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Generator for Prefix {
|
||||||
|
fn generate(self) -> Result<KeyPair, Error> {
|
||||||
|
for _ in 0..self.iterations {
|
||||||
|
let keypair = try!(Random.generate());
|
||||||
|
if keypair.address().starts_with(&self.prefix) {
|
||||||
|
return Ok(keypair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::Custom("Could not find keypair".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use {Generator, Prefix};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prefix_generator() {
|
||||||
|
let prefix = vec![0xffu8];
|
||||||
|
let keypair = Prefix::new(prefix.clone(), usize::max_value()).generate().unwrap();
|
||||||
|
assert!(keypair.address().starts_with(&prefix));
|
||||||
|
}
|
||||||
|
}
|
138
ethkey/src/primitive.rs
Normal file
138
ethkey/src/primitive.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// 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::ops::{Deref, DerefMut};
|
||||||
|
use std::{fmt, cmp, hash};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use rustc_serialize::hex::{ToHex, FromHex};
|
||||||
|
use Error;
|
||||||
|
|
||||||
|
macro_rules! impl_primitive {
|
||||||
|
($name: ident, $size: expr, $err: expr) => {
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Eq)]
|
||||||
|
pub struct $name([u8; $size]);
|
||||||
|
|
||||||
|
impl fmt::Debug for $name {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "{}", self.to_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for $name {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "{}", self.to_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for $name {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.from_hex() {
|
||||||
|
Ok(ref hex) if hex.len() == $size => {
|
||||||
|
let mut res = $name::default();
|
||||||
|
res.copy_from_slice(hex);
|
||||||
|
Ok(res)
|
||||||
|
},
|
||||||
|
_ => Err($err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for $name {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let self_ref: &[u8] = &self.0;
|
||||||
|
let other_ref: &[u8] = &other.0;
|
||||||
|
self_ref == other_ref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for $name {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||||
|
let self_ref: &[u8] = &self.0;
|
||||||
|
let other_ref: &[u8] = &other.0;
|
||||||
|
self_ref.partial_cmp(other_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for $name {
|
||||||
|
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||||
|
let self_ref: &[u8] = &self.0;
|
||||||
|
let other_ref: &[u8] = &other.0;
|
||||||
|
self_ref.cmp(other_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for $name {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let mut res = Self::default();
|
||||||
|
res.copy_from_slice(&self.0);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for $name {
|
||||||
|
fn default() -> Self {
|
||||||
|
$name([0u8; $size])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; $size]> for $name {
|
||||||
|
fn from(s: [u8; $size]) -> Self {
|
||||||
|
$name(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<[u8; $size]> for $name {
|
||||||
|
fn into(self) -> [u8; $size] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl hash::Hash for $name {
|
||||||
|
fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
|
||||||
|
let self_ref: &[u8] = &self.0;
|
||||||
|
self_ref.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for $name {
|
||||||
|
type Target = [u8; $size];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for $name {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_primitive!(Address, 20, Error::InvalidAddress);
|
||||||
|
impl_primitive!(Secret, 32, Error::InvalidSecret);
|
||||||
|
impl_primitive!(Message, 32, Error::InvalidMessage);
|
||||||
|
impl_primitive!(Public, 64, Error::InvalidPublic);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
}
|
32
ethkey/src/random.rs
Normal file
32
ethkey/src/random.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 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 rand::os::OsRng;
|
||||||
|
use super::{Generator, KeyPair, Error, SECP256K1};
|
||||||
|
|
||||||
|
/// Randomly generates new keypair.
|
||||||
|
pub struct Random;
|
||||||
|
|
||||||
|
impl Generator for Random {
|
||||||
|
fn generate(self) -> Result<KeyPair, Error> {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
let mut rng = try!(OsRng::new());
|
||||||
|
let (sec, publ) = try!(context.generate_keypair(&mut rng));
|
||||||
|
|
||||||
|
Ok(KeyPair::from_keypair(sec, publ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
207
ethkey/src/signature.rs
Normal file
207
ethkey/src/signature.rs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
// 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::ops::{Deref, DerefMut};
|
||||||
|
use std::{mem, fmt};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use secp256k1::{Message as SecpMessage, RecoverableSignature, RecoveryId, Error as SecpError};
|
||||||
|
use secp256k1::key::{SecretKey, PublicKey};
|
||||||
|
use rustc_serialize::hex::{ToHex, FromHex};
|
||||||
|
use {Secret, Public, SECP256K1, Error, Message, public_to_address, Address};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Eq)]
|
||||||
|
pub struct Signature([u8; 65]);
|
||||||
|
|
||||||
|
impl Signature {
|
||||||
|
/// Get a slice into the 'r' portion of the data.
|
||||||
|
pub fn r(&self) -> &[u8] {
|
||||||
|
&self.0[0..32]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a slice into the 's' portion of the data.
|
||||||
|
pub fn s(&self) -> &[u8] {
|
||||||
|
&self.0[32..64]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the recovery byte.
|
||||||
|
pub fn v(&self) -> u8 {
|
||||||
|
self.0[64]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// manual implementation large arrays don't have trait impls by default.
|
||||||
|
// remove when integer generics exist
|
||||||
|
impl ::std::cmp::PartialEq for Signature {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
&self.0[..] == &other.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// also manual for the same reason, but the pretty printing might be useful.
|
||||||
|
impl fmt::Debug for Signature {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
f.debug_struct("Signature")
|
||||||
|
.field("r", &self.0[0..32].to_hex())
|
||||||
|
.field("s", &self.0[32..64].to_hex())
|
||||||
|
.field("v", &self.0[64..65].to_hex())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Signature {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "{}", self.to_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Signature {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.from_hex() {
|
||||||
|
Ok(ref hex) if hex.len() == 65 => {
|
||||||
|
let mut data = [0; 65];
|
||||||
|
data.copy_from_slice(&hex[0..65]);
|
||||||
|
Ok(Signature(data))
|
||||||
|
},
|
||||||
|
_ => Err(Error::InvalidSignature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Signature {
|
||||||
|
fn default() -> Self {
|
||||||
|
Signature([0; 65])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; 65]> for Signature {
|
||||||
|
fn from(s: [u8; 65]) -> Self {
|
||||||
|
Signature(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<[u8; 65]> for Signature {
|
||||||
|
fn into(self) -> [u8; 65] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Signature {
|
||||||
|
type Target = [u8; 65];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Signature {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
// no way to create from raw byte array.
|
||||||
|
let sec: &SecretKey = unsafe { mem::transmute(secret) };
|
||||||
|
let s = try!(context.sign_recoverable(&try!(SecpMessage::from_slice(&message[..])), sec));
|
||||||
|
let (rec_id, data) = s.serialize_compact(context);
|
||||||
|
let mut data_arr = [0; 65];
|
||||||
|
|
||||||
|
// no need to check if s is low, it always is
|
||||||
|
data_arr[0..64].copy_from_slice(&data[0..64]);
|
||||||
|
data_arr[64] = rec_id.to_i32() as u8;
|
||||||
|
Ok(Signature(data_arr))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_public(public: &Public, signature: &Signature, message: &Message) -> Result<bool, Error> {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
|
||||||
|
let sig = rsig.to_standard(context);
|
||||||
|
|
||||||
|
let pdata: [u8; 65] = {
|
||||||
|
let mut temp = [4u8; 65];
|
||||||
|
temp[1..65].copy_from_slice(public.deref());
|
||||||
|
temp
|
||||||
|
};
|
||||||
|
|
||||||
|
let publ = try!(PublicKey::from_slice(context, &pdata));
|
||||||
|
match context.verify(&try!(SecpMessage::from_slice(&message[..])), &sig, &publ) {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(SecpError::IncorrectSignature) => Ok(false),
|
||||||
|
Err(x) => Err(Error::from(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_address(address: &Address, signature: &Signature, message: &Message) -> Result<bool, Error> {
|
||||||
|
let public = try!(recover(signature, message));
|
||||||
|
let recovered_address = public_to_address(&public);
|
||||||
|
Ok(address == &recovered_address)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recover(signature: &Signature, message: &Message) -> Result<Public, Error> {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
|
||||||
|
let pubkey = try!(context.recover(&try!(SecpMessage::from_slice(&message[..])), &rsig));
|
||||||
|
let serialized = pubkey.serialize_vec(context, false);
|
||||||
|
|
||||||
|
let mut public = Public::default();
|
||||||
|
public.copy_from_slice(&serialized[1..65]);
|
||||||
|
Ok(public)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use {Generator, Random, Message};
|
||||||
|
use super::{sign, verify_public, verify_address, recover, Signature};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signature_to_and_from_str() {
|
||||||
|
let keypair = Random.generate().unwrap();
|
||||||
|
let message = Message::default();
|
||||||
|
let signature = sign(keypair.secret(), &message).unwrap();
|
||||||
|
let string = format!("{}", signature);
|
||||||
|
let deserialized = Signature::from_str(&string).unwrap();
|
||||||
|
assert_eq!(signature, deserialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sign_and_recover_public() {
|
||||||
|
let keypair = Random.generate().unwrap();
|
||||||
|
let message = Message::default();
|
||||||
|
let signature = sign(keypair.secret(), &message).unwrap();
|
||||||
|
assert_eq!(keypair.public(), &recover(&signature, &message).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sign_and_verify_public() {
|
||||||
|
let keypair = Random.generate().unwrap();
|
||||||
|
let message = Message::default();
|
||||||
|
let signature = sign(keypair.secret(), &message).unwrap();
|
||||||
|
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sign_and_verify_address() {
|
||||||
|
let keypair = Random.generate().unwrap();
|
||||||
|
let message = Message::default();
|
||||||
|
let signature = sign(keypair.secret(), &message).unwrap();
|
||||||
|
assert!(verify_address(&keypair.address(), &signature, &message).unwrap());
|
||||||
|
}
|
||||||
|
}
|
11
ethstore/.editorconfig
Normal file
11
ethstore/.editorconfig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
root = true
|
||||||
|
[*]
|
||||||
|
indent_style=tab
|
||||||
|
indent_size=tab
|
||||||
|
tab_width=4
|
||||||
|
end_of_line=lf
|
||||||
|
charset=utf-8
|
||||||
|
trim_trailing_whitespace=true
|
||||||
|
max_line_length=120
|
||||||
|
insert_final_newline=true
|
||||||
|
|
2
ethstore/.gitignore
vendored
Normal file
2
ethstore/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
target
|
||||||
|
*.swp
|
23
ethstore/.travis.yml
Normal file
23
ethstore/.travis.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
sudo: false
|
||||||
|
language: rust
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
matrix:
|
||||||
|
fast_finish: false
|
||||||
|
include:
|
||||||
|
- rust: stable
|
||||||
|
- rust: beta
|
||||||
|
- rust: nightly
|
||||||
|
after_success: |
|
||||||
|
[ $TRAVIS_BRANCH = master ] &&
|
||||||
|
[ $TRAVIS_PULL_REQUEST = false ] &&
|
||||||
|
[ $TRAVIS_RUST_VERSION = stable ] &&
|
||||||
|
cargo doc --no-deps --verbose &&
|
||||||
|
echo '<meta http-equiv=refresh content=0;url=ethkey/index.html>' > target/doc/index.html &&
|
||||||
|
pip install --user ghp-import &&
|
||||||
|
/home/travis/.local/bin/ghp-import -n target/doc &&
|
||||||
|
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- secure: C4l7WR0jS84WNmd3MvmpPXQz4wRh4CLDS6bP3BqSHXadz8FPKejtMJZscLYAk5kIkDcVsTAYb88RsEFRrYOA4wkS6vhZBtryYRaJ68MlkyEU/77SYwm86rkQINIDw65O73dUD5LbWWCUoYkenGu26u/UnfayHfJBAyKw5IHkVKf6eDqu7E8ojKSEOXbWgBHjq6uixI8IESb15UjIE0AQ1Od+6cqhsz/caPhTMT3CJGjoCoVGWChwWSQZ+Ppb+xB83C/1h58UVwE9sZEyIPKwVP6socnHPmtR+VEUI6a7YIsOk6ZadKLtyy4523w4HqHNx1/dYjmsknbGpkF4D0DRp5L3D4t4J6URCkJIHfSRrBF5l2QbLMMuSf+KWMWuFOrOF5DBryobRKAVmIL5AjfvFsxtBNzYLPyVBs0ntbPuN5WeUPhadam00za9Z1ZvOUJxfNfyy9R67u6FdD9xkw2m/9hO7KJLDeZ4TSCRFrzfl/7WQprfjCwhZ+reKPgHH0Ufy1/Kh/WEuEBfZDa+z3mWWHlslqH2uBPH3+pvhzdVQGLB/5GZdJNeg/nJYJDCqHyWUKxkw+OMSvI0J8W0GiHV4TuY9V3p+rYjU2Zj69u3/xO/IvKrFtB9xdeJMrLiFQ2cD5vgzQOLCKo80f53NitUjdVSoWrY/NcYopBU4VHZMlk=
|
30
ethstore/Cargo.toml
Normal file
30
ethstore/Cargo.toml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
[package]
|
||||||
|
name = "ethstore"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "0.2.11"
|
||||||
|
rand = "0.3.14"
|
||||||
|
ethkey = { path = "../ethkey" }
|
||||||
|
serde = "0.7"
|
||||||
|
serde_json = "0.7"
|
||||||
|
serde_macros = { version = "0.7", optional = true }
|
||||||
|
rustc-serialize = "0.3"
|
||||||
|
rust-crypto = "0.2.36"
|
||||||
|
tiny-keccak = "1.0"
|
||||||
|
docopt = { version = "0.6", optional = true }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
serde_codegen = { version = "0.7", optional = true }
|
||||||
|
syntex = "0.33.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["serde_codegen"]
|
||||||
|
nightly = ["serde_macros"]
|
||||||
|
cli = ["docopt"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "ethstore"
|
||||||
|
doc = false
|
185
ethstore/README.md
Normal file
185
ethstore/README.md
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
# ethstore
|
||||||
|
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
|
||||||
|
[travis-image]: https://travis-ci.org/ethcore/ethstore.svg?branch=master
|
||||||
|
[travis-url]: https://travis-ci.org/ethcore/ethstore
|
||||||
|
|
||||||
|
Ethereum key management.
|
||||||
|
|
||||||
|
[Documentation](http://ethcore.github.io/ethstore/ethstore/index.html)
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Ethereum key management.
|
||||||
|
Copyright 2016 Ethcore (UK) Limited
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
ethstore insert <secret> <password> [--dir DIR]
|
||||||
|
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]
|
||||||
|
ethstore list [--dir DIR]
|
||||||
|
ethstore import [--src DIR] [--dir DIR]
|
||||||
|
ethstore import-wallet <path> <password> [--dir DIR]
|
||||||
|
ethstore remove <address> <password> [--dir DIR]
|
||||||
|
ethstore sign <address> <password> <message> [--dir DIR]
|
||||||
|
ethstore [-h | --help]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Display this message and exit.
|
||||||
|
--dir DIR Specify the secret store directory. It may be either
|
||||||
|
parity, parity-test, geth, geth-test
|
||||||
|
or a path [default: parity].
|
||||||
|
--src DIR Specify import source. It may be either
|
||||||
|
parity, parity-test, get, geth-test
|
||||||
|
or a path [default: geth].
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
insert Save account with password.
|
||||||
|
change-pwd Change account password.
|
||||||
|
list List accounts.
|
||||||
|
import Import accounts from src.
|
||||||
|
import-wallet Import presale wallet.
|
||||||
|
remove Remove account.
|
||||||
|
sign Sign message.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### `insert <secret> <password> [--dir DIR]`
|
||||||
|
*Encrypt secret with a password and save it in secret store.*
|
||||||
|
|
||||||
|
- `<secret>` - ethereum secret, 32 bytes long
|
||||||
|
- `<password>` - account password, file path
|
||||||
|
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore insert 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 password.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
a8fa5dd30a87bb9e3288d604eb74949c515ab66e
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore insert `ethkey generate random -s` "this is sparta"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
24edfff680d536a5f6fe862d36df6f8f6f40f115
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]`
|
||||||
|
*Change account password.*
|
||||||
|
|
||||||
|
- `<address>` - ethereum address, 20 bytes long
|
||||||
|
- `<old-pwd>` - old account password, file path
|
||||||
|
- `<new-pwd>` - new account password, file path
|
||||||
|
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore change-pwd a8fa5dd30a87bb9e3288d604eb74949c515ab66e old_pwd.txt new_pwd.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `list [--dir DIR]`
|
||||||
|
*List secret store accounts.*
|
||||||
|
|
||||||
|
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore list
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
0: 24edfff680d536a5f6fe862d36df6f8f6f40f115
|
||||||
|
1: 6edddfc6349aff20bc6467ccf276c5b52487f7a8
|
||||||
|
2: e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `import [--src DIR] [--dir DIR]`
|
||||||
|
*Import accounts from src.*
|
||||||
|
|
||||||
|
- `[--src DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: geth
|
||||||
|
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore import
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
0: e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
|
||||||
|
1: 6edddfc6349aff20bc6467ccf276c5b52487f7a8
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `import-wallet <path> <password> [--dir DIR]`
|
||||||
|
*Import account from presale wallet.*
|
||||||
|
|
||||||
|
- `<path>` - presale wallet path
|
||||||
|
- `<password>` - account password, file path
|
||||||
|
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore import-wallet ethwallet.json password.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `remove <address> <password> [--dir DIR]`
|
||||||
|
*Remove account from secret store.*
|
||||||
|
|
||||||
|
- `<address>` - ethereum address, 20 bytes long
|
||||||
|
- `<password>` - account password, file path
|
||||||
|
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore remove a8fa5dd30a87bb9e3288d604eb74949c515ab66e password.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
#### `sign <address> <password> <message> [--dir DIR]`
|
||||||
|
*Sign message with account's secret.*
|
||||||
|
|
||||||
|
- `<address>` - ethereum address, 20 bytes long
|
||||||
|
- `<password>` - account password, file path
|
||||||
|
- `<message>` - message to sign, 32 bytes long
|
||||||
|
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore sign 24edfff680d536a5f6fe862d36df6f8f6f40f115 password.txt 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
c6649f9555232d90ff716d7e552a744c5af771574425a74860e12f763479eb1b708c1f3a7dc0a0a7f7a81e0a0ca88c6deacf469222bb3d9c5bf0847f98bae54901
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
# Ethcore toolchain
|
||||||
|
*this project is a part of the ethcore toolchain*
|
||||||
|
|
||||||
|
- [**ethkey**](https://github.com/ethcore/ethkey) - Ethereum keys generator and signer.
|
||||||
|
- [**ethstore**](https://github.com/ethcore/ethstore) - Ethereum key management.
|
||||||
|
- [**ethabi**](https://github.com/ethcore/ethabi) - Ethereum function calls encoding.
|
45
ethstore/build.rs
Normal file
45
ethstore/build.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#[cfg(not(feature = "serde_macros"))]
|
||||||
|
mod inner {
|
||||||
|
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/json/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 inner {
|
||||||
|
pub fn main() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
inner::main();
|
||||||
|
}
|
59
ethstore/src/account/cipher.rs
Normal file
59
ethstore/src/account/cipher.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// 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 json;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct Aes128Ctr {
|
||||||
|
pub iv: [u8; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum Cipher {
|
||||||
|
Aes128Ctr(Aes128Ctr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::Aes128Ctr> for Aes128Ctr {
|
||||||
|
fn from(json: json::Aes128Ctr) -> Self {
|
||||||
|
Aes128Ctr {
|
||||||
|
iv: json.iv.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<json::Aes128Ctr> for Aes128Ctr {
|
||||||
|
fn into(self) -> json::Aes128Ctr {
|
||||||
|
json::Aes128Ctr {
|
||||||
|
iv: From::from(self.iv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::Cipher> for Cipher {
|
||||||
|
fn from(json: json::Cipher) -> Self {
|
||||||
|
match json {
|
||||||
|
json::Cipher::Aes128Ctr(params) => Cipher::Aes128Ctr(From::from(params)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<json::Cipher> for Cipher {
|
||||||
|
fn into(self) -> json::Cipher {
|
||||||
|
match self {
|
||||||
|
Cipher::Aes128Ctr(params) => json::Cipher::Aes128Ctr(params.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user