Merge remote-tracking branch 'parity/master' into bft

Conflicts:
	ethcore/src/client/client.rs
This commit is contained in:
keorn 2016-10-05 14:57:14 +01:00
commit 1f56588b87
89 changed files with 1867 additions and 763 deletions

View File

@ -19,9 +19,11 @@ linux-stable:
script: script:
- cargo build --release --verbose - cargo build --release --verbose
- strip target/release/parity - strip target/release/parity
- md5sum target/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/checksum --body checksum
tags: tags:
- rust - rust
- rust-stable - rust-stable
@ -40,9 +42,11 @@ linux-stable-14.04:
script: script:
- cargo build --release --verbose - cargo build --release --verbose
- strip target/release/parity - strip target/release/parity
- md5sum target/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/parity --body target/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/checksum --body checksum
tags: tags:
- rust - rust
- rust-14.04 - rust-14.04
@ -101,9 +105,11 @@ linux-centos:
- export CC="gcc" - export CC="gcc"
- cargo build --release --verbose - cargo build --release --verbose
- strip target/release/parity - strip target/release/parity
- md5sum target/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/checksum --body checksum
tags: tags:
- rust - rust
- rust-centos - rust-centos
@ -127,9 +133,11 @@ linux-armv7:
- cat .cargo/config - cat .cargo/config
- cargo build --target armv7-unknown-linux-gnueabihf --release --verbose - cargo build --target armv7-unknown-linux-gnueabihf --release --verbose
- arm-linux-gnueabihf-strip target/armv7-unknown-linux-gnueabihf/release/parity - arm-linux-gnueabihf-strip target/armv7-unknown-linux-gnueabihf/release/parity
- md5sum target/armv7-unknown-linux-gnueabihf/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity --body target/armv7-unknown-linux-gnueabihf/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity --body target/armv7-unknown-linux-gnueabihf/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/checksum --body checksum
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -154,9 +162,11 @@ linux-arm:
- cat .cargo/config - cat .cargo/config
- cargo build --target arm-unknown-linux-gnueabihf --release --verbose - cargo build --target arm-unknown-linux-gnueabihf --release --verbose
- arm-linux-gnueabihf-strip target/arm-unknown-linux-gnueabihf/release/parity - arm-linux-gnueabihf-strip target/arm-unknown-linux-gnueabihf/release/parity
- md5sum target/arm-unknown-linux-gnueabihf/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity --body target/arm-unknown-linux-gnueabihf/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity --body target/arm-unknown-linux-gnueabihf/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/checksum --body checksum
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -181,9 +191,11 @@ linux-armv6:
- cat .cargo/config - cat .cargo/config
- cargo build --target arm-unknown-linux-gnueabi --release --verbose - cargo build --target arm-unknown-linux-gnueabi --release --verbose
- arm-linux-gnueabi-strip target/arm-unknown-linux-gnueabi/release/parity - arm-linux-gnueabi-strip target/arm-unknown-linux-gnueabi/release/parity
- md5sum target/arm-unknown-linux-gnueabi/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity --body target/arm-unknown-linux-gnueabi/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity --body target/arm-unknown-linux-gnueabi/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/checksum --body checksum
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -208,9 +220,11 @@ linux-aarch64:
- cat .cargo/config - cat .cargo/config
- cargo build --target aarch64-unknown-linux-gnu --release --verbose - cargo build --target aarch64-unknown-linux-gnu --release --verbose
- aarch64-linux-gnu-strip target/aarch64-unknown-linux-gnu/release/parity - aarch64-linux-gnu-strip target/aarch64-unknown-linux-gnu/release/parity
- md5sum target/aarch64-unknown-linux-gnu/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity --body target/aarch64-unknown-linux-gnu/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity --body target/aarch64-unknown-linux-gnu/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/checksum --body checksum
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -228,9 +242,11 @@ darwin:
- stable - stable
script: script:
- cargo build --release --verbose - cargo build --release --verbose
- md5sum target/release/parity >> checksum
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity --body target/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/checksum --body checksum
tags: tags:
- osx - osx
artifacts: artifacts:
@ -248,12 +264,15 @@ windows:
- set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;C:\vs2015\VC\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt - set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;C:\vs2015\VC\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt
- set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64 - set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64
- set RUST_BACKTRACE=1 - set RUST_BACKTRACE=1
- set RUSTFLAGS=-Zorbit=off
- rustup default stable-x86_64-pc-windows-msvc - rustup default stable-x86_64-pc-windows-msvc
- cargo build --release --verbose - cargo build --release --verbose
- cmd md5sum target\release\parity >> checksum
- aws configure set aws_access_key_id %s3_key% - aws configure set aws_access_key_id %s3_key%
- aws configure set aws_secret_access_key %s3_secret% - aws configure set aws_secret_access_key %s3_secret%
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity --body target/release/parity.exe - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity --body target\release\parity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity --body target/release/parity.pdb - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity --body target\release\parity.pdb
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/checksum --body checksum
tags: tags:
- rust-windows - rust-windows
artifacts: artifacts:

13
Cargo.lock generated
View File

@ -120,6 +120,11 @@ name = "bloomchain"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "0.3.0" version = "0.3.0"
@ -270,10 +275,12 @@ version = "1.4.0"
dependencies = [ dependencies = [
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.90 (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.4.0", "ethash 1.4.0",
"ethcore-bloom-journal 0.1.0",
"ethcore-devtools 1.4.0", "ethcore-devtools 1.4.0",
"ethcore-io 1.4.0", "ethcore-io 1.4.0",
"ethcore-ipc 1.4.0", "ethcore-ipc 1.4.0",
@ -309,6 +316,10 @@ dependencies = [
"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)",
] ]
[[package]]
name = "ethcore-bloom-journal"
version = "0.1.0"
[[package]] [[package]]
name = "ethcore-dapps" name = "ethcore-dapps"
version = "1.4.0" version = "1.4.0"
@ -528,6 +539,7 @@ dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"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-bigint 0.1.0", "ethcore-bigint 0.1.0",
"ethcore-bloom-journal 0.1.0",
"ethcore-devtools 1.4.0", "ethcore-devtools 1.4.0",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (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)",
@ -1896,6 +1908,7 @@ dependencies = [
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
"checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2" "checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2"
"checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d" "checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d"
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27" "checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
"checksum bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)" = "<none>" "checksum bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)" = "<none>"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"

View File

@ -62,7 +62,7 @@ default = ["ui", "use-precompiled-js", "ipc"]
ui = ["dapps", "ethcore-signer/ui"] ui = ["dapps", "ethcore-signer/ui"]
use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"] use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"]
dapps = ["ethcore-dapps"] dapps = ["ethcore-dapps"]
ipc = ["ethcore/ipc"] ipc = ["ethcore/ipc", "ethsync/ipc"]
jit = ["ethcore/jit"] jit = ["ethcore/jit"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"]
json-tests = ["ethcore/json-tests"] json-tests = ["ethcore/json-tests"]
@ -70,12 +70,14 @@ stratum = ["ipc"]
ethkey-cli = ["ethcore/ethkey-cli"] ethkey-cli = ["ethcore/ethkey-cli"]
ethstore-cli = ["ethcore/ethstore-cli"] ethstore-cli = ["ethcore/ethstore-cli"]
evm-debug = ["ethcore/evm-debug"] evm-debug = ["ethcore/evm-debug"]
evm-debug-tests = ["ethcore/evm-debug-tests"]
slow-blocks = ["ethcore/slow-blocks"]
[[bin]] [[bin]]
path = "parity/main.rs" path = "parity/main.rs"
name = "parity" name = "parity"
[profile.release] [profile.release]
debug = true debug = false
lto = false lto = false

View File

@ -5,6 +5,7 @@
[Internal Documentation][doc-url] [Internal Documentation][doc-url]
Be sure to check out [our wiki][wiki-url] for more information. Be sure to check out [our wiki][wiki-url] for more information.
[travis-image]: https://travis-ci.org/ethcore/parity.svg?branch=master [travis-image]: https://travis-ci.org/ethcore/parity.svg?branch=master
@ -18,8 +19,11 @@ Be sure to check out [our wiki][wiki-url] for more information.
[doc-url]: https://ethcore.github.io/parity/ethcore/index.html [doc-url]: https://ethcore.github.io/parity/ethcore/index.html
[wiki-url]: https://github.com/ethcore/parity/wiki [wiki-url]: https://github.com/ethcore/parity/wiki
**Requires Rust version 1.12.0 to build**
---- ----
## About Parity ## About Parity
Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and
@ -96,9 +100,9 @@ and Parity will begin syncing the Ethereum blockchain.
### Using systemd service file ### Using systemd service file
To start Parity as a regular user using systemd init: To start Parity as a regular user using systemd init:
1. Copy ```parity/scripts/parity.service``` to your 1. Copy `parity/scripts/parity.service` to your
systemd user directory (usually ```~/.config/systemd/user```). systemd user directory (usually `~/.config/systemd/user`).
2. To pass any argument to Parity, write a ```~/.parity/parity.conf``` file this way: 2. To pass any argument to Parity, write a `~/.parity/parity.conf` file this way:
```ARGS="ARG1 ARG2 ARG3"```. `ARGS="ARG1 ARG2 ARG3"`.
Example: ```ARGS="ui --geth --identity MyMachine"```. Example: `ARGS="ui --geth --identity MyMachine"`.

View File

@ -6,6 +6,7 @@ environment:
certpass: certpass:
secure: 0BgXJqxq9Ei34/hZ7121FQ== secure: 0BgXJqxq9Ei34/hZ7121FQ==
keyfile: C:\users\appveyor\Certificates.p12 keyfile: C:\users\appveyor\Certificates.p12
RUSTFLAGS: -Zorbit=off
branches: branches:
only: only:
@ -18,10 +19,10 @@ branches:
install: install:
- git submodule update --init --recursive - git submodule update --init --recursive
- ps: Install-Product node 6 - ps: Install-Product node 6
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.10.0-x86_64-pc-windows-msvc.exe" - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.12.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/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 - ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe
- rust-1.10.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - rust-1.12.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 - 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 - rustc -V
- cargo -V - cargo -V

View File

@ -157,7 +157,7 @@ impl Drop for Database {
} }
} }
#[derive(Ipc)] #[ipc]
impl DatabaseService for Database { impl DatabaseService for Database {
fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error> { fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error> {
let mut db = self.db.write(); let mut db = self.db.write();

View File

@ -38,6 +38,8 @@ ethcore-ipc-nano = { path = "../ipc/nano" }
rlp = { path = "../util/rlp" } rlp = { path = "../util/rlp" }
rand = "0.3" rand = "0.3"
lru-cache = "0.0.7" lru-cache = "0.0.7"
ethcore-bloom-journal = { path = "../util/bloom" }
byteorder = "0.5"
[dependencies.hyper] [dependencies.hyper]
git = "https://github.com/ethcore/hyper" git = "https://github.com/ethcore/hyper"
@ -45,7 +47,9 @@ default-features = false
[features] [features]
jit = ["evmjit"] jit = ["evmjit"]
evm-debug = [] evm-debug = ["slow-blocks"]
evm-debug-tests = ["evm-debug"]
slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms
json-tests = [] json-tests = []
test-heavy = [] test-heavy = []
dev = ["clippy"] dev = ["clippy"]

View File

@ -8,7 +8,7 @@
"difficultyBoundDivisor": "0x0800", "difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar": "0x8e4e9b13d4b45cb0befc93c3061b1408f67316b2", "registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d",
"frontierCompatibilityModeLimit": "0x789b0" "frontierCompatibilityModeLimit": "0x789b0"
} }
} }

View File

@ -121,6 +121,10 @@ impl<'db> HashDB for AccountDB<'db>{
fn remove(&mut self, _key: &H256) { fn remove(&mut self, _key: &H256) {
unimplemented!() unimplemented!()
} }
fn get_aux(&self, hash: &[u8]) -> Option<Vec<u8>> {
self.db.get_aux(hash)
}
} }
/// DB backend wrapper for Account trie /// DB backend wrapper for Account trie
@ -193,6 +197,18 @@ impl<'db> HashDB for AccountDBMut<'db>{
let key = combine_key(&self.address_hash, key); let key = combine_key(&self.address_hash, key);
self.db.remove(&key) self.db.remove(&key)
} }
fn insert_aux(&mut self, hash: Vec<u8>, value: Vec<u8>) {
self.db.insert_aux(hash, value);
}
fn get_aux(&self, hash: &[u8]) -> Option<Vec<u8>> {
self.db.get_aux(hash)
}
fn remove_aux(&mut self, hash: &[u8]) {
self.db.remove_aux(hash);
}
} }
struct Wrapping<'db>(&'db HashDB); struct Wrapping<'db>(&'db HashDB);

View File

@ -43,6 +43,8 @@ impl ActionValue {
pub struct ActionParams { pub struct ActionParams {
/// Address of currently executed code. /// Address of currently executed code.
pub code_address: Address, pub code_address: Address,
/// Hash of currently executed code.
pub code_hash: H256,
/// Receive address. Usually equal to code_address, /// Receive address. Usually equal to code_address,
/// except when called using CALLCODE. /// except when called using CALLCODE.
pub address: Address, pub address: Address,
@ -57,7 +59,7 @@ pub struct ActionParams {
/// Transaction value. /// Transaction value.
pub value: ActionValue, pub value: ActionValue,
/// Code being executed. /// Code being executed.
pub code: Option<Bytes>, pub code: Option<Arc<Bytes>>,
/// Input data. /// Input data.
pub data: Option<Bytes>, pub data: Option<Bytes>,
/// Type of call /// Type of call
@ -70,6 +72,7 @@ impl Default for ActionParams {
fn default() -> ActionParams { fn default() -> ActionParams {
ActionParams { ActionParams {
code_address: Address::new(), code_address: Address::new(),
code_hash: SHA3_EMPTY,
address: Address::new(), address: Address::new(),
sender: Address::new(), sender: Address::new(),
origin: Address::new(), origin: Address::new(),
@ -88,10 +91,11 @@ impl From<ethjson::vm::Transaction> for ActionParams {
let address: Address = t.address.into(); let address: Address = t.address.into();
ActionParams { ActionParams {
code_address: Address::new(), code_address: Address::new(),
code_hash: (&*t.code).sha3(),
address: address, address: address,
sender: t.sender.into(), sender: t.sender.into(),
origin: t.origin.into(), origin: t.origin.into(),
code: Some(t.code.into()), code: Some(Arc::new(t.code.into())),
data: Some(t.data.into()), data: Some(t.data.into()),
gas: t.gas.into(), gas: t.gas.into(),
gas_price: t.gas_price.into(), gas_price: t.gas_price.into(),

View File

@ -16,14 +16,26 @@
//! Blockchain block. //! Blockchain block.
use common::*; use std::sync::Arc;
use std::collections::HashSet;
use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, Decoder, DecoderError, View, Stream};
use util::{Bytes, Address, Uint, FixedHash, Hashable, U256, H256, ordered_trie_root, SHA3_NULL_RLP};
use util::error::{Mismatch, OutOfBounds};
use basic_types::{LogBloom, Seal};
use env_info::{EnvInfo, LastHashes};
use engines::Engine; use engines::Engine;
use state::*; use error::{Error, BlockError, TransactionError};
use state_db::StateDB;
use verification::PreverifiedBlock;
use trace::FlatTrace;
use factory::Factories; use factory::Factories;
use rlp::*; use header::Header;
use receipt::Receipt;
use state::State;
use state_db::StateDB;
use trace::FlatTrace;
use transaction::SignedTransaction;
use verification::PreverifiedBlock;
use views::BlockView;
/// A block, encoded as it is on the block chain. /// A block, encoded as it is on the block chain.
#[derive(Default, Debug, Clone, PartialEq)] #[derive(Default, Debug, Clone, PartialEq)]
@ -518,25 +530,38 @@ pub fn enact(
b.set_uncles_hash(header.uncles_hash().clone()); b.set_uncles_hash(header.uncles_hash().clone());
b.set_transactions_root(header.transactions_root().clone()); b.set_transactions_root(header.transactions_root().clone());
b.set_receipts_root(header.receipts_root().clone()); b.set_receipts_root(header.receipts_root().clone());
for t in transactions { try!(b.push_transaction(t.clone(), None)); }
for u in uncles { try!(b.push_uncle(u.clone())); } try!(push_transactions(&mut b, transactions));
for u in uncles {
try!(b.push_uncle(u.clone()));
}
Ok(b.close_and_lock()) Ok(b.close_and_lock())
} }
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header #[inline(always)]
#[cfg_attr(feature="dev", allow(too_many_arguments))] #[cfg(not(feature = "slow-blocks"))]
pub fn enact_bytes( fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> {
block_bytes: &[u8], for t in transactions {
engine: &Engine, try!(block.push_transaction(t.clone(), None));
tracing: bool, }
db: StateDB, Ok(())
parent: &Header, }
last_hashes: Arc<LastHashes>,
factories: Factories, #[cfg(feature = "slow-blocks")]
) -> Result<LockedBlock, Error> { fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> {
let block = BlockView::new(block_bytes); use std::time;
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, factories) let slow_tx = option_env!("SLOW_TX_DURATION").and_then(|v| v.parse().ok()).unwrap_or(100);
for t in transactions {
let hash = t.hash();
let start = time::Instant::now();
try!(block.push_transaction(t.clone(), None));
let took = start.elapsed();
if took > time::Duration::from_millis(slow_tx) {
warn!("Heavy transaction in block {:?}: {:?}", block.header().number(), hash);
}
}
Ok(())
} }
/// 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
@ -554,26 +579,45 @@ pub fn enact_verified(
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, factories) enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, factories)
} }
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
#[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn enact_and_seal(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
factories: Factories,
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)).seal(engine, header.seal())))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use tests::helpers::*; use tests::helpers::*;
use super::*; use super::*;
use common::*; use common::*;
use engines::Engine;
use factory::Factories;
use state_db::StateDB;
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn enact_bytes(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
factories: Factories,
) -> Result<LockedBlock, Error> {
let block = BlockView::new(block_bytes);
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, factories)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn enact_and_seal(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
factories: Factories,
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)).seal(engine, header.seal())))
}
#[test] #[test]
fn open_block() { fn open_block() {

View File

@ -18,7 +18,7 @@ use ipc::IpcConfig;
use util::H256; use util::H256;
/// Represents what has to be handled by actor listening to chain events /// Represents what has to be handled by actor listening to chain events
#[derive(Ipc)] #[ipc]
pub trait ChainNotify : Send + Sync { pub trait ChainNotify : Send + Sync {
/// fires when chain has new blocks. /// fires when chain has new blocks.
fn new_blocks(&self, fn new_blocks(&self,

View File

@ -23,10 +23,10 @@ use time::precise_time_ns;
// util // util
use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock}; use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock};
use util::journaldb; use util::{journaldb, TrieFactory, Trie};
use util::{U256, H256, H520, Address, H2048, Uint}; use util::{U256, H256, H520, Address, H2048, Uint, FixedHash};
use util::sha3::*; use util::sha3::*;
use util::TrieFactory; use util::trie::TrieSpec;
use util::kvdb::*; use util::kvdb::*;
// other // other
@ -53,7 +53,7 @@ use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{ use client::{
BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient,
MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
ChainNotify ChainNotify,
}; };
use client::Error as ClientError; use client::Error as ClientError;
use env_info::EnvInfo; use env_info::EnvInfo;
@ -173,6 +173,11 @@ impl Client {
let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone(), spec.engine.clone())); let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone(), spec.engine.clone()));
let tracedb = RwLock::new(TraceDB::new(config.tracing.clone(), db.clone(), chain.clone())); let tracedb = RwLock::new(TraceDB::new(config.tracing.clone(), db.clone(), chain.clone()));
let trie_spec = match config.fat_db {
true => TrieSpec::Fat,
false => TrieSpec::Secure,
};
let journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE); let journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE);
let mut state_db = StateDB::new(journal_db); let mut state_db = StateDB::new(journal_db);
if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db)) { if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db)) {
@ -195,7 +200,7 @@ impl Client {
let factories = Factories { let factories = Factories {
vm: EvmFactory::new(config.vm_type.clone()), vm: EvmFactory::new(config.vm_type.clone()),
trie: TrieFactory::new(config.trie_spec.clone()), trie: TrieFactory::new(trie_spec),
accountdb: Default::default(), accountdb: Default::default(),
}; };
@ -833,7 +838,7 @@ impl BlockChainClient for Client {
} }
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>> { fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>> {
self.state_at(id).map(|s| s.code(address)) self.state_at(id).map(|s| s.code(address).map(|c| (*c).clone()))
} }
fn balance(&self, address: &Address, id: BlockID) -> Option<U256> { fn balance(&self, address: &Address, id: BlockID) -> Option<U256> {
@ -844,6 +849,38 @@ impl BlockChainClient for Client {
self.state_at(id).map(|s| s.storage_at(address, position)) self.state_at(id).map(|s| s.storage_at(address, position))
} }
fn list_accounts(&self, id: BlockID) -> Option<Vec<Address>> {
if !self.factories.trie.is_fat() {
trace!(target: "fatdb", "list_accounts: Not a fat DB");
return None;
}
let state = match self.state_at(id) {
Some(state) => state,
_ => return None,
};
let (root, db) = state.drop();
let trie = match self.factories.trie.readonly(db.as_hashdb(), &root) {
Ok(trie) => trie,
_ => {
trace!(target: "fatdb", "list_accounts: Couldn't open the DB");
return None;
}
};
let iter = match trie.iter() {
Ok(iter) => iter,
_ => return None,
};
let accounts = iter.filter_map(|item| {
item.ok().map(|(addr, _)| Address::from_slice(&addr))
}).collect();
Some(accounts)
}
fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction> { fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction> {
self.transaction_address(id).and_then(|address| self.chain.read().transaction(&address)) self.transaction_address(id).and_then(|address| self.chain.read().transaction(&address))
} }

View File

@ -22,7 +22,6 @@ pub use evm::VMType;
use verification::{VerifierType, QueueConfig}; use verification::{VerifierType, QueueConfig};
use util::{journaldb, CompactionProfile}; use util::{journaldb, CompactionProfile};
use util::trie::TrieSpec;
/// Client state db compaction profile /// Client state db compaction profile
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -91,8 +90,8 @@ pub struct ClientConfig {
pub tracing: TraceConfig, pub tracing: TraceConfig,
/// VM type. /// VM type.
pub vm_type: VMType, pub vm_type: VMType,
/// Trie type. /// Fat DB enabled?
pub trie_spec: TrieSpec, pub fat_db: bool,
/// The JournalDB ("pruning") algorithm to use. /// The JournalDB ("pruning") algorithm to use.
pub pruning: journaldb::Algorithm, pub pruning: journaldb::Algorithm,
/// The name of the client instance. /// The name of the client instance.

View File

@ -25,8 +25,9 @@ use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute; use blockchain::TreeRoute;
use client::{ use client::{
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID, BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError,
}; };
use db::{NUM_COLUMNS, COL_STATE};
use header::{Header as BlockHeader, BlockNumber}; use header::{Header as BlockHeader, BlockNumber};
use filter::Filter; use filter::Filter;
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
@ -286,8 +287,8 @@ impl TestBlockChainClient {
pub fn get_temp_state_db() -> GuardedTempResult<StateDB> { pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
let temp = RandomTempPath::new(); let temp = RandomTempPath::new();
let db = Database::open_default(temp.as_str()).unwrap(); let db = Database::open(&DatabaseConfig::with_columns(NUM_COLUMNS), temp.as_str()).unwrap();
let journal_db = journaldb::new(Arc::new(db), journaldb::Algorithm::EarlyMerge, None); let journal_db = journaldb::new(Arc::new(db), journaldb::Algorithm::EarlyMerge, COL_STATE);
let state_db = StateDB::new(journal_db); let state_db = StateDB::new(journal_db);
GuardedTempResult { GuardedTempResult {
_temp: temp, _temp: temp,
@ -384,6 +385,10 @@ impl BlockChainClient for TestBlockChainClient {
} }
} }
fn list_accounts(&self, _id: BlockID) -> Option<Vec<Address>> {
None
}
fn transaction(&self, _id: TransactionID) -> Option<LocalizedTransaction> { fn transaction(&self, _id: TransactionID) -> Option<LocalizedTransaction> {
None // Simple default. None // Simple default.
} }

View File

@ -38,7 +38,6 @@ use ipc::IpcConfig;
use types::blockchain_info::BlockChainInfo; use types::blockchain_info::BlockChainInfo;
use types::block_status::BlockStatus; use types::block_status::BlockStatus;
#[derive(Ipc)]
#[ipc(client_ident="RemoteClient")] #[ipc(client_ident="RemoteClient")]
/// Blockchain database client. Owns and manages a blockchain and a block queue. /// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send { pub trait BlockChainClient : Sync + Send {
@ -112,6 +111,9 @@ pub trait BlockChainClient : Sync + Send {
Therefore storage_at has returned Some; qed") Therefore storage_at has returned Some; qed")
} }
/// Get a list of all accounts in the block `id`, if fat DB is in operation, otherwise `None`.
fn list_accounts(&self, id: BlockID) -> Option<Vec<Address>>;
/// Get transaction with given hash. /// Get transaction with given hash.
fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction>; fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction>;

View File

@ -34,8 +34,10 @@ pub const COL_BODIES: Option<u32> = Some(2);
pub const COL_EXTRA: Option<u32> = Some(3); pub const COL_EXTRA: Option<u32> = Some(3);
/// Column for Traces /// Column for Traces
pub const COL_TRACE: Option<u32> = Some(4); pub const COL_TRACE: Option<u32> = Some(4);
/// Column for Traces
pub const COL_ACCOUNT_BLOOM: Option<u32> = Some(5);
/// Number of columns in DB /// Number of columns in DB
pub const NUM_COLUMNS: Option<u32> = Some(5); pub const NUM_COLUMNS: Option<u32> = Some(6);
/// Modes for updating caches. /// Modes for updating caches.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]

View File

@ -81,7 +81,7 @@ pub trait Ext {
) -> MessageCallResult; ) -> MessageCallResult;
/// Returns code at given address /// Returns code at given address
fn extcode(&self, address: &Address) -> Bytes; fn extcode(&self, address: &Address) -> Arc<Bytes>;
/// Returns code size at given address /// Returns code size at given address
fn extcodesize(&self, address: &Address) -> usize; fn extcodesize(&self, address: &Address) -> usize;

View File

@ -18,8 +18,10 @@
//! //!
//! TODO: consider spliting it into two separate files. //! TODO: consider spliting it into two separate files.
use std::fmt; use std::fmt;
use std::sync::Arc;
use evm::Evm; use evm::Evm;
use util::{U256, Uint}; use util::{U256, Uint};
use super::interpreter::SharedCache;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
/// Type of EVM to use. /// Type of EVM to use.
@ -82,7 +84,8 @@ impl VMType {
/// Evm factory. Creates appropriate Evm. /// Evm factory. Creates appropriate Evm.
#[derive(Clone)] #[derive(Clone)]
pub struct Factory { pub struct Factory {
evm: VMType evm: VMType,
evm_cache: Arc<SharedCache>,
} }
impl Factory { impl Factory {
@ -95,9 +98,9 @@ impl Factory {
Box::new(super::jit::JitEvm::default()) Box::new(super::jit::JitEvm::default())
}, },
VMType::Interpreter => if Self::can_fit_in_usize(gas) { VMType::Interpreter => if Self::can_fit_in_usize(gas) {
Box::new(super::interpreter::Interpreter::<usize>::default()) Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
} else { } else {
Box::new(super::interpreter::Interpreter::<U256>::default()) Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
} }
} }
} }
@ -108,9 +111,9 @@ impl Factory {
pub fn create(&self, gas: U256) -> Box<Evm> { pub fn create(&self, gas: U256) -> Box<Evm> {
match self.evm { match self.evm {
VMType::Interpreter => if Self::can_fit_in_usize(gas) { VMType::Interpreter => if Self::can_fit_in_usize(gas) {
Box::new(super::interpreter::Interpreter::<usize>::default()) Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
} else { } else {
Box::new(super::interpreter::Interpreter::<U256>::default()) Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
} }
} }
} }
@ -118,7 +121,8 @@ impl Factory {
/// Create new instance of specific `VMType` factory /// Create new instance of specific `VMType` factory
pub fn new(evm: VMType) -> Self { pub fn new(evm: VMType) -> Self {
Factory { Factory {
evm: evm evm: evm,
evm_cache: Arc::new(SharedCache::default()),
} }
} }
@ -132,7 +136,8 @@ impl Default for Factory {
#[cfg(all(feature = "jit", not(test)))] #[cfg(all(feature = "jit", not(test)))]
fn default() -> Factory { fn default() -> Factory {
Factory { Factory {
evm: VMType::Jit evm: VMType::Jit,
evm_cache: Arc::new(SharedCache::default()),
} }
} }
@ -140,7 +145,8 @@ impl Default for Factory {
#[cfg(any(not(feature = "jit"), test))] #[cfg(any(not(feature = "jit"), test))]
fn default() -> Factory { fn default() -> Factory {
Factory { Factory {
evm: VMType::Interpreter evm: VMType::Interpreter,
evm_cache: Arc::new(SharedCache::default()),
} }
} }
} }

View File

@ -0,0 +1,164 @@
// 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/>.
pub use self::inner::*;
#[macro_use]
#[cfg(not(feature = "evm-debug"))]
mod inner {
macro_rules! evm_debug {
($x: expr) => {}
}
pub struct EvmInformant;
impl EvmInformant {
pub fn new(_depth: usize) -> Self {
EvmInformant {}
}
pub fn done(&mut self) {}
}
}
#[macro_use]
#[cfg(feature = "evm-debug")]
mod inner {
use std::iter;
use std::collections::HashMap;
use std::time::{Instant, Duration};
use evm::interpreter::stack::Stack;
use evm::instructions::{Instruction, InstructionInfo, INSTRUCTIONS};
use evm::{CostType};
use util::U256;
macro_rules! evm_debug {
($x: expr) => {
$x
}
}
fn print(data: String) {
if cfg!(feature = "evm-debug-tests") {
println!("{}", data);
} else {
debug!(target: "evm", "{}", data);
}
}
pub struct EvmInformant {
spacing: String,
last_instruction: Instant,
stats: HashMap<Instruction, Stats>,
}
impl EvmInformant {
fn color(instruction: Instruction, name: &str) -> String {
let c = instruction as usize % 6;
let colors = [31, 34, 33, 32, 35, 36];
format!("\x1B[1;{}m{}\x1B[0m", colors[c], name)
}
fn as_micro(duration: &Duration) -> u64 {
let mut sec = duration.as_secs();
let subsec = duration.subsec_nanos() as u64;
sec = sec.saturating_mul(1_000_000u64);
sec += subsec / 1_000;
sec
}
pub fn new(depth: usize) -> Self {
EvmInformant {
spacing: iter::repeat(".").take(depth).collect(),
last_instruction: Instant::now(),
stats: HashMap::new(),
}
}
pub fn before_instruction<Cost: CostType>(&mut self, pc: usize, instruction: Instruction, info: &InstructionInfo, current_gas: &Cost, stack: &Stack<U256>) {
let time = self.last_instruction.elapsed();
self.last_instruction = Instant::now();
print(format!("{}[0x{:<3x}][{:>19}(0x{:<2x}) Gas Left: {:6?} (Previous took: {:10}μs)",
&self.spacing,
pc,
Self::color(instruction, info.name),
instruction,
current_gas,
Self::as_micro(&time),
));
if info.args > 0 {
for (idx, item) in stack.peek_top(info.args).iter().enumerate() {
print(format!("{} |{:2}: {:?}", self.spacing, idx, item));
}
}
}
pub fn after_instruction(&mut self, instruction: Instruction) {
let mut stats = self.stats.entry(instruction).or_insert_with(|| Stats::default());
let took = self.last_instruction.elapsed();
stats.note(took);
}
pub fn done(&mut self) {
// Print out stats
let infos = &*INSTRUCTIONS;
let mut stats: Vec<(_,_)> = self.stats.drain().collect();
stats.sort_by(|ref a, ref b| b.1.avg().cmp(&a.1.avg()));
print(format!("\n{}-------OPCODE STATS:", self.spacing));
for (instruction, stats) in stats.into_iter() {
let info = infos[instruction as usize];
print(format!("{}-------{:>19}(0x{:<2x}) count: {:4}, avg: {:10}μs",
self.spacing,
Self::color(instruction, info.name),
instruction,
stats.count,
stats.avg(),
));
}
}
}
struct Stats {
count: u64,
total_duration: Duration,
}
impl Default for Stats {
fn default() -> Self {
Stats {
count: 0,
total_duration: Duration::from_secs(0),
}
}
}
impl Stats {
fn note(&mut self, took: Duration) {
self.count += 1;
self.total_duration += took;
}
fn avg(&self) -> u64 {
EvmInformant::as_micro(&self.total_duration) / self.count
}
}
}

View File

@ -16,25 +16,17 @@
//! Rust VM implementation //! Rust VM implementation
#[cfg(not(feature = "evm-debug"))] #[macro_use]
macro_rules! evm_debug { mod informant;
($x: expr) => {}
}
#[cfg(feature = "evm-debug")]
macro_rules! evm_debug {
($x: expr) => {
$x
}
}
mod gasometer; mod gasometer;
mod stack; mod stack;
mod memory; mod memory;
mod shared_cache;
use self::gasometer::Gasometer; use self::gasometer::Gasometer;
use self::stack::{Stack, VecStack}; use self::stack::{Stack, VecStack};
use self::memory::Memory; use self::memory::Memory;
pub use self::shared_cache::SharedCache;
use std::marker::PhantomData; use std::marker::PhantomData;
use common::*; use common::*;
@ -43,13 +35,6 @@ use super::instructions::{self, Instruction, InstructionInfo};
use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType}; use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType};
use bit_set::BitSet; use bit_set::BitSet;
#[cfg(feature = "evm-debug")]
fn color(instruction: Instruction, name: &'static str) -> String {
let c = instruction as usize % 6;
let colors = [31, 34, 33, 32, 35, 36];
format!("\x1B[1;{}m{}\x1B[0m", colors[c], name)
}
type CodePosition = usize; type CodePosition = usize;
type ProgramCounter = usize; type ProgramCounter = usize;
@ -72,6 +57,15 @@ struct CodeReader<'a> {
#[cfg_attr(feature="dev", allow(len_without_is_empty))] #[cfg_attr(feature="dev", allow(len_without_is_empty))]
impl<'a> CodeReader<'a> { impl<'a> CodeReader<'a> {
/// Create new code reader - starting at position 0.
fn new(code: &'a Bytes) -> Self {
CodeReader {
position: 0,
code: code,
}
}
/// Get `no_of_bytes` from code and convert to U256. Move PC /// Get `no_of_bytes` from code and convert to U256. Move PC
fn read(&mut self, no_of_bytes: usize) -> U256 { fn read(&mut self, no_of_bytes: usize) -> U256 {
let pos = self.position; let pos = self.position;
@ -98,9 +92,9 @@ enum InstructionResult<Gas> {
/// Intepreter EVM implementation /// Intepreter EVM implementation
#[derive(Default)]
pub struct Interpreter<Cost: CostType> { pub struct Interpreter<Cost: CostType> {
mem: Vec<u8>, mem: Vec<u8>,
cache: Arc<SharedCache>,
_type: PhantomData<Cost>, _type: PhantomData<Cost>,
} }
@ -108,15 +102,14 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> { fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> {
self.mem.clear(); self.mem.clear();
let mut informant = informant::EvmInformant::new(ext.depth());
let code = &params.code.as_ref().unwrap(); let code = &params.code.as_ref().unwrap();
let valid_jump_destinations = self.find_jump_destinations(code); let valid_jump_destinations = self.cache.jump_destinations(&params.code_hash, code);
let mut gasometer = Gasometer::<Cost>::new(try!(Cost::from_u256(params.gas))); let mut gasometer = Gasometer::<Cost>::new(try!(Cost::from_u256(params.gas)));
let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero());
let mut reader = CodeReader { let mut reader = CodeReader::new(code);
position: 0,
code: code
};
let infos = &*instructions::INSTRUCTIONS; let infos = &*instructions::INSTRUCTIONS;
while reader.position < code.len() { while reader.position < code.len() {
@ -136,15 +129,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
gasometer.current_mem_gas = mem_gas; gasometer.current_mem_gas = mem_gas;
gasometer.current_gas = gasometer.current_gas - gas_cost; gasometer.current_gas = gasometer.current_gas - gas_cost;
evm_debug!({ evm_debug!({ informant.before_instruction(reader.position, instruction, &info, &gasometer.current_gas, &stack) });
println!("[0x{:x}][{}(0x{:x}) Gas: {:?}\n Gas Before: {:?}",
reader.position,
color(instruction, info.name),
instruction,
gas_cost,
gasometer.current_gas + gas_cost
);
});
let (mem_written, store_written) = match trace_executed { let (mem_written, store_written) = match trace_executed {
true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)), true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)),
@ -156,6 +141,8 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
gasometer.current_gas, &params, ext, instruction, &mut reader, &mut stack gasometer.current_gas, &params, ext, instruction, &mut reader, &mut stack
)); ));
evm_debug!({ informant.after_instruction(instruction) });
if trace_executed { if trace_executed {
ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written); ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written);
} }
@ -177,17 +164,26 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
reader.position = pos; reader.position = pos;
}, },
InstructionResult::StopExecutionNeedsReturn(gas, off, size) => { InstructionResult::StopExecutionNeedsReturn(gas, off, size) => {
informant.done();
return Ok(GasLeft::NeedsReturn(gas.as_u256(), self.mem.read_slice(off, size))); return Ok(GasLeft::NeedsReturn(gas.as_u256(), self.mem.read_slice(off, size)));
}, },
InstructionResult::StopExecution => break, InstructionResult::StopExecution => break,
} }
} }
informant.done();
Ok(GasLeft::Known(gasometer.current_gas.as_u256())) Ok(GasLeft::Known(gasometer.current_gas.as_u256()))
} }
} }
impl<Cost: CostType> Interpreter<Cost> { impl<Cost: CostType> Interpreter<Cost> {
/// Create a new `Interpreter` instance with shared cache.
pub fn new(cache: Arc<SharedCache>) -> Interpreter<Cost> {
Interpreter {
mem: Vec::new(),
cache: cache,
_type: PhantomData::default(),
}
}
fn verify_instruction(&self, ext: &evm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> evm::Result<()> { fn verify_instruction(&self, ext: &evm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> evm::Result<()> {
let schedule = ext.schedule(); let schedule = ext.schedule();
@ -486,10 +482,10 @@ impl<Cost: CostType> Interpreter<Cost> {
stack.push(U256::from(len)); stack.push(U256::from(len));
}, },
instructions::CALLDATACOPY => { instructions::CALLDATACOPY => {
self.copy_data_to_memory(stack, &params.data.clone().unwrap_or_else(|| vec![])); self.copy_data_to_memory(stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
}, },
instructions::CODECOPY => { instructions::CODECOPY => {
self.copy_data_to_memory(stack, &params.code.clone().unwrap_or_else(|| vec![])); self.copy_data_to_memory(stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8]));
}, },
instructions::EXTCODECOPY => { instructions::EXTCODECOPY => {
let address = u256_to_address(&stack.pop_back()); let address = u256_to_address(&stack.pop_back());
@ -790,23 +786,6 @@ impl<Cost: CostType> Interpreter<Cost> {
Ok(()) Ok(())
} }
fn find_jump_destinations(&self, code: &[u8]) -> BitSet {
let mut jump_dests = BitSet::with_capacity(code.len());
let mut position = 0;
while position < code.len() {
let instruction = code[position];
if instruction == instructions::JUMPDEST {
jump_dests.insert(position);
} else if instructions::is_push(instruction) {
position += instructions::get_push_bytes(instruction);
}
position += 1;
}
jump_dests
}
} }
fn get_and_reset_sign(value: U256) -> (U256, bool) { fn get_and_reset_sign(value: U256) -> (U256, bool) {
@ -833,15 +812,3 @@ fn address_to_u256(value: Address) -> U256 {
U256::from(&*H256::from(value)) U256::from(&*H256::from(value))
} }
#[test]
fn test_find_jump_destinations() {
// given
let interpreter = Interpreter::<U256>::default();
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b01600055".from_hex().unwrap();
// when
let valid_jump_destinations = interpreter.find_jump_destinations(&code);
// then
assert!(valid_jump_destinations.contains(66));
}

View File

@ -0,0 +1,84 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use lru_cache::LruCache;
use util::{H256, Mutex};
use util::sha3::*;
use bit_set::BitSet;
use super::super::instructions;
const CACHE_CODE_ITEMS: usize = 4096;
/// GLobal cache for EVM interpreter
pub struct SharedCache {
jump_destinations: Mutex<LruCache<H256, Arc<BitSet>>>
}
impl SharedCache {
/// Get jump destincations bitmap for a contract.
pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc<BitSet> {
if code_hash == &SHA3_EMPTY {
return Self::find_jump_destinations(code);
}
if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
return d.clone();
}
let d = Self::find_jump_destinations(code);
self.jump_destinations.lock().insert(code_hash.clone(), d.clone());
d
}
fn find_jump_destinations(code: &[u8]) -> Arc<BitSet> {
let mut jump_dests = BitSet::with_capacity(code.len());
let mut position = 0;
while position < code.len() {
let instruction = code[position];
if instruction == instructions::JUMPDEST {
jump_dests.insert(position);
} else if instructions::is_push(instruction) {
position += instructions::get_push_bytes(instruction);
}
position += 1;
}
Arc::new(jump_dests)
}
}
impl Default for SharedCache {
fn default() -> SharedCache {
SharedCache {
jump_destinations: Mutex::new(LruCache::new(CACHE_CODE_ITEMS)),
}
}
}
#[test]
fn test_find_jump_destinations() {
use util::FromHex;
// given
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b01600055".from_hex().unwrap();
// when
let valid_jump_destinations = SharedCache::find_jump_destinations(&code);
// then
assert!(valid_jump_destinations.contains(66));
}

View File

@ -34,7 +34,7 @@ pub trait Stack<T> {
/// Get number of elements on Stack /// Get number of elements on Stack
fn size(&self) -> usize; fn size(&self) -> usize;
/// Returns all data on stack. /// Returns all data on stack.
fn peek_top(&mut self, no_of_elems: usize) -> &[T]; fn peek_top(&self, no_of_elems: usize) -> &[T];
} }
pub struct VecStack<S> { pub struct VecStack<S> {
@ -68,12 +68,7 @@ impl<S : fmt::Display> Stack<S> for VecStack<S> {
fn pop_back(&mut self) -> S { fn pop_back(&mut self) -> S {
let val = self.stack.pop(); let val = self.stack.pop();
match val { match val {
Some(x) => { Some(x) => x,
evm_debug!({
println!(" POP: {}", x)
});
x
},
None => panic!("Tried to pop from empty stack.") None => panic!("Tried to pop from empty stack.")
} }
} }
@ -88,9 +83,6 @@ impl<S : fmt::Display> Stack<S> for VecStack<S> {
} }
fn push(&mut self, elem: S) { fn push(&mut self, elem: S) {
evm_debug!({
println!(" PUSH: {}", elem)
});
self.stack.push(elem); self.stack.push(elem);
} }
@ -98,7 +90,7 @@ impl<S : fmt::Display> Stack<S> for VecStack<S> {
self.stack.len() self.stack.len()
} }
fn peek_top(&mut self, no_from_top: usize) -> &[S] { fn peek_top(&self, no_from_top: usize) -> &[S] {
assert!(self.stack.len() >= no_from_top, "peek_top asked for more items than exist."); assert!(self.stack.len() >= no_from_top, "peek_top asked for more items than exist.");
&self.stack[self.stack.len() - no_from_top .. self.stack.len()] &self.stack[self.stack.len() - no_from_top .. self.stack.len()]
} }

View File

@ -49,7 +49,7 @@ pub struct FakeExt {
depth: usize, depth: usize,
store: HashMap<H256, H256>, store: HashMap<H256, H256>,
blockhashes: HashMap<U256, H256>, blockhashes: HashMap<U256, H256>,
codes: HashMap<Address, Bytes>, codes: HashMap<Address, Arc<Bytes>>,
logs: Vec<FakeLogEntry>, logs: Vec<FakeLogEntry>,
_suicides: HashSet<Address>, _suicides: HashSet<Address>,
info: EnvInfo, info: EnvInfo,
@ -136,8 +136,8 @@ impl Ext for FakeExt {
MessageCallResult::Success(*gas) MessageCallResult::Success(*gas)
} }
fn extcode(&self, address: &Address) -> Bytes { fn extcode(&self, address: &Address) -> Arc<Bytes> {
self.codes.get(address).unwrap_or(&Bytes::new()).clone() self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()
} }
fn extcodesize(&self, address: &Address) -> usize { fn extcodesize(&self, address: &Address) -> usize {
@ -184,11 +184,11 @@ fn test_stack_underflow() {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let err = { let err = {
let mut vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter::<usize>::default()); let mut vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter::<usize>::new(Arc::new(super::interpreter::SharedCache::default())));
test_finalize(vm.exec(params, &mut ext)).unwrap_err() test_finalize(vm.exec(params, &mut ext)).unwrap_err()
}; };
@ -211,7 +211,7 @@ fn test_add(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -231,7 +231,7 @@ fn test_sha3(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -251,7 +251,7 @@ fn test_address(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -273,7 +273,7 @@ fn test_origin(factory: super::Factory) {
params.address = address.clone(); params.address = address.clone();
params.origin = origin.clone(); params.origin = origin.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -295,7 +295,7 @@ fn test_sender(factory: super::Factory) {
params.address = address.clone(); params.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -329,9 +329,9 @@ fn test_extcodecopy(factory: super::Factory) {
params.address = address.clone(); params.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.codes.insert(sender, sender_code); ext.codes.insert(sender, Arc::new(sender_code));
let gas_left = { let gas_left = {
let mut vm = factory.create(params.gas); let mut vm = factory.create(params.gas);
@ -350,7 +350,7 @@ fn test_log_empty(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -382,7 +382,7 @@ fn test_log_sender(factory: super::Factory) {
params.address = address.clone(); params.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -406,7 +406,7 @@ fn test_blockhash(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.blockhashes.insert(U256::zero(), blockhash.clone()); ext.blockhashes.insert(U256::zero(), blockhash.clone());
@ -428,7 +428,7 @@ fn test_calldataload(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
params.data = Some(data); params.data = Some(data);
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
@ -449,7 +449,7 @@ fn test_author(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.info.author = author; ext.info.author = author;
@ -469,7 +469,7 @@ fn test_timestamp(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.info.timestamp = timestamp; ext.info.timestamp = timestamp;
@ -489,7 +489,7 @@ fn test_number(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.info.number = number; ext.info.number = number;
@ -509,7 +509,7 @@ fn test_difficulty(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.info.difficulty = difficulty; ext.info.difficulty = difficulty;
@ -529,7 +529,7 @@ fn test_gas_limit(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.info.gas_limit = gas_limit; ext.info.gas_limit = gas_limit;
@ -548,7 +548,7 @@ fn test_mul(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -566,7 +566,7 @@ fn test_sub(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -584,7 +584,7 @@ fn test_div(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -602,7 +602,7 @@ fn test_div_zero(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -620,7 +620,7 @@ fn test_mod(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -639,7 +639,7 @@ fn test_smod(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -658,7 +658,7 @@ fn test_sdiv(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -677,7 +677,7 @@ fn test_exp(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -697,7 +697,7 @@ fn test_comparison(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -718,7 +718,7 @@ fn test_signed_comparison(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -739,7 +739,7 @@ fn test_bitops(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(150_000); params.gas = U256::from(150_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -762,7 +762,7 @@ fn test_addmod_mulmod(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -783,7 +783,7 @@ fn test_byte(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -802,7 +802,7 @@ fn test_signextend(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -822,7 +822,7 @@ fn test_badinstruction_int() {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let err = { let err = {
@ -842,7 +842,7 @@ fn test_pop(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -862,7 +862,7 @@ fn test_extops(factory: super::Factory) {
params.gas = U256::from(150_000); params.gas = U256::from(150_000);
params.gas_price = U256::from(0x32); params.gas_price = U256::from(0x32);
params.value = ActionValue::Transfer(U256::from(0x99)); params.value = ActionValue::Transfer(U256::from(0x99));
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -885,7 +885,7 @@ fn test_jumps(factory: super::Factory) {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(150_000); params.gas = U256::from(150_000);
params.code = Some(code); params.code = Some(Arc::new(code));
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
let gas_left = { let gas_left = {
@ -908,7 +908,7 @@ fn test_calls(factory: super::Factory) {
let code_address = Address::from(0x998); let code_address = Address::from(0x998);
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.gas = U256::from(150_000); params.gas = U256::from(150_000);
params.code = Some(code); params.code = Some(Arc::new(code));
params.address = address.clone(); params.address = address.clone();
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
ext.balances = { ext.balances = {

View File

@ -168,13 +168,14 @@ impl<'a> Executive<'a> {
let new_address = contract_address(&sender, &nonce); let new_address = contract_address(&sender, &nonce);
let params = ActionParams { let params = ActionParams {
code_address: new_address.clone(), code_address: new_address.clone(),
code_hash: t.data.sha3(),
address: new_address, address: new_address,
sender: sender.clone(), sender: sender.clone(),
origin: sender.clone(), origin: sender.clone(),
gas: init_gas, gas: init_gas,
gas_price: t.gas_price, gas_price: t.gas_price,
value: ActionValue::Transfer(t.value), value: ActionValue::Transfer(t.value),
code: Some(t.data.clone()), code: Some(Arc::new(t.data.clone())),
data: None, data: None,
call_type: CallType::None, call_type: CallType::None,
}; };
@ -190,6 +191,7 @@ impl<'a> Executive<'a> {
gas_price: t.gas_price, gas_price: t.gas_price,
value: ActionValue::Transfer(t.value), value: ActionValue::Transfer(t.value),
code: self.state.code(address), code: self.state.code(address),
code_hash: self.state.code_hash(address),
data: Some(t.data.clone()), data: Some(t.data.clone()),
call_type: CallType::Call, call_type: CallType::Call,
}; };
@ -511,7 +513,7 @@ mod tests {
params.address = address.clone(); params.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some("3331600055".from_hex().unwrap()); params.code = Some(Arc::new("3331600055".from_hex().unwrap()));
params.value = ActionValue::Transfer(U256::from(0x7)); params.value = ActionValue::Transfer(U256::from(0x7));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
@ -570,7 +572,7 @@ mod tests {
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
@ -628,7 +630,7 @@ mod tests {
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
params.call_type = CallType::Call; params.call_type = CallType::Call;
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
@ -740,7 +742,7 @@ mod tests {
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(100.into()); params.value = ActionValue::Transfer(100.into());
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
@ -828,7 +830,7 @@ mod tests {
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
@ -880,7 +882,7 @@ mod tests {
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
@ -937,7 +939,7 @@ mod tests {
params.address = address_a.clone(); params.address = address_a.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code_a.clone()); params.code = Some(Arc::new(code_a.clone()));
params.value = ActionValue::Transfer(U256::from(100_000)); params.value = ActionValue::Transfer(U256::from(100_000));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
@ -987,10 +989,10 @@ mod tests {
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(Arc::new(code.clone()));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.init_code(&address, code.clone()); state.init_code(&address, code);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
@ -1188,7 +1190,7 @@ mod tests {
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(0x0186a0); params.gas = U256::from(0x0186a0);
params.code = Some(code.clone()); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap()); params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();

View File

@ -146,7 +146,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
gas: *gas, gas: *gas,
gas_price: self.origin_info.gas_price, gas_price: self.origin_info.gas_price,
value: ActionValue::Transfer(*value), value: ActionValue::Transfer(*value),
code: Some(code.to_vec()), code: Some(Arc::new(code.to_vec())),
code_hash: code.sha3(),
data: None, data: None,
call_type: CallType::None, call_type: CallType::None,
}; };
@ -185,6 +186,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
gas: *gas, gas: *gas,
gas_price: self.origin_info.gas_price, gas_price: self.origin_info.gas_price,
code: self.state.code(code_address), code: self.state.code(code_address),
code_hash: self.state.code_hash(code_address),
data: Some(data.to_vec()), data: Some(data.to_vec()),
call_type: call_type, call_type: call_type,
}; };
@ -201,8 +203,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
} }
} }
fn extcode(&self, address: &Address) -> Bytes { fn extcode(&self, address: &Address) -> Arc<Bytes> {
self.state.code(address).unwrap_or_else(|| vec![]) self.state.code(address).unwrap_or_else(|| Arc::new(vec![]))
} }
fn extcodesize(&self, address: &Address) -> usize { fn extcodesize(&self, address: &Address) -> usize {

View File

@ -127,7 +127,7 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
MessageCallResult::Success(*gas) MessageCallResult::Success(*gas)
} }
fn extcode(&self, address: &Address) -> Bytes { fn extcode(&self, address: &Address) -> Arc<Bytes> {
self.ext.extcode(address) self.ext.extcode(address)
} }
@ -232,7 +232,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
for (address, account) in vm.post_state.unwrap().into_iter() { for (address, account) in vm.post_state.unwrap().into_iter() {
let address = address.into(); let address = address.into();
let code: Vec<u8> = account.code.into(); let code: Vec<u8> = account.code.into();
fail_unless(state.code(&address).unwrap_or_else(Vec::new) == code, "code is incorrect"); fail_unless(state.code(&address).as_ref().map_or_else(|| code.is_empty(), |c| &**c == &code), "code is incorrect");
fail_unless(state.balance(&address) == account.balance.into(), "balance is incorrect"); fail_unless(state.balance(&address) == account.balance.into(), "balance is incorrect");
fail_unless(state.nonce(&address) == account.nonce.into(), "nonce is incorrect"); fail_unless(state.nonce(&address) == account.nonce.into(), "nonce is incorrect");
account.storage.into_iter().foreach(|(k, v)| { account.storage.into_iter().foreach(|(k, v)| {

View File

@ -99,6 +99,8 @@ extern crate ethcore_devtools as devtools;
extern crate rand; extern crate rand;
extern crate bit_set; extern crate bit_set;
extern crate rlp; extern crate rlp;
extern crate ethcore_bloom_journal as bloom_journal;
extern crate byteorder;
#[macro_use] #[macro_use]
extern crate log; extern crate log;

View File

@ -23,3 +23,6 @@ pub mod extras;
mod v9; mod v9;
pub use self::v9::ToV9; pub use self::v9::ToV9;
pub use self::v9::Extract; pub use self::v9::Extract;
mod v10;
pub use self::v10::ToV10;

View File

@ -24,6 +24,7 @@ use util::{Address, FixedHash, H256};
use util::kvdb::Database; use util::kvdb::Database;
use util::migration::{Batch, Config, Error, Migration, SimpleMigration, Progress}; use util::migration::{Batch, Config, Error, Migration, SimpleMigration, Progress};
use util::sha3::Hashable; use util::sha3::Hashable;
use std::sync::Arc;
use rlp::{decode, Rlp, RlpStream, Stream, View}; use rlp::{decode, Rlp, RlpStream, Stream, View};
@ -107,7 +108,7 @@ pub struct OverlayRecentV7 {
impl OverlayRecentV7 { impl OverlayRecentV7 {
// walk all journal entries in the database backwards. // walk all journal entries in the database backwards.
// find migrations for any possible inserted keys. // find migrations for any possible inserted keys.
fn walk_journal(&mut self, source: &Database) -> Result<(), Error> { fn walk_journal(&mut self, source: Arc<Database>) -> Result<(), Error> {
if let Some(val) = try!(source.get(None, V7_LATEST_ERA_KEY).map_err(Error::Custom)) { if let Some(val) = try!(source.get(None, V7_LATEST_ERA_KEY).map_err(Error::Custom)) {
let mut era = decode::<u64>(&val); let mut era = decode::<u64>(&val);
loop { loop {
@ -151,7 +152,7 @@ impl OverlayRecentV7 {
// walk all journal entries in the database backwards. // walk all journal entries in the database backwards.
// replace all possible inserted/deleted keys with their migrated counterparts // replace all possible inserted/deleted keys with their migrated counterparts
// and commit the altered entries. // and commit the altered entries.
fn migrate_journal(&self, source: &Database, mut batch: Batch, dest: &mut Database) -> Result<(), Error> { fn migrate_journal(&self, source: Arc<Database>, mut batch: Batch, dest: &mut Database) -> Result<(), Error> {
if let Some(val) = try!(source.get(None, V7_LATEST_ERA_KEY).map_err(Error::Custom)) { if let Some(val) = try!(source.get(None, V7_LATEST_ERA_KEY).map_err(Error::Custom)) {
try!(batch.insert(V7_LATEST_ERA_KEY.into(), val.to_owned(), dest)); try!(batch.insert(V7_LATEST_ERA_KEY.into(), val.to_owned(), dest));
@ -228,7 +229,7 @@ impl Migration for OverlayRecentV7 {
// walk all records in the database, attempting to migrate any possible and // walk all records in the database, attempting to migrate any possible and
// keeping records of those that we do. then migrate the journal using // keeping records of those that we do. then migrate the journal using
// this information. // this information.
fn migrate(&mut self, source: &Database, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> { fn migrate(&mut self, source: Arc<Database>, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> {
let mut batch = Batch::new(config, col); let mut batch = Batch::new(config, col);
// check version metadata. // check version metadata.
@ -257,7 +258,7 @@ impl Migration for OverlayRecentV7 {
try!(batch.insert(key, value.into_vec(), dest)); try!(batch.insert(key, value.into_vec(), dest));
} }
try!(self.walk_journal(source)); try!(self.walk_journal(source.clone()));
self.migrate_journal(source, batch, dest) self.migrate_journal(source, batch, dest)
} }
} }

View File

@ -0,0 +1,117 @@
// 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/>.
//! Bloom upgrade
use std::sync::Arc;
use db::{COL_EXTRA, COL_HEADERS, COL_STATE};
use state_db::{ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET, StateDB};
use util::trie::TrieDB;
use views::HeaderView;
use bloom_journal::Bloom;
use util::migration::{Error, Migration, Progress, Batch, Config};
use util::journaldb;
use util::{H256, FixedHash, Trie};
use util::{Database, DBTransaction};
/// Account bloom upgrade routine. If bloom already present, does nothing.
/// If database empty (no best block), does nothing.
/// Can be called on upgraded database with no issues (will do nothing).
pub fn generate_bloom(source: Arc<Database>, dest: &mut Database) -> Result<(), Error> {
trace!(target: "migration", "Account bloom upgrade started");
let best_block_hash = match try!(source.get(COL_EXTRA, b"best")) {
// no migration needed
None => {
trace!(target: "migration", "No best block hash, skipping");
return Ok(());
},
Some(hash) => hash,
};
let best_block_header = match try!(source.get(COL_HEADERS, &best_block_hash)) {
// no best block, nothing to do
None => {
trace!(target: "migration", "No best block header, skipping");
return Ok(())
},
Some(x) => x,
};
let state_root = HeaderView::new(&best_block_header).state_root();
trace!("Adding accounts bloom (one-time upgrade)");
let bloom_journal = {
let mut bloom = Bloom::new(ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET);
// no difference what algorithm is passed, since there will be no writes
let state_db = journaldb::new(
source.clone(),
journaldb::Algorithm::OverlayRecent,
COL_STATE);
let account_trie = try!(TrieDB::new(state_db.as_hashdb(), &state_root).map_err(|e| Error::Custom(format!("Cannot open trie: {:?}", e))));
for item in try!(account_trie.iter().map_err(|_| Error::MigrationImpossible)) {
let (ref account_key, _) = try!(item.map_err(|_| Error::MigrationImpossible));
let account_key_hash = H256::from_slice(&account_key);
bloom.set(&*account_key_hash);
}
bloom.drain_journal()
};
trace!(target: "migration", "Generated {} bloom updates", bloom_journal.entries.len());
let mut batch = DBTransaction::new(dest);
try!(StateDB::commit_bloom(&mut batch, bloom_journal).map_err(|_| Error::Custom("Failed to commit bloom".to_owned())));
try!(dest.write(batch));
trace!(target: "migration", "Finished bloom update");
Ok(())
}
/// Account bloom migration.
#[derive(Default)]
pub struct ToV10 {
progress: Progress,
}
impl ToV10 {
/// New v10 migration
pub fn new() -> ToV10 { ToV10 { progress: Progress::default() } }
}
impl Migration for ToV10 {
fn version(&self) -> u32 {
10
}
fn pre_columns(&self) -> Option<u32> { Some(5) }
fn columns(&self) -> Option<u32> { Some(6) }
fn migrate(&mut self, source: Arc<Database>, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> {
let mut batch = Batch::new(config, col);
for (key, value) in source.iter(col) {
self.progress.tick();
try!(batch.insert(key.to_vec(), value.to_vec(), dest));
}
try!(batch.commit(dest));
if col == COL_STATE {
try!(generate_bloom(source, dest));
}
Ok(())
}
}

View File

@ -20,6 +20,7 @@
use rlp::{Rlp, RlpStream, View, Stream}; use rlp::{Rlp, RlpStream, View, Stream};
use util::kvdb::Database; use util::kvdb::Database;
use util::migration::{Batch, Config, Error, Migration, Progress}; use util::migration::{Batch, Config, Error, Migration, Progress};
use std::sync::Arc;
/// Which part of block to preserve /// Which part of block to preserve
pub enum Extract { pub enum Extract {
@ -55,7 +56,7 @@ impl Migration for ToV9 {
fn version(&self) -> u32 { 9 } fn version(&self) -> u32 { 9 }
fn migrate(&mut self, source: &Database, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> { fn migrate(&mut self, source: Arc<Database>, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> {
let mut batch = Batch::new(config, self.column); let mut batch = Batch::new(config, self.column);
for (key, value) in source.iter(col) { for (key, value) in source.iter(col) {

View File

@ -587,7 +587,7 @@ impl MinerService for Miner {
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> { fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
let sealing_work = self.sealing_work.lock(); let sealing_work = self.sealing_work.lock();
sealing_work.queue.peek_last_ref().map_or_else(|| chain.latest_code(address), |b| b.block().fields().state.code(address)) sealing_work.queue.peek_last_ref().map_or_else(|| chain.latest_code(address), |b| b.block().fields().state.code(address).map(|c| (*c).clone()))
} }
fn set_author(&self, author: Address) { fn set_author(&self, author: Address) {

View File

@ -43,6 +43,8 @@ use self::account::Account;
use self::block::AbridgedBlock; use self::block::AbridgedBlock;
use self::io::SnapshotWriter; use self::io::SnapshotWriter;
use super::state_db::StateDB;
use crossbeam::{scope, ScopedJoinHandle}; use crossbeam::{scope, ScopedJoinHandle};
use rand::{Rng, OsRng}; use rand::{Rng, OsRng};
@ -454,6 +456,10 @@ impl StateRebuilder {
self.code_map.insert(code_hash, code); self.code_map.insert(code_hash, code);
} }
let backing = self.db.backing().clone();
// bloom has to be updated
let mut bloom = StateDB::load_bloom(&backing);
// batch trie writes // batch trie writes
{ {
@ -464,12 +470,14 @@ impl StateRebuilder {
}; };
for (hash, thin_rlp) in pairs { for (hash, thin_rlp) in pairs {
bloom.set(&*hash);
try!(account_trie.insert(&hash, &thin_rlp)); try!(account_trie.insert(&hash, &thin_rlp));
} }
} }
let backing = self.db.backing().clone(); let bloom_journal = bloom.drain_journal();
let mut batch = backing.transaction(); let mut batch = backing.transaction();
try!(StateDB::commit_bloom(&mut batch, bloom_journal));
try!(self.db.inject(&mut batch)); try!(self.db.inject(&mut batch));
try!(backing.write(batch).map_err(::util::UtilError::SimpleString)); try!(backing.write(batch).map_err(::util::UtilError::SimpleString));
trace!(target: "snapshot", "current state root: {:?}", self.state_root); trace!(target: "snapshot", "current state root: {:?}", self.state_root);

View File

@ -22,7 +22,6 @@ use ipc::IpcConfig;
/// This handles: /// This handles:
/// - restoration of snapshots to temporary databases. /// - restoration of snapshots to temporary databases.
/// - responding to queries for snapshot manifests and chunks /// - responding to queries for snapshot manifests and chunks
#[derive(Ipc)]
#[ipc(client_ident="RemoteSnapshotService")] #[ipc(client_ident="RemoteSnapshotService")]
pub trait SnapshotService : Sync + Send { pub trait SnapshotService : Sync + Send {
/// Query the most recent manifest data. /// Query the most recent manifest data.

View File

@ -248,6 +248,7 @@ impl Spec {
} }
trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root); trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root);
for (address, account) in self.genesis_state.get().iter() { for (address, account) in self.genesis_state.get().iter() {
db.note_account_bloom(address);
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address)); account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address));
} }
assert!(db.as_hashdb().contains(&self.state_root())); assert!(db.as_hashdb().contains(&self.state_root()));

View File

@ -40,14 +40,16 @@ pub struct Account {
// Modified storage. Accumulates changes to storage made in `set_storage` // Modified storage. Accumulates changes to storage made in `set_storage`
// Takes precedence over `storage_cache`. // Takes precedence over `storage_cache`.
storage_changes: HashMap<H256, H256>, storage_changes: HashMap<H256, H256>,
// Code hash of the account. If None, means that it's a contract whose code has not yet been set. // Code hash of the account.
code_hash: Option<H256>, code_hash: H256,
// Size of the accoun code. // Size of the accoun code.
code_size: Option<usize>, code_size: Option<usize>,
// Code cache of the account. // Code cache of the account.
code_cache: Bytes, code_cache: Arc<Bytes>,
// Account is new or has been modified // Account is new or has been modified.
filth: Filth, filth: Filth,
// Account code new or has been modified.
code_filth: Filth,
// Cached address hash. // Cached address hash.
address_hash: Cell<Option<H256>>, address_hash: Cell<Option<H256>>,
} }
@ -62,10 +64,11 @@ impl Account {
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_cache: Self::empty_storage_cache(),
storage_changes: storage, storage_changes: storage,
code_hash: Some(code.sha3()), code_hash: code.sha3(),
code_size: Some(code.len()), code_size: Some(code.len()),
code_cache: code, code_cache: Arc::new(code),
filth: Filth::Dirty, filth: Filth::Dirty,
code_filth: Filth::Dirty,
address_hash: Cell::new(None), address_hash: Cell::new(None),
} }
} }
@ -82,9 +85,10 @@ impl Account {
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_cache: Self::empty_storage_cache(),
storage_changes: pod.storage.into_iter().collect(), storage_changes: pod.storage.into_iter().collect(),
code_hash: pod.code.as_ref().map(|c| c.sha3()), code_hash: pod.code.as_ref().map_or(SHA3_EMPTY, |c| c.sha3()),
code_filth: Filth::Dirty,
code_size: Some(pod.code.as_ref().map_or(0, |c| c.len())), code_size: Some(pod.code.as_ref().map_or(0, |c| c.len())),
code_cache: pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c), code_cache: Arc::new(pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c)),
filth: Filth::Dirty, filth: Filth::Dirty,
address_hash: Cell::new(None), address_hash: Cell::new(None),
} }
@ -98,10 +102,11 @@ impl Account {
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(), storage_changes: HashMap::new(),
code_hash: Some(SHA3_EMPTY), code_hash: SHA3_EMPTY,
code_cache: vec![], code_cache: Arc::new(vec![]),
code_size: Some(0), code_size: Some(0),
filth: Filth::Dirty, filth: Filth::Dirty,
code_filth: Filth::Clean,
address_hash: Cell::new(None), address_hash: Cell::new(None),
} }
} }
@ -115,10 +120,11 @@ impl Account {
storage_root: r.val_at(2), storage_root: r.val_at(2),
storage_cache: Self::empty_storage_cache(), storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(), storage_changes: HashMap::new(),
code_hash: Some(r.val_at(3)), code_hash: r.val_at(3),
code_cache: vec![], code_cache: Arc::new(vec![]),
code_size: None, code_size: None,
filth: Filth::Clean, filth: Filth::Clean,
code_filth: Filth::Clean,
address_hash: Cell::new(None), address_hash: Cell::new(None),
} }
} }
@ -132,10 +138,11 @@ impl Account {
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(), storage_changes: HashMap::new(),
code_hash: None, code_hash: SHA3_EMPTY,
code_cache: vec![], code_cache: Arc::new(vec![]),
code_size: None, code_size: None,
filth: Filth::Dirty, filth: Filth::Dirty,
code_filth: Filth::Clean,
address_hash: Cell::new(None), address_hash: Cell::new(None),
} }
} }
@ -143,16 +150,15 @@ impl Account {
/// Set this account's code to the given code. /// Set this account's code to the given code.
/// NOTE: Account should have been created with `new_contract()` /// NOTE: Account should have been created with `new_contract()`
pub fn init_code(&mut self, code: Bytes) { pub fn init_code(&mut self, code: Bytes) {
assert!(self.code_hash.is_none()); self.code_hash = code.sha3();
self.code_cache = code; self.code_cache = Arc::new(code);
self.code_size = Some(self.code_cache.len()); self.code_size = Some(self.code_cache.len());
self.filth = Filth::Dirty; self.filth = Filth::Dirty;
self.code_filth = Filth::Dirty;
} }
/// Reset this account's code to the given code. /// Reset this account's code to the given code.
pub fn reset_code(&mut self, code: Bytes) { pub fn reset_code(&mut self, code: Bytes) {
self.code_hash = None;
self.code_size = Some(0);
self.init_code(code); self.init_code(code);
} }
@ -209,10 +215,9 @@ impl Account {
/// return the nonce associated with this account. /// return the nonce associated with this account.
pub fn nonce(&self) -> &U256 { &self.nonce } pub fn nonce(&self) -> &U256 { &self.nonce }
#[cfg(test)]
/// return the code hash associated with this account. /// return the code hash associated with this account.
pub fn code_hash(&self) -> H256 { pub fn code_hash(&self) -> H256 {
self.code_hash.clone().unwrap_or(SHA3_EMPTY) self.code_hash.clone()
} }
/// return the code hash associated with this account. /// return the code hash associated with this account.
@ -227,13 +232,11 @@ impl Account {
/// returns the account's code. If `None` then the code cache isn't available - /// returns the account's code. If `None` then the code cache isn't available -
/// get someone who knows to call `note_code`. /// get someone who knows to call `note_code`.
pub fn code(&self) -> Option<&[u8]> { pub fn code(&self) -> Option<Arc<Bytes>> {
match self.code_hash { if self.code_hash != SHA3_EMPTY && self.code_cache.is_empty() {
Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache), return None;
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
None => Some(&self.code_cache),
_ => None,
} }
Some(self.code_cache.clone())
} }
/// returns the account's code size. If `None` then the code cache or code size cache isn't available - /// returns the account's code size. If `None` then the code cache or code size cache isn't available -
@ -246,24 +249,23 @@ impl Account {
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result. /// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> { pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
let h = code.sha3(); let h = code.sha3();
match self.code_hash { if self.code_hash == h {
Some(ref i) if h == *i => { self.code_cache = Arc::new(code);
self.code_cache = code; self.code_size = Some(self.code_cache.len());
self.code_size = Some(self.code_cache.len()); Ok(())
Ok(()) } else {
}, Err(h)
_ => Err(h)
} }
} }
/// Is `code_cache` valid; such that code is going to return Some? /// Is `code_cache` valid; such that code is going to return Some?
pub fn is_cached(&self) -> bool { pub fn is_cached(&self) -> bool {
!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 == SHA3_EMPTY)
} }
/// Is this a new or modified account? /// Is this a new or modified account?
pub fn is_dirty(&self) -> bool { pub fn is_dirty(&self) -> bool {
self.filth == Filth::Dirty || !self.storage_is_clean() self.filth == Filth::Dirty || self.code_filth == Filth::Dirty || !self.storage_is_clean()
} }
/// Mark account as clean. /// Mark account as clean.
@ -277,20 +279,17 @@ impl Account {
// 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 db.get(&self.code_hash) {
Some(ref h) => match db.get(h) { Some(x) => {
Some(x) => { self.code_cache = Arc::new(x.to_vec());
self.code_cache = x.to_vec(); self.code_size = Some(x.len());
self.code_size = Some(x.len()); true
true },
}, _ => {
_ => { warn!("Failed reverse get of {}", self.code_hash);
warn!("Failed reverse get of {}", h); false
false },
}, }
},
_ => false,
}
} }
/// Provide a database to get `code_size`. Should not be called if it is a contract without code. /// Provide a database to get `code_size`. Should not be called if it is a contract without code.
@ -298,18 +297,19 @@ impl Account {
// TODO: fill out self.code_cache; // TODO: fill out self.code_cache;
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.code_size.is_some() || self.code_size.is_some() ||
match self.code_hash { if self.code_hash != SHA3_EMPTY {
Some(ref h) if h != &SHA3_EMPTY => match db.get(h) { match db.get(&self.code_hash) {
Some(x) => { Some(x) => {
self.code_size = Some(x.len()); self.code_size = Some(x.len());
true true
}, },
_ => { _ => {
warn!("Failed reverse get of {}", h); warn!("Failed reverse get of {}", self.code_hash);
false false
}, },
}, }
_ => false, } else {
false
} }
} }
@ -370,15 +370,16 @@ impl Account {
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this. /// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
pub fn commit_code(&mut self, db: &mut HashDB) { pub fn commit_code(&mut self, db: &mut HashDB) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty()); trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty());
match (self.code_hash.is_none(), self.code_cache.is_empty()) { match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) {
(true, true) => { (true, true) => {
self.code_hash = Some(SHA3_EMPTY);
self.code_size = Some(0); self.code_size = Some(0);
self.code_filth = Filth::Clean;
}, },
(true, false) => { (true, false) => {
self.code_hash = Some(db.insert(&self.code_cache)); db.emplace(self.code_hash.clone(), (*self.code_cache).clone());
self.code_size = Some(self.code_cache.len()); self.code_size = Some(self.code_cache.len());
self.code_filth = Filth::Clean;
}, },
(false, _) => {}, (false, _) => {},
} }
@ -390,7 +391,7 @@ impl Account {
stream.append(&self.nonce); stream.append(&self.nonce);
stream.append(&self.balance); stream.append(&self.balance);
stream.append(&self.storage_root); stream.append(&self.storage_root);
stream.append(self.code_hash.as_ref().unwrap_or(&SHA3_EMPTY)); stream.append(&self.code_hash);
stream.out() stream.out()
} }
@ -404,8 +405,9 @@ impl Account {
storage_changes: HashMap::new(), storage_changes: HashMap::new(),
code_hash: self.code_hash.clone(), code_hash: self.code_hash.clone(),
code_size: self.code_size.clone(), code_size: self.code_size.clone(),
code_cache: Bytes::new(), code_cache: self.code_cache.clone(),
filth: self.filth, filth: self.filth,
code_filth: self.code_filth,
address_hash: self.address_hash.clone(), address_hash: self.address_hash.clone(),
} }
} }
@ -433,6 +435,7 @@ impl Account {
self.nonce = other.nonce; self.nonce = other.nonce;
self.storage_root = other.storage_root; self.storage_root = other.storage_root;
self.code_hash = other.code_hash; self.code_hash = other.code_hash;
self.code_filth = other.code_filth;
self.code_cache = other.code_cache; self.code_cache = other.code_cache;
self.code_size = other.code_size; self.code_size = other.code_size;
self.address_hash = other.address_hash; self.address_hash = other.address_hash;
@ -536,7 +539,7 @@ mod tests {
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]); a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_hash(), SHA3_EMPTY); assert_eq!(a.code_filth, Filth::Dirty);
assert_eq!(a.code_size(), Some(3)); assert_eq!(a.code_size(), Some(3));
a.commit_code(&mut db); a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"); assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
@ -548,11 +551,12 @@ mod tests {
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]); a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_hash(), SHA3_EMPTY); assert_eq!(a.code_filth, Filth::Dirty);
a.commit_code(&mut db); a.commit_code(&mut db);
assert_eq!(a.code_filth, Filth::Clean);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"); assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
a.reset_code(vec![0x55]); a.reset_code(vec![0x55]);
assert_eq!(a.code_hash(), SHA3_EMPTY); assert_eq!(a.code_filth, Filth::Dirty);
a.commit_code(&mut db); a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be"); assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be");
} }

View File

@ -300,7 +300,10 @@ impl State {
} }
} }
} }
// check bloom before any requests to trie
if !self.db.check_account_bloom(address) { return H256::zero() }
// account is not found in the global cache, get from the DB and insert into local // account is not found in the global cache, get from the DB and insert into local
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let maybe_acc = match db.get(address) { let maybe_acc = match db.get(address) {
@ -319,9 +322,14 @@ impl State {
} }
/// Get accounts' code. /// Get accounts' code.
pub fn code(&self, a: &Address) -> Option<Bytes> { pub fn code(&self, a: &Address) -> Option<Arc<Bytes>> {
self.ensure_cached(a, RequireCache::Code, self.ensure_cached(a, RequireCache::Code,
|a| a.as_ref().map_or(None, |a| a.code().map(|x|x.to_vec()))) |a| a.as_ref().map_or(None, |a| a.code().clone()))
}
pub fn code_hash(&self, a: &Address) -> H256 {
self.ensure_cached(a, RequireCache::None,
|a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash()))
} }
/// Get accounts' code size. /// Get accounts' code size.
@ -400,6 +408,7 @@ impl State {
for (address, ref mut a) in accounts.iter_mut() { for (address, ref mut a) in accounts.iter_mut() {
match a { match a {
&mut&mut AccountEntry::Cached(ref mut account) if account.is_dirty() => { &mut&mut AccountEntry::Cached(ref mut account) if account.is_dirty() => {
db.note_account_bloom(&address);
let addr_hash = account.address_hash(address); let addr_hash = account.address_hash(address);
let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash); let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash);
account.commit_storage(&factories.trie, account_db.as_hashdb_mut()); account.commit_storage(&factories.trie, account_db.as_hashdb_mut());
@ -463,6 +472,7 @@ impl State {
pub fn populate_from(&mut self, accounts: PodState) { pub fn populate_from(&mut self, accounts: PodState) {
assert!(self.snapshots.borrow().is_empty()); assert!(self.snapshots.borrow().is_empty());
for (add, acc) in accounts.drain().into_iter() { for (add, acc) in accounts.drain().into_iter() {
self.db.note_account_bloom(&add);
self.cache.borrow_mut().insert(add, AccountEntry::Cached(Account::from_pod(acc))); self.cache.borrow_mut().insert(add, AccountEntry::Cached(Account::from_pod(acc)));
} }
} }
@ -538,6 +548,9 @@ impl State {
match result { match result {
Some(r) => r, Some(r) => r,
None => { None => {
// first check bloom if it is not in database for sure
if !self.db.check_account_bloom(a) { return f(None); }
// not found in the global cache, get from the DB and insert into local // not found in the global cache, get from the DB and insert into local
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let mut maybe_acc = match db.get(a) { let mut maybe_acc = match db.get(a) {
@ -574,11 +587,17 @@ impl State {
Some(Some(acc)) => self.insert_cache(a, AccountEntry::Cached(acc)), Some(Some(acc)) => self.insert_cache(a, AccountEntry::Cached(acc)),
Some(None) => self.insert_cache(a, AccountEntry::Missing), Some(None) => self.insert_cache(a, AccountEntry::Missing),
None => { None => {
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let maybe_acc = if self.db.check_account_bloom(a) {
let maybe_acc = match db.get(a) { let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
Ok(Some(acc)) => AccountEntry::Cached(Account::from_rlp(acc)), let maybe_acc = match db.get(a) {
Ok(None) => AccountEntry::Missing, Ok(Some(acc)) => AccountEntry::Cached(Account::from_rlp(acc)),
Err(e) => panic!("Potential DB corruption encountered: {}", e), Ok(None) => AccountEntry::Missing,
Err(e) => panic!("Potential DB corruption encountered: {}", e),
};
maybe_acc
}
else {
AccountEntry::Missing
}; };
self.insert_cache(a, maybe_acc); self.insert_cache(a, maybe_acc);
} }
@ -640,6 +659,7 @@ impl Clone for State {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::sync::Arc;
use std::str::FromStr; use std::str::FromStr;
use rustc_serialize::hex::FromHex; use rustc_serialize::hex::FromHex;
use super::*; use super::*;
@ -1504,14 +1524,14 @@ fn code_from_database() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}); state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{});
state.init_code(&a, vec![1, 2, 3]); state.init_code(&a, vec![1, 2, 3]);
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
state.commit().unwrap(); state.commit().unwrap();
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
state.drop() state.drop()
}; };
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
} }
#[test] #[test]

View File

@ -18,11 +18,19 @@ use lru_cache::LruCache;
use util::journaldb::JournalDB; use util::journaldb::JournalDB;
use util::hash::{H256}; use util::hash::{H256};
use util::hashdb::HashDB; use util::hashdb::HashDB;
use util::{Arc, Address, DBTransaction, UtilError, Mutex};
use state::Account; use state::Account;
use util::{Arc, Address, Database, DBTransaction, UtilError, Mutex, Hashable};
use bloom_journal::{Bloom, BloomJournal};
use db::COL_ACCOUNT_BLOOM;
use byteorder::{LittleEndian, ByteOrder};
const STATE_CACHE_ITEMS: usize = 65536; const STATE_CACHE_ITEMS: usize = 65536;
pub const ACCOUNT_BLOOM_SPACE: usize = 1048576;
pub const DEFAULT_ACCOUNT_PRESET: usize = 1000000;
pub const ACCOUNT_BLOOM_HASHCOUNT_KEY: &'static [u8] = b"account_hash_count";
struct AccountCache { struct AccountCache {
/// DB Account cache. `None` indicates that account is known to be missing. /// DB Account cache. `None` indicates that account is known to be missing.
accounts: LruCache<Address, Option<Account>>, accounts: LruCache<Address, Option<Account>>,
@ -39,22 +47,83 @@ pub struct StateDB {
account_cache: Arc<Mutex<AccountCache>>, account_cache: Arc<Mutex<AccountCache>>,
cache_overlay: Vec<(Address, Option<Account>)>, cache_overlay: Vec<(Address, Option<Account>)>,
is_canon: bool, is_canon: bool,
account_bloom: Arc<Mutex<Bloom>>,
} }
impl StateDB { impl StateDB {
/// Create a new instance wrapping `JournalDB` /// Create a new instance wrapping `JournalDB`
pub fn new(db: Box<JournalDB>) -> StateDB { pub fn new(db: Box<JournalDB>) -> StateDB {
let bloom = Self::load_bloom(db.backing());
StateDB { StateDB {
db: db, db: db,
account_cache: Arc::new(Mutex::new(AccountCache { accounts: LruCache::new(STATE_CACHE_ITEMS) })), account_cache: Arc::new(Mutex::new(AccountCache { accounts: LruCache::new(STATE_CACHE_ITEMS) })),
cache_overlay: Vec::new(), cache_overlay: Vec::new(),
is_canon: false, is_canon: false,
account_bloom: Arc::new(Mutex::new(bloom)),
} }
} }
/// Loads accounts bloom from the database
/// This bloom is used to handle request for the non-existant account fast
pub fn load_bloom(db: &Database) -> Bloom {
let hash_count_entry = db.get(COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY)
.expect("Low-level database error");
if hash_count_entry.is_none() {
return Bloom::new(ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET);
}
let hash_count_bytes = hash_count_entry.unwrap();
assert_eq!(hash_count_bytes.len(), 1);
let hash_count = hash_count_bytes[0];
let mut bloom_parts = vec![0u64; ACCOUNT_BLOOM_SPACE / 8];
let mut key = [0u8; 8];
for i in 0..ACCOUNT_BLOOM_SPACE / 8 {
LittleEndian::write_u64(&mut key, i as u64);
bloom_parts[i] = db.get(COL_ACCOUNT_BLOOM, &key).expect("low-level database error")
.and_then(|val| Some(LittleEndian::read_u64(&val[..])))
.unwrap_or(0u64);
}
let bloom = Bloom::from_parts(&bloom_parts, hash_count as u32);
trace!(target: "account_bloom", "Bloom is {:?} full, hash functions count = {:?}", bloom.saturation(), hash_count);
bloom
}
pub fn check_account_bloom(&self, address: &Address) -> bool {
trace!(target: "account_bloom", "Check account bloom: {:?}", address);
let bloom = self.account_bloom.lock();
bloom.check(&*address.sha3())
}
pub fn note_account_bloom(&self, address: &Address) {
trace!(target: "account_bloom", "Note account bloom: {:?}", address);
let mut bloom = self.account_bloom.lock();
bloom.set(&*address.sha3());
}
pub fn commit_bloom(batch: &mut DBTransaction, journal: BloomJournal) -> Result<(), UtilError> {
assert!(journal.hash_functions <= 255);
batch.put(COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY, &vec![journal.hash_functions as u8]);
let mut key = [0u8; 8];
let mut val = [0u8; 8];
for (bloom_part_index, bloom_part_value) in journal.entries {
LittleEndian::write_u64(&mut key, bloom_part_index as u64);
LittleEndian::write_u64(&mut val, bloom_part_value);
batch.put(COL_ACCOUNT_BLOOM, &key, &val);
}
Ok(())
}
/// Commit all recent insert operations and canonical historical commits' removals from the /// Commit all recent insert operations and canonical historical commits' removals from the
/// old era to the backing database, reverting any non-canonical historical commit's inserts. /// old era to the backing database, reverting any non-canonical historical commit's inserts.
pub fn commit(&mut self, batch: &mut DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result<u32, UtilError> { pub fn commit(&mut self, batch: &mut DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result<u32, UtilError> {
{
let mut bloom_lock = self.account_bloom.lock();
try!(Self::commit_bloom(batch, bloom_lock.drain_journal()));
}
let records = try!(self.db.commit(batch, now, id, end)); let records = try!(self.db.commit(batch, now, id, end));
if self.is_canon { if self.is_canon {
self.commit_cache(); self.commit_cache();
@ -81,6 +150,7 @@ impl StateDB {
account_cache: self.account_cache.clone(), account_cache: self.account_cache.clone(),
cache_overlay: Vec::new(), cache_overlay: Vec::new(),
is_canon: false, is_canon: false,
account_bloom: self.account_bloom.clone(),
} }
} }
@ -91,6 +161,7 @@ impl StateDB {
account_cache: self.account_cache.clone(), account_cache: self.account_cache.clone(),
cache_overlay: Vec::new(), cache_overlay: Vec::new(),
is_canon: true, is_canon: true,
account_bloom: self.account_bloom.clone(),
} }
} }

View File

@ -57,7 +57,7 @@ fn should_return_registrar() {
IoChannel::disconnected(), IoChannel::disconnected(),
&db_config &db_config
).unwrap(); ).unwrap();
assert_eq!(client.additional_params().get("registrar"), Some(&"8e4e9b13d4b45cb0befc93c3061b1408f67316b2".to_owned())); assert_eq!(client.additional_params().get("registrar"), Some(&"52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d".to_owned()));
} }
#[test] #[test]

View File

@ -29,6 +29,7 @@ use ethereum;
use devtools::*; use devtools::*;
use miner::Miner; use miner::Miner;
use rlp::{self, RlpStream, Stream}; use rlp::{self, RlpStream, Stream};
use db::COL_STATE;
#[cfg(feature = "json-tests")] #[cfg(feature = "json-tests")]
pub enum ChainEra { pub enum ChainEra {
@ -344,7 +345,7 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
pub fn get_temp_state_db_in(path: &Path) -> StateDB { pub fn get_temp_state_db_in(path: &Path) -> StateDB {
let db = new_db(path.to_str().expect("Only valid utf8 paths for tests.")); let db = new_db(path.to_str().expect("Only valid utf8 paths for tests."));
let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, None); let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, COL_STATE);
StateDB::new(journal_db) StateDB::new(journal_db)
} }

View File

@ -181,7 +181,7 @@ impl From<ActionParams> for Create {
from: p.sender, from: p.sender,
value: p.value.value(), value: p.value.value(),
gas: p.gas, gas: p.gas,
init: p.code.unwrap_or_else(Vec::new), init: p.code.map_or_else(Vec::new, |c| (*c).clone()),
} }
} }
} }

View File

@ -164,6 +164,7 @@ pub mod headers {
} }
/// A mode for verifying headers. /// A mode for verifying headers.
#[allow(dead_code)]
pub struct Headers; pub struct Headers;
impl Kind for Headers { impl Kind for Headers {
@ -179,4 +180,4 @@ pub mod headers {
engine.verify_block_unordered(&unverified, None).map(|_| unverified) engine.verify_block_unordered(&unverified, None).map(|_| unverified)
} }
} }
} }

View File

@ -123,7 +123,6 @@ impl Args {
} }
} }
fn die(msg: &'static str) -> ! { fn die(msg: &'static str) -> ! {
println!("{}", msg); println!("{}", msg);
::std::process::exit(-1) ::std::process::exit(-1)

View File

@ -49,7 +49,7 @@ pub fn expand_ipc_implementation(
let item = match *annotatable { let item = match *annotatable {
Annotatable::Item(ref item) => item, Annotatable::Item(ref item) => item,
_ => { _ => {
cx.span_err(meta_item.span, "`#[derive(Ipc)]` may only be applied to struct implementations"); cx.span_err(meta_item.span, "`#[ipc]` may only be applied to implementations and traits");
return; return;
}, },
}; };
@ -832,7 +832,7 @@ fn implement_interface(
_ => { _ => {
cx.span_err( cx.span_err(
item.span, item.span,
"`#[derive(Ipc)]` may only be applied to implementations and traits"); "`#[ipc]` may only be applied to implementations and traits");
return Err(Error); return Err(Error);
}, },
}; };

View File

@ -83,7 +83,7 @@ pub fn register(reg: &mut syntex::Registry) {
reg.add_attr("feature(custom_derive)"); reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)"); reg.add_attr("feature(custom_attribute)");
reg.add_decorator("derive_Ipc", codegen::expand_ipc_implementation); reg.add_decorator("ipc", codegen::expand_ipc_implementation);
reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation); reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation);
reg.add_post_expansion_pass(strip_attributes); reg.add_post_expansion_pass(strip_attributes);
@ -92,7 +92,7 @@ pub fn register(reg: &mut syntex::Registry) {
#[cfg(not(feature = "with-syntex"))] #[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) { pub fn register(reg: &mut rustc_plugin::Registry) {
reg.register_syntax_extension( reg.register_syntax_extension(
syntax::parse::token::intern("derive_Ipc"), syntax::parse::token::intern("ipc"),
syntax::ext::base::MultiDecorator( syntax::ext::base::MultiDecorator(
Box::new(codegen::expand_ipc_implementation))); Box::new(codegen::expand_ipc_implementation)));
reg.register_syntax_extension( reg.register_syntax_extension(

View File

@ -40,12 +40,12 @@ pub struct ModuleState {
} }
#[derive(Ipc)] #[ipc]
pub trait ControlService { pub trait ControlService {
fn shutdown(&self) -> bool; fn shutdown(&self) -> bool;
} }
#[derive(Ipc)] #[ipc]
impl HypervisorService { impl HypervisorService {
// return type for making method synchronous // return type for making method synchronous
fn module_ready(&self, module_id: u64, control_url: String) -> bool { fn module_ready(&self, module_id: u64, control_url: String) -> bool {

View File

@ -33,7 +33,7 @@ impl IpcConfig for DBWriter {}
#[derive(Binary)] #[derive(Binary)]
pub enum DBError { Write, Read } pub enum DBError { Write, Read }
#[derive(Ipc)] #[ipc]
impl<L: Sized> DBWriter for DB<L> { impl<L: Sized> DBWriter for DB<L> {
fn write(&self, data: Vec<u8>) -> Result<(), DBError> { fn write(&self, data: Vec<u8>) -> Result<(), DBError> {
let mut writes = self.writes.write().unwrap(); let mut writes = self.writes.write().unwrap();
@ -48,7 +48,7 @@ impl<L: Sized> DBWriter for DB<L> {
} }
} }
#[derive(Ipc)] #[ipc]
trait DBNotify { trait DBNotify {
fn notify(&self, a: u64, b: u64) -> bool; fn notify(&self, a: u64, b: u64) -> bool;
} }

View File

@ -28,7 +28,7 @@ pub struct CustomData {
pub b: u64, pub b: u64,
} }
#[derive(Ipc)] #[ipc]
impl Service { impl Service {
fn commit(&self, f: u32) -> u32 { fn commit(&self, f: u32) -> u32 {
let mut lock = self.commits.write().unwrap(); let mut lock = self.commits.write().unwrap();

View File

@ -18,7 +18,6 @@ use ipc::IpcConfig;
pub struct BadlyNamedService; pub struct BadlyNamedService;
#[derive(Ipc)]
#[ipc(client_ident="PrettyNamedClient")] #[ipc(client_ident="PrettyNamedClient")]
impl BadlyNamedService { impl BadlyNamedService {
fn is_zero(&self, x: u64) -> bool { fn is_zero(&self, x: u64) -> bool {

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use ethcore::ethstore::{EthStore, import_accounts}; use ethcore::ethstore::{EthStore, SecretStore, import_accounts, read_geth_accounts};
use ethcore::ethstore::dir::DiskDirectory; use ethcore::ethstore::dir::DiskDirectory;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use helpers::{password_prompt, password_from_file}; use helpers::{password_prompt, password_from_file};
@ -24,6 +24,7 @@ pub enum AccountCmd {
New(NewAccount), New(NewAccount),
List(String), List(String),
Import(ImportAccounts), Import(ImportAccounts),
ImportFromGeth(ImportFromGethAccounts)
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -39,11 +40,21 @@ pub struct ImportAccounts {
pub to: String, pub to: String,
} }
/// Parameters for geth accounts' import
#[derive(Debug, PartialEq)]
pub struct ImportFromGethAccounts {
/// import mainnet (false) or testnet (true) accounts
pub testnet: bool,
/// directory to import accounts to
pub to: String,
}
pub fn execute(cmd: AccountCmd) -> Result<String, String> { pub fn execute(cmd: AccountCmd) -> Result<String, String> {
match cmd { match cmd {
AccountCmd::New(new_cmd) => new(new_cmd), AccountCmd::New(new_cmd) => new(new_cmd),
AccountCmd::List(path) => list(path), AccountCmd::List(path) => list(path),
AccountCmd::Import(import_cmd) => import(import_cmd), AccountCmd::Import(import_cmd) => import(import_cmd),
AccountCmd::ImportFromGeth(import_geth_cmd) => import_geth(import_geth_cmd)
} }
} }
@ -51,6 +62,13 @@ fn keys_dir(path: String) -> Result<DiskDirectory, String> {
DiskDirectory::create(path).map_err(|e| format!("Could not open keys directory: {}", e)) DiskDirectory::create(path).map_err(|e| format!("Could not open keys directory: {}", e))
} }
fn secret_store(dir: Box<DiskDirectory>, iterations: Option<u32>) -> Result<EthStore, String> {
match iterations {
Some(i) => EthStore::open_with_iterations(dir, i),
_ => EthStore::open(dir)
}.map_err(|e| format!("Could not open keys store: {}", e))
}
fn new(n: NewAccount) -> Result<String, String> { fn new(n: NewAccount) -> Result<String, String> {
let password: String = match n.password_file { let password: String = match n.password_file {
Some(file) => try!(password_from_file(file)), Some(file) => try!(password_from_file(file)),
@ -58,7 +76,7 @@ fn new(n: NewAccount) -> Result<String, String> {
}; };
let dir = Box::new(try!(keys_dir(n.path))); let dir = Box::new(try!(keys_dir(n.path)));
let secret_store = Box::new(EthStore::open_with_iterations(dir, n.iterations).unwrap()); let secret_store = Box::new(try!(secret_store(dir, Some(n.iterations))));
let acc_provider = AccountProvider::new(secret_store); let acc_provider = AccountProvider::new(secret_store);
let new_account = try!(acc_provider.new_account(&password).map_err(|e| format!("Could not create new account: {}", e))); let new_account = try!(acc_provider.new_account(&password).map_err(|e| format!("Could not create new account: {}", e)));
Ok(format!("{:?}", new_account)) Ok(format!("{:?}", new_account))
@ -66,7 +84,7 @@ fn new(n: NewAccount) -> Result<String, String> {
fn list(path: String) -> Result<String, String> { fn list(path: String) -> Result<String, String> {
let dir = Box::new(try!(keys_dir(path))); let dir = Box::new(try!(keys_dir(path)));
let secret_store = Box::new(EthStore::open(dir).unwrap()); let secret_store = Box::new(try!(secret_store(dir, None)));
let acc_provider = AccountProvider::new(secret_store); let acc_provider = AccountProvider::new(secret_store);
let accounts = acc_provider.accounts(); let accounts = acc_provider.accounts();
let result = accounts.into_iter() let result = accounts.into_iter()
@ -86,3 +104,17 @@ fn import(i: ImportAccounts) -> Result<String, String> {
} }
Ok(format!("{}", imported)) Ok(format!("{}", imported))
} }
fn import_geth(i: ImportFromGethAccounts) -> Result<String, String> {
use std::io::ErrorKind;
use ethcore::ethstore::Error;
let dir = Box::new(try!(keys_dir(i.to)));
let secret_store = Box::new(try!(secret_store(dir, None)));
let geth_accounts = read_geth_accounts(i.testnet);
match secret_store.import_geth_accounts(geth_accounts, i.testnet) {
Ok(v) => Ok(format!("Successfully imported {} account(s) from geth.", v.len())),
Err(Error::Io(ref io_err)) if io_err.kind() == ErrorKind::NotFound => Err("Failed to find geth keys folder.".into()),
Err(err) => Err(format!("Import geth accounts failed. {}", err))
}
}

View File

@ -30,8 +30,8 @@ use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError,
use ethcore::error::ImportError; use ethcore::error::ImportError;
use ethcore::miner::Miner; use ethcore::miner::Miner;
use cache::CacheConfig; use cache::CacheConfig;
use params::{SpecType, Pruning, Switch, tracing_switch_to_bool};
use informant::{Informant, MillisecondDuration}; use informant::{Informant, MillisecondDuration};
use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool};
use io_handler::ImportIoHandler; use io_handler::ImportIoHandler;
use helpers::{to_client_config, execute_upgrades}; use helpers::{to_client_config, execute_upgrades};
use dir::Directories; use dir::Directories;
@ -81,6 +81,7 @@ pub struct ImportBlockchain {
pub wal: bool, pub wal: bool,
pub mode: Mode, pub mode: Mode,
pub tracing: Switch, pub tracing: Switch,
pub fat_db: Switch,
pub vm_type: VMType, pub vm_type: VMType,
} }
@ -96,6 +97,7 @@ pub struct ExportBlockchain {
pub compaction: DatabaseCompactionProfile, pub compaction: DatabaseCompactionProfile,
pub wal: bool, pub wal: bool,
pub mode: Mode, pub mode: Mode,
pub fat_db: Switch,
pub tracing: Switch, pub tracing: Switch,
pub from_block: BlockID, pub from_block: BlockID,
pub to_block: BlockID, pub to_block: BlockID,
@ -135,14 +137,17 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
// load user defaults // load user defaults
let mut user_defaults = try!(UserDefaults::load(&user_defaults_path)); let mut user_defaults = try!(UserDefaults::load(&user_defaults_path));
// check if tracing is on
let tracing = try!(tracing_switch_to_bool(cmd.tracing, &user_defaults));
fdlimit::raise_fd_limit(); fdlimit::raise_fd_limit();
// select pruning algorithm // select pruning algorithm
let algorithm = cmd.pruning.to_algorithm(&user_defaults); let algorithm = cmd.pruning.to_algorithm(&user_defaults);
// check if tracing is on
let tracing = try!(tracing_switch_to_bool(cmd.tracing, &user_defaults));
// check if fatdb is on
let fat_db = try!(fatdb_switch_to_bool(cmd.fat_db, &user_defaults, algorithm));
// prepare client and snapshot paths. // prepare client and snapshot paths.
let client_path = db_dirs.client_path(algorithm); let client_path = db_dirs.client_path(algorithm);
let snapshot_path = db_dirs.snapshot_path(); let snapshot_path = db_dirs.snapshot_path();
@ -151,7 +156,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile())); try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile()));
// prepare client config // prepare client config
let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), algorithm); let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), algorithm);
// build client // build client
let service = try!(ClientService::start( let service = try!(ClientService::start(
@ -283,14 +288,17 @@ fn execute_export(cmd: ExportBlockchain) -> Result<String, String> {
// load user defaults // load user defaults
let user_defaults = try!(UserDefaults::load(&user_defaults_path)); let user_defaults = try!(UserDefaults::load(&user_defaults_path));
// check if tracing is on
let tracing = try!(tracing_switch_to_bool(cmd.tracing, &user_defaults));
fdlimit::raise_fd_limit(); fdlimit::raise_fd_limit();
// select pruning algorithm // select pruning algorithm
let algorithm = cmd.pruning.to_algorithm(&user_defaults); let algorithm = cmd.pruning.to_algorithm(&user_defaults);
// check if tracing is on
let tracing = try!(tracing_switch_to_bool(cmd.tracing, &user_defaults));
// check if fatdb is on
let fat_db = try!(fatdb_switch_to_bool(cmd.fat_db, &user_defaults, algorithm));
// prepare client and snapshot paths. // prepare client and snapshot paths.
let client_path = db_dirs.client_path(algorithm); let client_path = db_dirs.client_path(algorithm);
let snapshot_path = db_dirs.snapshot_path(); let snapshot_path = db_dirs.snapshot_path();
@ -299,7 +307,7 @@ fn execute_export(cmd: ExportBlockchain) -> Result<String, String> {
try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile())); try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile()));
// prepare client config // prepare client config
let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, cmd.compaction, cmd.wal, VMType::default(), "".into(), algorithm); let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, VMType::default(), "".into(), algorithm);
let service = try!(ClientService::start( let service = try!(ClientService::start(
client_config, client_config,

View File

@ -82,7 +82,7 @@ cache_size_queue = 50
cache_size = 128 # Overrides above caches with total size cache_size = 128 # Overrides above caches with total size
fast_and_loose = false fast_and_loose = false
db_compaction = "ssd" db_compaction = "ssd"
fat_db = false fat_db = "auto"
[snapshots] [snapshots]
disable_periodic = false disable_periodic = false

View File

@ -49,7 +49,7 @@ cache_size_db = 128
cache_size_blocks = 16 cache_size_blocks = 16
cache_size_queue = 100 cache_size_queue = 100
db_compaction = "ssd" db_compaction = "ssd"
fat_db = true fat_db = "off"
[snapshots] [snapshots]
disable_periodic = true disable_periodic = true

View File

@ -217,7 +217,7 @@ usage! {
or |c: &Config| otry!(c.footprint).fast_and_loose.clone(), or |c: &Config| otry!(c.footprint).fast_and_loose.clone(),
flag_db_compaction: String = "ssd", flag_db_compaction: String = "ssd",
or |c: &Config| otry!(c.footprint).db_compaction.clone(), or |c: &Config| otry!(c.footprint).db_compaction.clone(),
flag_fat_db: bool = false, flag_fat_db: String = "auto",
or |c: &Config| otry!(c.footprint).fat_db.clone(), or |c: &Config| otry!(c.footprint).fat_db.clone(),
// -- Import/Export Options // -- Import/Export Options
@ -362,7 +362,7 @@ struct Footprint {
cache_size_blocks: Option<u32>, cache_size_blocks: Option<u32>,
cache_size_queue: Option<u32>, cache_size_queue: Option<u32>,
db_compaction: Option<String>, db_compaction: Option<String>,
fat_db: Option<bool>, fat_db: Option<String>,
} }
#[derive(Default, Debug, PartialEq, RustcDecodable)] #[derive(Default, Debug, PartialEq, RustcDecodable)]
@ -535,7 +535,7 @@ mod tests {
flag_cache_size: Some(128), flag_cache_size: Some(128),
flag_fast_and_loose: false, flag_fast_and_loose: false,
flag_db_compaction: "ssd".into(), flag_db_compaction: "ssd".into(),
flag_fat_db: false, flag_fat_db: "auto".into(),
// -- Import/Export Options // -- Import/Export Options
flag_from: "1".into(), flag_from: "1".into(),
@ -687,7 +687,7 @@ mod tests {
cache_size_blocks: Some(16), cache_size_blocks: Some(16),
cache_size_queue: Some(100), cache_size_queue: Some(100),
db_compaction: Some("ssd".into()), db_compaction: Some("ssd".into()),
fat_db: Some(true), fat_db: Some("off".into()),
}), }),
snapshots: Some(Snapshots { snapshots: Some(Snapshots {
disable_periodic: Some(true), disable_periodic: Some(true),

View File

@ -217,7 +217,10 @@ Footprint Options:
--db-compaction TYPE Database compaction type. TYPE may be one of: --db-compaction TYPE Database compaction type. TYPE may be one of:
ssd - suitable for SSDs and fast HDDs; ssd - suitable for SSDs and fast HDDs;
hdd - suitable for slow HDDs (default: {flag_db_compaction}). hdd - suitable for slow HDDs (default: {flag_db_compaction}).
--fat-db Fat database. (default: {flag_fat_db}) --fat-db BOOL Build appropriate information to allow enumeration
of all accounts and storage keys. Doubles the size
of the state database. BOOL may be one of on, off
or auto. (default: {flag_fat_db})
Import/Export Options: Import/Export Options:
--from BLOCK Export from block BLOCK, which may be an index or --from BLOCK Export from block BLOCK, which may be an index or

View File

@ -39,7 +39,7 @@ use signer::Configuration as SignerConfiguration;
use run::RunCmd; use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat}; use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet; use presale::ImportWallet;
use account::{AccountCmd, NewAccount, ImportAccounts}; use account::{AccountCmd, NewAccount, ImportAccounts, ImportFromGethAccounts};
use snapshot::{self, SnapshotCommand}; use snapshot::{self, SnapshotCommand};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -84,6 +84,7 @@ impl Configuration {
let cache_config = self.cache_config(); let cache_config = self.cache_config();
let spec = try!(self.chain().parse()); let spec = try!(self.chain().parse());
let tracing = try!(self.args.flag_tracing.parse()); let tracing = try!(self.args.flag_tracing.parse());
let fat_db = try!(self.args.flag_fat_db.parse());
let compaction = try!(self.args.flag_db_compaction.parse()); let compaction = try!(self.args.flag_db_compaction.parse());
let wal = !self.args.flag_fast_and_loose; let wal = !self.args.flag_fast_and_loose;
let enable_network = self.enable_network(&mode); let enable_network = self.enable_network(&mode);
@ -119,6 +120,14 @@ impl Configuration {
unreachable!(); unreachable!();
}; };
Cmd::Account(account_cmd) Cmd::Account(account_cmd)
} else if self.args.flag_import_geth_keys {
let account_cmd = AccountCmd::ImportFromGeth(
ImportFromGethAccounts {
to: dirs.keys,
testnet: self.args.flag_testnet
}
);
Cmd::Account(account_cmd)
} else if self.args.cmd_wallet { } else if self.args.cmd_wallet {
let presale_cmd = ImportWallet { let presale_cmd = ImportWallet {
iterations: self.args.flag_keys_iterations, iterations: self.args.flag_keys_iterations,
@ -140,6 +149,7 @@ impl Configuration {
wal: wal, wal: wal,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db,
vm_type: vm_type, vm_type: vm_type,
}; };
Cmd::Blockchain(BlockchainCmd::Import(import_cmd)) Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
@ -156,6 +166,7 @@ impl Configuration {
wal: wal, wal: wal,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db,
from_block: try!(to_block_id(&self.args.flag_from)), from_block: try!(to_block_id(&self.args.flag_from)),
to_block: try!(to_block_id(&self.args.flag_to)), to_block: try!(to_block_id(&self.args.flag_to)),
}; };
@ -169,6 +180,7 @@ impl Configuration {
logger_config: logger_config, logger_config: logger_config,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db,
compaction: compaction, compaction: compaction,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_file.clone(),
wal: wal, wal: wal,
@ -185,6 +197,7 @@ impl Configuration {
logger_config: logger_config, logger_config: logger_config,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db,
compaction: compaction, compaction: compaction,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_file.clone(),
wal: wal, wal: wal,
@ -216,6 +229,7 @@ impl Configuration {
miner_extras: try!(self.miner_extras()), miner_extras: try!(self.miner_extras()),
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db,
compaction: compaction, compaction: compaction,
wal: wal, wal: wal,
vm_type: vm_type, vm_type: vm_type,
@ -313,7 +327,6 @@ impl Configuration {
fn accounts_config(&self) -> Result<AccountsConfig, String> { fn accounts_config(&self) -> Result<AccountsConfig, String> {
let cfg = AccountsConfig { let cfg = AccountsConfig {
iterations: self.args.flag_keys_iterations, iterations: self.args.flag_keys_iterations,
import_keys: self.args.flag_import_geth_keys,
testnet: self.args.flag_testnet, testnet: self.args.flag_testnet,
password_files: self.args.flag_password.clone(), password_files: self.args.flag_password.clone(),
unlocked_accounts: try!(to_addresses(&self.args.flag_unlock)), unlocked_accounts: try!(to_addresses(&self.args.flag_unlock)),
@ -717,6 +730,7 @@ mod tests {
wal: true, wal: true,
mode: Default::default(), mode: Default::default(),
tracing: Default::default(), tracing: Default::default(),
fat_db: Default::default(),
vm_type: VMType::Interpreter, vm_type: VMType::Interpreter,
}))); })));
} }
@ -737,6 +751,7 @@ mod tests {
wal: true, wal: true,
mode: Default::default(), mode: Default::default(),
tracing: Default::default(), tracing: Default::default(),
fat_db: Default::default(),
from_block: BlockID::Number(1), from_block: BlockID::Number(1),
to_block: BlockID::Latest, to_block: BlockID::Latest,
}))); })));
@ -758,6 +773,7 @@ mod tests {
wal: true, wal: true,
mode: Default::default(), mode: Default::default(),
tracing: Default::default(), tracing: Default::default(),
fat_db: Default::default(),
from_block: BlockID::Number(1), from_block: BlockID::Number(1),
to_block: BlockID::Latest, to_block: BlockID::Latest,
}))); })));
@ -804,6 +820,7 @@ mod tests {
ui: false, ui: false,
name: "".into(), name: "".into(),
custom_bootnodes: false, custom_bootnodes: false,
fat_db: Default::default(),
no_periodic_snapshot: false, no_periodic_snapshot: false,
})); }));
} }

View File

@ -191,6 +191,7 @@ pub fn to_client_config(
cache_config: &CacheConfig, cache_config: &CacheConfig,
mode: Mode, mode: Mode,
tracing: bool, tracing: bool,
fat_db: bool,
compaction: DatabaseCompactionProfile, compaction: DatabaseCompactionProfile,
wal: bool, wal: bool,
vm_type: VMType, vm_type: VMType,
@ -217,6 +218,7 @@ pub fn to_client_config(
client_config.mode = mode; client_config.mode = mode;
client_config.tracing.enabled = tracing; client_config.tracing.enabled = tracing;
client_config.fat_db = fat_db;
client_config.pruning = pruning; client_config.pruning = pruning;
client_config.db_compaction = compaction; client_config.db_compaction = compaction;
client_config.db_wal = wal; client_config.db_wal = wal;

View File

@ -19,6 +19,7 @@ use std::fs::File;
use std::io::{Read, Write, Error as IoError, ErrorKind}; use std::io::{Read, Write, Error as IoError, ErrorKind};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::fmt::{Display, Formatter, Error as FmtError}; use std::fmt::{Display, Formatter, Error as FmtError};
use std::sync::Arc;
use util::journaldb::Algorithm; use util::journaldb::Algorithm;
use util::migration::{Manager as MigrationManager, Config as MigrationConfig, Error as MigrationError, Migration}; use util::migration::{Manager as MigrationManager, Config as MigrationConfig, Error as MigrationError, Migration};
use util::kvdb::{CompactionProfile, Database, DatabaseConfig}; use util::kvdb::{CompactionProfile, Database, DatabaseConfig};
@ -29,7 +30,7 @@ use ethcore::migrations::Extract;
/// Database is assumed to be at default version, when no version file is found. /// Database is assumed to be at default version, when no version file is found.
const DEFAULT_VERSION: u32 = 5; const DEFAULT_VERSION: u32 = 5;
/// Current version of database models. /// Current version of database models.
const CURRENT_VERSION: u32 = 9; const CURRENT_VERSION: u32 = 10;
/// First version of the consolidated database. /// First version of the consolidated database.
const CONSOLIDATION_VERSION: u32 = 9; const CONSOLIDATION_VERSION: u32 = 9;
/// Defines how many items are migrated to the new version of database at once. /// Defines how many items are migrated to the new version of database at once.
@ -143,7 +144,8 @@ pub fn default_migration_settings(compaction_profile: &CompactionProfile) -> Mig
/// Migrations on the consolidated database. /// Migrations on the consolidated database.
fn consolidated_database_migrations(compaction_profile: &CompactionProfile) -> Result<MigrationManager, Error> { fn consolidated_database_migrations(compaction_profile: &CompactionProfile) -> Result<MigrationManager, Error> {
let manager = MigrationManager::new(default_migration_settings(compaction_profile)); let mut manager = MigrationManager::new(default_migration_settings(compaction_profile));
try!(manager.add_migration(migrations::ToV10::new()).map_err(|_| Error::MigrationImpossible));
Ok(manager) Ok(manager)
} }
@ -172,13 +174,13 @@ fn consolidate_database(
let old_path_str = try!(old_db_path.to_str().ok_or(Error::MigrationImpossible)); let old_path_str = try!(old_db_path.to_str().ok_or(Error::MigrationImpossible));
let new_path_str = try!(new_db_path.to_str().ok_or(Error::MigrationImpossible)); let new_path_str = try!(new_db_path.to_str().ok_or(Error::MigrationImpossible));
let cur_db = try!(Database::open(&db_config, old_path_str).map_err(db_error)); let cur_db = Arc::new(try!(Database::open(&db_config, old_path_str).map_err(db_error)));
// open new DB with proper number of columns // open new DB with proper number of columns
db_config.columns = migration.columns(); db_config.columns = migration.columns();
let mut new_db = try!(Database::open(&db_config, new_path_str).map_err(db_error)); let mut new_db = try!(Database::open(&db_config, new_path_str).map_err(db_error));
// Migrate to new database (default column only) // Migrate to new database (default column only)
try!(migration.migrate(&cur_db, &config, &mut new_db, None)); try!(migration.migrate(cur_db, &config, &mut new_db, None));
Ok(()) Ok(())
} }

View File

@ -142,7 +142,6 @@ impl str::FromStr for ResealPolicy {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct AccountsConfig { pub struct AccountsConfig {
pub iterations: u32, pub iterations: u32,
pub import_keys: bool,
pub testnet: bool, pub testnet: bool,
pub password_files: Vec<String>, pub password_files: Vec<String>,
pub unlocked_accounts: Vec<Address>, pub unlocked_accounts: Vec<Address>,
@ -152,7 +151,6 @@ impl Default for AccountsConfig {
fn default() -> Self { fn default() -> Self {
AccountsConfig { AccountsConfig {
iterations: 10240, iterations: 10240,
import_keys: false,
testnet: false, testnet: false,
password_files: Vec::new(), password_files: Vec::new(),
unlocked_accounts: Vec::new(), unlocked_accounts: Vec::new(),
@ -252,6 +250,20 @@ pub fn tracing_switch_to_bool(switch: Switch, user_defaults: &UserDefaults) -> R
} }
} }
pub fn fatdb_switch_to_bool(switch: Switch, user_defaults: &UserDefaults, algorithm: Algorithm) -> Result<bool, String> {
let result = match (user_defaults.is_first_launch, switch, user_defaults.fat_db) {
(false, Switch::On, false) => Err("FatDB resync required".into()),
(_, Switch::On, _) => Ok(true),
(_, Switch::Off, _) => Ok(false),
(_, Switch::Auto, def) => Ok(def),
};
if result.clone().unwrap_or(false) && algorithm != Algorithm::Archive {
return Err("Fat DB is not supported with the chosen pruning option. Please rerun with `--pruning=archive`".into());
}
result
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::journaldb::Algorithm; use util::journaldb::Algorithm;

View File

@ -15,7 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Mutex, Condvar}; use std::sync::{Arc, Mutex, Condvar};
use std::io::ErrorKind;
use ctrlc::CtrlC; use ctrlc::CtrlC;
use fdlimit::raise_fd_limit; use fdlimit::raise_fd_limit;
use ethcore_logger::{Config as LogConfig, setup_log}; use ethcore_logger::{Config as LogConfig, setup_log};
@ -35,7 +34,10 @@ use rpc::{HttpServer, IpcServer, HttpConfiguration, IpcConfiguration};
use signer::SignerServer; use signer::SignerServer;
use dapps::WebappServer; use dapps::WebappServer;
use io_handler::ClientIoHandler; use io_handler::ClientIoHandler;
use params::{SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch, tracing_switch_to_bool}; use params::{
SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch,
tracing_switch_to_bool, fatdb_switch_to_bool,
};
use helpers::{to_client_config, execute_upgrades, passwords_from_files}; use helpers::{to_client_config, execute_upgrades, passwords_from_files};
use dir::Directories; use dir::Directories;
use cache::CacheConfig; use cache::CacheConfig;
@ -72,6 +74,7 @@ pub struct RunCmd {
pub miner_extras: MinerExtras, pub miner_extras: MinerExtras,
pub mode: Mode, pub mode: Mode,
pub tracing: Switch, pub tracing: Switch,
pub fat_db: Switch,
pub compaction: DatabaseCompactionProfile, pub compaction: DatabaseCompactionProfile,
pub wal: bool, pub wal: bool,
pub vm_type: VMType, pub vm_type: VMType,
@ -115,11 +118,14 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
// load user defaults // load user defaults
let mut user_defaults = try!(UserDefaults::load(&user_defaults_path)); let mut user_defaults = try!(UserDefaults::load(&user_defaults_path));
// select pruning algorithm
let algorithm = cmd.pruning.to_algorithm(&user_defaults);
// check if tracing is on // check if tracing is on
let tracing = try!(tracing_switch_to_bool(cmd.tracing, &user_defaults)); let tracing = try!(tracing_switch_to_bool(cmd.tracing, &user_defaults));
// select pruning algorithm // check if fatdb is on
let algorithm = cmd.pruning.to_algorithm(&user_defaults); let fat_db = try!(fatdb_switch_to_bool(cmd.fat_db, &user_defaults, algorithm));
// prepare client and snapshot paths. // prepare client and snapshot paths.
let client_path = db_dirs.client_path(algorithm); let client_path = db_dirs.client_path(algorithm);
@ -135,7 +141,17 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
// display info about used pruning algorithm // display info about used pruning algorithm
info!("Starting {}", Colour::White.bold().paint(version())); info!("Starting {}", Colour::White.bold().paint(version()));
info!("Using state DB journalling strategy {}", Colour::White.bold().paint(algorithm.as_str())); info!("State DB configuation: {}{}{}",
Colour::White.bold().paint(algorithm.as_str()),
match fat_db {
true => Colour::White.bold().paint(" +Fat").to_string(),
false => "".to_owned(),
},
match tracing {
true => Colour::White.bold().paint(" +Trace").to_string(),
false => "".to_owned(),
}
);
// display warning about using experimental journaldb alorithm // display warning about using experimental journaldb alorithm
if !algorithm.is_stable() { if !algorithm.is_stable() {
@ -171,6 +187,7 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
&cmd.cache_config, &cmd.cache_config,
cmd.mode, cmd.mode,
tracing, tracing,
fat_db,
cmd.compaction, cmd.compaction,
cmd.wal, cmd.wal,
cmd.vm_type, cmd.vm_type,
@ -223,7 +240,9 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
let signer_path = cmd.signer_conf.signer_path.clone(); let signer_path = cmd.signer_conf.signer_path.clone();
let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies { let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies {
signer_port: cmd.signer_port, signer_port: cmd.signer_port,
signer_service: Arc::new(rpc_apis::SignerService::new(move || signer::new_token(signer_path.clone()))), signer_service: Arc::new(rpc_apis::SignerService::new(move || {
signer::generate_new_token(signer_path.clone()).map_err(|e| format!("{:?}", e))
})),
client: client.clone(), client: client.clone(),
sync: sync_provider.clone(), sync: sync_provider.clone(),
net: manage_network.clone(), net: manage_network.clone(),
@ -340,28 +359,11 @@ fn daemonize(_pid_file: String) -> Result<(), String> {
} }
fn prepare_account_provider(dirs: &Directories, cfg: AccountsConfig) -> Result<AccountProvider, String> { fn prepare_account_provider(dirs: &Directories, cfg: AccountsConfig) -> Result<AccountProvider, String> {
use ethcore::ethstore::{import_accounts, EthStore}; use ethcore::ethstore::EthStore;
use ethcore::ethstore::dir::{GethDirectory, DirectoryType, DiskDirectory}; use ethcore::ethstore::dir::DiskDirectory;
use ethcore::ethstore::Error;
let passwords = try!(passwords_from_files(cfg.password_files)); let passwords = try!(passwords_from_files(cfg.password_files));
if cfg.import_keys {
let t = if cfg.testnet {
DirectoryType::Testnet
} else {
DirectoryType::Main
};
let from = GethDirectory::open(t);
let to = try!(DiskDirectory::create(dirs.keys.clone()).map_err(|e| format!("Could not open keys directory: {}", e)));
match import_accounts(&from, &to) {
Ok(_) => {}
Err(Error::Io(ref io_err)) if io_err.kind() == ErrorKind::NotFound => {}
Err(err) => warn!("Import geth accounts failed. {}", err)
}
}
let dir = Box::new(try!(DiskDirectory::create(dirs.keys.clone()).map_err(|e| format!("Could not open keys directory: {}", e)))); let dir = Box::new(try!(DiskDirectory::create(dirs.keys.clone()).map_err(|e| format!("Could not open keys directory: {}", e))));
let account_service = AccountProvider::new(Box::new( let account_service = AccountProvider::new(Box::new(
try!(EthStore::open_with_iterations(dir, cfg.iterations).map_err(|e| format!("Could not open keys directory: {}", e))) try!(EthStore::open_with_iterations(dir, cfg.iterations).map_err(|e| format!("Could not open keys directory: {}", e)))

View File

@ -74,7 +74,7 @@ pub fn new_token(path: String) -> Result<String, String> {
.map_err(|err| format!("Error generating token: {:?}", err)) .map_err(|err| format!("Error generating token: {:?}", err))
} }
fn generate_new_token(path: String) -> io::Result<String> { pub fn generate_new_token(path: String) -> io::Result<String> {
let path = codes_path(path); let path = codes_path(path);
let mut codes = try!(signer::AuthCodes::from_file(&path)); let mut codes = try!(signer::AuthCodes::from_file(&path));
let code = try!(codes.generate_new()); let code = try!(codes.generate_new());

View File

@ -30,7 +30,7 @@ use ethcore::miner::Miner;
use ethcore::ids::BlockID; use ethcore::ids::BlockID;
use cache::CacheConfig; use cache::CacheConfig;
use params::{SpecType, Pruning, Switch, tracing_switch_to_bool}; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool};
use helpers::{to_client_config, execute_upgrades}; use helpers::{to_client_config, execute_upgrades};
use dir::Directories; use dir::Directories;
use user_defaults::UserDefaults; use user_defaults::UserDefaults;
@ -57,6 +57,7 @@ pub struct SnapshotCommand {
pub logger_config: LogConfig, pub logger_config: LogConfig,
pub mode: Mode, pub mode: Mode,
pub tracing: Switch, pub tracing: Switch,
pub fat_db: Switch,
pub compaction: DatabaseCompactionProfile, pub compaction: DatabaseCompactionProfile,
pub file_path: Option<String>, pub file_path: Option<String>,
pub wal: bool, pub wal: bool,
@ -139,9 +140,6 @@ impl SnapshotCommand {
// load user defaults // load user defaults
let user_defaults = try!(UserDefaults::load(&user_defaults_path)); let user_defaults = try!(UserDefaults::load(&user_defaults_path));
// check if tracing is on
let tracing = try!(tracing_switch_to_bool(self.tracing, &user_defaults));
// Setup logging // Setup logging
let _logger = setup_log(&self.logger_config); let _logger = setup_log(&self.logger_config);
@ -150,6 +148,12 @@ impl SnapshotCommand {
// select pruning algorithm // select pruning algorithm
let algorithm = self.pruning.to_algorithm(&user_defaults); let algorithm = self.pruning.to_algorithm(&user_defaults);
// check if tracing is on
let tracing = try!(tracing_switch_to_bool(self.tracing, &user_defaults));
// check if fatdb is on
let fat_db = try!(fatdb_switch_to_bool(self.fat_db, &user_defaults, algorithm));
// prepare client and snapshot paths. // prepare client and snapshot paths.
let client_path = db_dirs.client_path(algorithm); let client_path = db_dirs.client_path(algorithm);
let snapshot_path = db_dirs.snapshot_path(); let snapshot_path = db_dirs.snapshot_path();
@ -158,7 +162,7 @@ impl SnapshotCommand {
try!(execute_upgrades(&db_dirs, algorithm, self.compaction.compaction_profile())); try!(execute_upgrades(&db_dirs, algorithm, self.compaction.compaction_profile()));
// prepare client config // prepare client config
let client_config = to_client_config(&self.cache_config, self.mode, tracing, self.compaction, self.wal, VMType::default(), "".into(), algorithm); let client_config = to_client_config(&self.cache_config, self.mode, tracing, fat_db, self.compaction, self.wal, VMType::default(), "".into(), algorithm);
let service = try!(ClientService::start( let service = try!(ClientService::start(
client_config, client_config,

View File

@ -30,6 +30,7 @@ pub struct UserDefaults {
pub is_first_launch: bool, pub is_first_launch: bool,
pub pruning: Algorithm, pub pruning: Algorithm,
pub tracing: bool, pub tracing: bool,
pub fat_db: bool,
} }
impl Serialize for UserDefaults { impl Serialize for UserDefaults {
@ -38,6 +39,7 @@ impl Serialize for UserDefaults {
let mut map: BTreeMap<String, Value> = BTreeMap::new(); let mut map: BTreeMap<String, Value> = BTreeMap::new();
map.insert("pruning".into(), Value::String(self.pruning.as_str().into())); map.insert("pruning".into(), Value::String(self.pruning.as_str().into()));
map.insert("tracing".into(), Value::Bool(self.tracing)); map.insert("tracing".into(), Value::Bool(self.tracing));
map.insert("fat_db".into(), Value::Bool(self.fat_db));
map.serialize(serializer) map.serialize(serializer)
} }
} }
@ -62,11 +64,14 @@ impl Visitor for UserDefaultsVisitor {
let pruning = try!(pruning.parse().map_err(|_| Error::custom("invalid pruning method"))); let pruning = try!(pruning.parse().map_err(|_| Error::custom("invalid pruning method")));
let tracing: Value = try!(map.remove("tracing".into()).ok_or_else(|| Error::custom("missing tracing"))); let tracing: Value = try!(map.remove("tracing".into()).ok_or_else(|| Error::custom("missing tracing")));
let tracing = try!(tracing.as_bool().ok_or_else(|| Error::custom("invalid tracing value"))); let tracing = try!(tracing.as_bool().ok_or_else(|| Error::custom("invalid tracing value")));
let fat_db: Value = map.remove("fat_db".into()).unwrap_or_else(|| Value::Bool(false));
let fat_db = try!(fat_db.as_bool().ok_or_else(|| Error::custom("invalid fat_db value")));
let user_defaults = UserDefaults { let user_defaults = UserDefaults {
is_first_launch: false, is_first_launch: false,
pruning: pruning, pruning: pruning,
tracing: tracing, tracing: tracing,
fat_db: fat_db,
}; };
Ok(user_defaults) Ok(user_defaults)
@ -79,6 +84,7 @@ impl Default for UserDefaults {
is_first_launch: true, is_first_launch: true,
pruning: Algorithm::default(), pruning: Algorithm::default(),
tracing: false, tracing: false,
fat_db: false,
} }
} }
} }

View File

@ -31,16 +31,32 @@ use serde::{Serialize, Deserialize};
/// function `to_delegate` which will automatically wrap each strongly-typed /// function `to_delegate` which will automatically wrap each strongly-typed
/// function in a wrapper which handles parameter and output type serialization. /// function in a wrapper which handles parameter and output type serialization.
/// ///
/// Every function must have a `#[name("rpc_nameHere")]` attribute after /// RPC functions may come in a couple forms: async and synchronous.
/// its documentation, and no other attributes. All function names are /// These are parsed with the custom `#[rpc]` attribute, which must follow
/// allowed except for `to_delegate`, which is auto-generated. /// documentation.
///
/// ## The #[rpc] attribute
///
/// Valid forms:
/// - `#[rpc(name = "name_here")]` (a synchronous rpc function which should be bound to the given name)
/// - `#[rpc(async, name = "name_here")]` (an async rpc function which should be bound to the given name)
///
/// Synchronous function format:
/// `fn foo(&self, Param1, Param2, Param3) -> Out`.
///
/// Asynchronous RPC functions must come in this form:
/// `fn foo(&self, Param1, Param2, Param3, Ready<Out>);
///
/// Anything else will be rejected by the code generator.
macro_rules! build_rpc_trait { macro_rules! build_rpc_trait {
// entry-point. todo: make another for traits w/ bounds.
( (
$(#[$t_attr: meta])* $(#[$t_attr: meta])*
pub trait $name: ident { pub trait $name: ident {
$( $(
$(#[doc=$m_doc: expr])* #[name($rpc_name: expr)] $( #[doc=$m_doc:expr] )*
fn $method: ident (&self $(, $param: ty)*) -> $out: ty; #[ rpc( $($t:tt)* ) ]
fn $m_name: ident ( $($p: tt)* ) $( -> Result<$out: ty, Error> )* ;
)* )*
} }
) => { ) => {
@ -48,7 +64,7 @@ macro_rules! build_rpc_trait {
pub trait $name: Sized + Send + Sync + 'static { pub trait $name: Sized + Send + Sync + 'static {
$( $(
$(#[doc=$m_doc])* $(#[doc=$m_doc])*
fn $method(&self $(, $param)*) -> $out; fn $m_name ( $($p)* ) $( -> Result<$out, Error> )* ;
)* )*
/// Transform this into an `IoDelegate`, automatically wrapping /// Transform this into an `IoDelegate`, automatically wrapping
@ -56,14 +72,33 @@ macro_rules! build_rpc_trait {
fn to_delegate(self) -> ::jsonrpc_core::IoDelegate<Self> { fn to_delegate(self) -> ::jsonrpc_core::IoDelegate<Self> {
let mut del = ::jsonrpc_core::IoDelegate::new(self.into()); let mut del = ::jsonrpc_core::IoDelegate::new(self.into());
$( $(
del.add_method($rpc_name, move |base, params| { build_rpc_trait!(WRAP del =>
($name::$method as fn(&_ $(, $param)*) -> $out).wrap_rpc(base, params) ( $($t)* )
}); fn $m_name ( $($p)* ) $( -> Result<$out, Error> )*
);
)* )*
del del
} }
} }
} };
( WRAP $del: expr =>
(name = $name: expr)
fn $method: ident (&self $(, $param: ty)*) -> Result<$out: ty, Error>
) => {
$del.add_method($name, move |base, params| {
(Self::$method as fn(&_ $(, $param)*) -> Result<$out, Error>).wrap_rpc(base, params)
})
};
( WRAP $del: expr =>
(async, name = $name: expr)
fn $method: ident (&self, Ready<$out: ty> $(, $param: ty)*)
) => {
$del.add_async_method($name, move |base, params, ready| {
(Self::$method as fn(&_, Ready<$out> $(, $param)*)).wrap_rpc(base, params, ready)
})
};
} }
/// A wrapper type without an implementation of `Deserialize` /// A wrapper type without an implementation of `Deserialize`
@ -71,11 +106,35 @@ macro_rules! build_rpc_trait {
/// that take a trailing default parameter. /// that take a trailing default parameter.
pub struct Trailing<T: Default + Deserialize>(pub T); pub struct Trailing<T: Default + Deserialize>(pub T);
/// A wrapper type for `jsonrpc_core`'s weakly-typed `Ready` struct.
pub struct Ready<T: Serialize> {
inner: ::jsonrpc_core::Ready,
_marker: ::std::marker::PhantomData<T>,
}
impl<T: Serialize> From<::jsonrpc_core::Ready> for Ready<T> {
fn from(ready: ::jsonrpc_core::Ready) -> Self {
Ready { inner: ready, _marker: ::std::marker::PhantomData }
}
}
impl<T: Serialize> Ready<T> {
/// Respond withthe asynchronous result.
pub fn ready(self, result: Result<T, Error>) {
self.inner.ready(result.map(to_value))
}
}
/// Wrapper trait for synchronous RPC functions. /// Wrapper trait for synchronous RPC functions.
pub trait Wrap<B: Send + Sync + 'static> { pub trait Wrap<B: Send + Sync + 'static> {
fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error>; fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error>;
} }
/// Wrapper trait for asynchronous RPC functions.
pub trait WrapAsync<B: Send + Sync + 'static> {
fn wrap_rpc(&self, base: &B, params: Params, ready: ::jsonrpc_core::Ready);
}
// special impl for no parameters. // special impl for no parameters.
impl<B, OUT> Wrap<B> for fn(&B) -> Result<OUT, Error> impl<B, OUT> Wrap<B> for fn(&B) -> Result<OUT, Error>
where B: Send + Sync + 'static, OUT: Serialize where B: Send + Sync + 'static, OUT: Serialize
@ -87,10 +146,23 @@ impl<B, OUT> Wrap<B> for fn(&B) -> Result<OUT, Error>
} }
} }
impl<B, OUT> WrapAsync<B> for fn(&B, Ready<OUT>)
where B: Send + Sync + 'static, OUT: Serialize
{
fn wrap_rpc(&self, base: &B, params: Params, ready: ::jsonrpc_core::Ready) {
match ::v1::helpers::params::expect_no_params(params) {
Ok(()) => (self)(base, ready.into()),
Err(e) => ready.ready(Err(e)),
}
}
}
// creates a wrapper implementation which deserializes the parameters, // creates a wrapper implementation which deserializes the parameters,
// calls the function with concrete type, and serializes the output. // calls the function with concrete type, and serializes the output.
macro_rules! wrap { macro_rules! wrap {
($($x: ident),+) => { ($($x: ident),+) => {
// synchronous implementation
impl < impl <
BASE: Send + Sync + 'static, BASE: Send + Sync + 'static,
OUT: Serialize, OUT: Serialize,
@ -102,6 +174,20 @@ macro_rules! wrap {
}).map(to_value) }).map(to_value)
} }
} }
// asynchronous implementation
impl <
BASE: Send + Sync + 'static,
OUT: Serialize,
$($x: Deserialize,)+
> WrapAsync<BASE> for fn(&BASE, Ready<OUT>, $($x,)+ ) {
fn wrap_rpc(&self, base: &BASE, params: Params, ready: ::jsonrpc_core::Ready) {
match from_params::<($($x,)+)>(params) {
Ok(($($x,)+)) => (self)(base, ready.into(), $($x,)+),
Err(e) => ready.ready(Err(e)),
}
}
}
} }
} }
@ -126,10 +212,34 @@ impl<B, OUT, T> Wrap<B> for fn(&B, Trailing<T>) -> Result<OUT, Error>
} }
} }
impl<B, OUT, T> WrapAsync<B> for fn(&B, Ready<OUT>, Trailing<T>)
where B: Send + Sync + 'static, OUT: Serialize, T: Default + Deserialize
{
fn wrap_rpc(&self, base: &B, params: Params, ready: ::jsonrpc_core::Ready) {
let len = match params {
Params::Array(ref v) => v.len(),
Params::None => 0,
_ => return ready.ready(Err(errors::invalid_params("not an array", ""))),
};
let id = match len {
0 => Ok((T::default(),)),
1 => from_params::<(T,)>(params),
_ => Err(Error::invalid_params()),
};
match id {
Ok((id,)) => (self)(base, ready.into(), Trailing(id)),
Err(e) => ready.ready(Err(e)),
}
}
}
// similar to `wrap!`, but handles a single default trailing parameter // similar to `wrap!`, but handles a single default trailing parameter
// accepts an additional argument indicating the number of non-trailing parameters. // accepts an additional argument indicating the number of non-trailing parameters.
macro_rules! wrap_with_trailing { macro_rules! wrap_with_trailing {
($num: expr, $($x: ident),+) => { ($num: expr, $($x: ident),+) => {
// synchronous implementation
impl < impl <
BASE: Send + Sync + 'static, BASE: Send + Sync + 'static,
OUT: Serialize, OUT: Serialize,
@ -155,6 +265,35 @@ macro_rules! wrap_with_trailing {
(self)(base, $($x,)+ Trailing(id)).map(to_value) (self)(base, $($x,)+ Trailing(id)).map(to_value)
} }
} }
// asynchronous implementation
impl <
BASE: Send + Sync + 'static,
OUT: Serialize,
$($x: Deserialize,)+
TRAILING: Default + Deserialize,
> WrapAsync<BASE> for fn(&BASE, Ready<OUT>, $($x,)+ Trailing<TRAILING>) {
fn wrap_rpc(&self, base: &BASE, params: Params, ready: ::jsonrpc_core::Ready) {
let len = match params {
Params::Array(ref v) => v.len(),
Params::None => 0,
_ => return ready.ready(Err(errors::invalid_params("not an array", ""))),
};
let params = match len - $num {
0 => from_params::<($($x,)+)>(params)
.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
1 => from_params::<($($x,)+ TRAILING)>(params)
.map(|($($x,)+ id)| ($($x,)+ id)),
_ => Err(Error::invalid_params()),
};
match params {
Ok(($($x,)+ id)) => (self)(base, ready.into(), $($x,)+ Trailing(id)),
Err(e) => ready.ready(Err(e))
}
}
}
} }
} }

View File

@ -18,7 +18,7 @@
use std::{fs, io}; use std::{fs, io};
use std::sync::{mpsc, Arc, Weak}; use std::sync::{mpsc, Arc, Weak};
use std::str::FromStr; use std::str::FromStr;
use std::collections::{BTreeMap};
use util::{RotatingLogger, Address, Mutex, sha3}; use util::{RotatingLogger, Address, Mutex, sha3};
use util::misc::version_data; use util::misc::version_data;
@ -29,12 +29,13 @@ use ethstore::random_phrase;
use ethsync::{SyncProvider, ManageNetwork}; use ethsync::{SyncProvider, ManageNetwork};
use ethcore::miner::MinerService; use ethcore::miner::MinerService;
use ethcore::client::{MiningBlockChainClient}; use ethcore::client::{MiningBlockChainClient};
use ethcore::ids::BlockID;
use jsonrpc_core::{from_params, to_value, Value, Error, Params, Ready}; use jsonrpc_core::Error;
use v1::traits::Ethcore; use v1::traits::Ethcore;
use v1::types::{Bytes, U256, H160, H256, H512, Peers, Transaction}; use v1::types::{Bytes, U256, H160, H256, H512, Peers, Transaction, RpcSettings};
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
use v1::helpers::params::expect_no_params; use v1::helpers::auto_args::Ready;
/// Ethcore implementation. /// Ethcore implementation.
pub struct EthcoreClient<C, M, S: ?Sized, F=FetchClient> where pub struct EthcoreClient<C, M, S: ?Sized, F=FetchClient> where
@ -112,162 +113,168 @@ impl<C, M, S: ?Sized, F> Ethcore for EthcoreClient<C, M, S, F> where
S: SyncProvider + 'static, S: SyncProvider + 'static,
F: Fetch + 'static { F: Fetch + 'static {
fn transactions_limit(&self, params: Params) -> Result<Value, Error> { fn transactions_limit(&self) -> Result<usize, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&take_weak!(self.miner).transactions_limit())) Ok(take_weak!(self.miner).transactions_limit())
} }
fn min_gas_price(&self, params: Params) -> Result<Value, Error> { fn min_gas_price(&self) -> Result<U256, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&U256::from(take_weak!(self.miner).minimal_gas_price()))) Ok(U256::from(take_weak!(self.miner).minimal_gas_price()))
} }
fn extra_data(&self, params: Params) -> Result<Value, Error> { fn extra_data(&self) -> Result<Bytes, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&Bytes::new(take_weak!(self.miner).extra_data()))) Ok(Bytes::new(take_weak!(self.miner).extra_data()))
} }
fn gas_floor_target(&self, params: Params) -> Result<Value, Error> { fn gas_floor_target(&self) -> Result<U256, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&U256::from(take_weak!(self.miner).gas_floor_target()))) Ok(U256::from(take_weak!(self.miner).gas_floor_target()))
} }
fn gas_ceil_target(&self, params: Params) -> Result<Value, Error> { fn gas_ceil_target(&self) -> Result<U256, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&U256::from(take_weak!(self.miner).gas_ceil_target()))) Ok(U256::from(take_weak!(self.miner).gas_ceil_target()))
} }
fn dev_logs(&self, params: Params) -> Result<Value, Error> { fn dev_logs(&self) -> Result<Vec<String>, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
let logs = self.logger.logs(); let logs = self.logger.logs();
Ok(to_value(&logs.as_slice())) Ok(logs.as_slice().to_owned())
} }
fn dev_logs_levels(&self, params: Params) -> Result<Value, Error> { fn dev_logs_levels(&self) -> Result<String, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&self.logger.levels())) Ok(self.logger.levels().to_owned())
} }
fn net_chain(&self, params: Params) -> Result<Value, Error> { fn net_chain(&self) -> Result<String, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&self.settings.chain)) Ok(self.settings.chain.clone())
} }
fn net_peers(&self, params: Params) -> Result<Value, Error> { fn net_peers(&self) -> Result<Peers, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
let sync_status = take_weak!(self.sync).status(); let sync_status = take_weak!(self.sync).status();
let net_config = take_weak!(self.net).network_config(); let net_config = take_weak!(self.net).network_config();
Ok(to_value(&Peers { Ok(Peers {
active: sync_status.num_active_peers, active: sync_status.num_active_peers,
connected: sync_status.num_peers, connected: sync_status.num_peers,
max: sync_status.current_max_peers(net_config.min_peers, net_config.max_peers), max: sync_status.current_max_peers(net_config.min_peers, net_config.max_peers),
})) })
} }
fn net_port(&self, params: Params) -> Result<Value, Error> { fn net_port(&self) -> Result<u16, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&self.settings.network_port)) Ok(self.settings.network_port)
} }
fn node_name(&self, params: Params) -> Result<Value, Error> { fn node_name(&self) -> Result<String, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&self.settings.name)) Ok(self.settings.name.clone())
} }
fn registry_address(&self, params: Params) -> Result<Value, Error> { fn registry_address(&self) -> Result<Option<H160>, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
let r = take_weak!(self.client) Ok(
.additional_params() take_weak!(self.client)
.get("registrar") .additional_params()
.and_then(|s| Address::from_str(s).ok()) .get("registrar")
.map(|s| H160::from(s)); .and_then(|s| Address::from_str(s).ok())
Ok(to_value(&r)) .map(|s| H160::from(s))
)
} }
fn rpc_settings(&self, params: Params) -> Result<Value, Error> { fn rpc_settings(&self) -> Result<RpcSettings, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params)); Ok(RpcSettings {
let mut map = BTreeMap::new(); enabled: self.settings.rpc_enabled,
map.insert("enabled".to_owned(), Value::Bool(self.settings.rpc_enabled)); interface: self.settings.rpc_interface.clone(),
map.insert("interface".to_owned(), Value::String(self.settings.rpc_interface.clone())); port: self.settings.rpc_port as u64,
map.insert("port".to_owned(), Value::U64(self.settings.rpc_port as u64)); })
Ok(Value::Object(map))
} }
fn default_extra_data(&self, params: Params) -> Result<Value, Error> { fn default_extra_data(&self) -> Result<Bytes, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&Bytes::new(version_data()))) Ok(Bytes::new(version_data()))
} }
fn gas_price_statistics(&self, params: Params) -> Result<Value, Error> { fn gas_price_statistics(&self) -> Result<Vec<U256>, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
match take_weak!(self.client).gas_price_statistics(100, 8) { match take_weak!(self.client).gas_price_statistics(100, 8) {
Ok(stats) => Ok(to_value(&stats Ok(stats) => Ok(stats.into_iter().map(Into::into).collect()),
.into_iter()
.map(|x| to_value(&U256::from(x)))
.collect::<Vec<_>>())),
_ => Err(Error::internal_error()), _ => Err(Error::internal_error()),
} }
} }
fn unsigned_transactions_count(&self, params: Params) -> Result<Value, Error> { fn unsigned_transactions_count(&self) -> Result<usize, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
match self.signer { match self.signer {
None => Err(errors::signer_disabled()), None => Err(errors::signer_disabled()),
Some(ref signer) => Ok(to_value(&signer.len())), Some(ref signer) => Ok(signer.len()),
} }
} }
fn generate_secret_phrase(&self, params: Params) -> Result<Value, Error> { fn generate_secret_phrase(&self) -> Result<String, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&random_phrase(12))) Ok(random_phrase(12))
} }
fn phrase_to_address(&self, params: Params) -> Result<Value, Error> { fn phrase_to_address(&self, phrase: String) -> Result<H160, Error> {
try!(self.active()); try!(self.active());
from_params::<(String,)>(params).map(|(phrase,)|
to_value(&H160::from(Brain::new(phrase).generate().unwrap().address())) Ok(Brain::new(phrase).generate().unwrap().address().into())
)
} }
fn encrypt_message(&self, params: Params) -> Result<Value, Error> { fn list_accounts(&self) -> Result<Option<Vec<H160>>, Error> {
try!(self.active()); try!(self.active());
from_params::<(H512, Bytes)>(params).and_then(|(key, phrase)| {
let s = try!(ecies::encrypt(&key.into(), &[0; 0], &phrase.0).map_err(|_| Error::internal_error())); Ok(take_weak!(self.client)
Ok(to_value(&Bytes::from(s))) .list_accounts(BlockID::Latest)
}) .map(|a| a.into_iter().map(Into::into).collect()))
} }
fn pending_transactions(&self, params: Params) -> Result<Value, Error> { fn list_storage_keys(&self, _address: H160) -> Result<Option<Vec<H256>>, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
Ok(to_value(&take_weak!(self.miner).all_transactions().into_iter().map(Into::into).collect::<Vec<Transaction>>())) // TODO: implement this
Ok(None)
} }
fn hash_content(&self, params: Params, ready: Ready) { fn encrypt_message(&self, key: H512, phrase: Bytes) -> Result<Bytes, Error> {
let res = self.active().and_then(|_| from_params::<(String,)>(params)); try!(self.active());
ecies::encrypt(&key.into(), &[0; 0], &phrase.0)
.map_err(|_| Error::internal_error())
.map(Into::into)
}
fn pending_transactions(&self) -> Result<Vec<Transaction>, Error> {
try!(self.active());
Ok(take_weak!(self.miner).all_transactions().into_iter().map(Into::into).collect::<Vec<_>>())
}
fn hash_content(&self, ready: Ready<H256>, url: String) {
let res = self.active();
let hash_content = |result| { let hash_content = |result| {
let path = try!(result); let path = try!(result);
@ -282,15 +289,15 @@ impl<C, M, S: ?Sized, F> Ethcore for EthcoreClient<C, M, S, F> where
match res { match res {
Err(e) => ready.ready(Err(e)), Err(e) => ready.ready(Err(e)),
Ok((url, )) => { Ok(()) => {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let res = self.fetch.lock().request_async(&url, Default::default(), Box::new(move |result| { let res = self.fetch.lock().request_async(&url, Default::default(), Box::new(move |result| {
let result = hash_content(result) let result = hash_content(result)
.map_err(errors::from_fetch_error) .map_err(errors::from_fetch_error)
.map(|hash| to_value(H256::from(hash))); .map(Into::into);
// Receive ready and invoke with result. // Receive ready and invoke with result.
let ready: Ready = rx.try_recv().expect("When on_done is invoked ready object is always sent."); let ready: Ready<H256> = rx.try_recv().expect("When on_done is invoked ready object is always sent.");
ready.ready(result); ready.ready(result);
})); }));

View File

@ -21,7 +21,6 @@ use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient; use ethcore::client::MiningBlockChainClient;
use ethsync::ManageNetwork; use ethsync::ManageNetwork;
use v1::helpers::errors; use v1::helpers::errors;
use v1::helpers::params::expect_no_params;
use v1::traits::EthcoreSet; use v1::traits::EthcoreSet;
use v1::types::{Bytes, H160, U256}; use v1::types::{Bytes, H160, U256};
@ -58,105 +57,94 @@ impl<C, M> EthcoreSet for EthcoreSetClient<C, M> where
C: MiningBlockChainClient + 'static, C: MiningBlockChainClient + 'static,
M: MinerService + 'static { M: MinerService + 'static {
fn set_min_gas_price(&self, params: Params) -> Result<Value, Error> { fn set_min_gas_price(&self, gas_price: U256) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(U256,)>(params).and_then(|(gas_price,)| {
take_weak!(self.miner).set_minimal_gas_price(gas_price.into()); take_weak!(self.miner).set_minimal_gas_price(gas_price.into());
Ok(to_value(&true)) Ok(true)
})
} }
fn set_gas_floor_target(&self, params: Params) -> Result<Value, Error> { fn set_gas_floor_target(&self, target: U256) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(U256,)>(params).and_then(|(target,)| {
take_weak!(self.miner).set_gas_floor_target(target.into()); take_weak!(self.miner).set_gas_floor_target(target.into());
Ok(to_value(&true)) Ok(true)
})
} }
fn set_gas_ceil_target(&self, params: Params) -> Result<Value, Error> { fn set_gas_ceil_target(&self, target: U256) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(U256,)>(params).and_then(|(target,)| {
take_weak!(self.miner).set_gas_ceil_target(target.into()); take_weak!(self.miner).set_gas_ceil_target(target.into());
Ok(to_value(&true)) Ok(true)
})
} }
fn set_extra_data(&self, params: Params) -> Result<Value, Error> { fn set_extra_data(&self, extra_data: Bytes) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(Bytes,)>(params).and_then(|(extra_data,)| {
take_weak!(self.miner).set_extra_data(extra_data.to_vec()); take_weak!(self.miner).set_extra_data(extra_data.to_vec());
Ok(to_value(&true)) Ok(true)
})
} }
fn set_author(&self, params: Params) -> Result<Value, Error> { fn set_author(&self, author: H160) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(H160,)>(params).and_then(|(author,)| {
take_weak!(self.miner).set_author(author.into()); take_weak!(self.miner).set_author(author.into());
Ok(to_value(&true)) Ok(true)
})
} }
fn set_transactions_limit(&self, params: Params) -> Result<Value, Error> { fn set_transactions_limit(&self, limit: usize) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(usize,)>(params).and_then(|(limit,)| {
take_weak!(self.miner).set_transactions_limit(limit); take_weak!(self.miner).set_transactions_limit(limit);
Ok(to_value(&true)) Ok(true)
})
} }
fn set_tx_gas_limit(&self, params: Params) -> Result<Value, Error> { fn set_tx_gas_limit(&self, limit: U256) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(U256,)>(params).and_then(|(limit,)| {
take_weak!(self.miner).set_tx_gas_limit(limit.into()); take_weak!(self.miner).set_tx_gas_limit(limit.into());
Ok(to_value(&true)) Ok(true)
})
} }
fn add_reserved_peer(&self, params: Params) -> Result<Value, Error> { fn add_reserved_peer(&self, peer: String) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(String,)>(params).and_then(|(peer,)| {
match take_weak!(self.net).add_reserved_peer(peer) { match take_weak!(self.net).add_reserved_peer(peer) {
Ok(()) => Ok(to_value(&true)), Ok(()) => Ok(true),
Err(e) => Err(errors::invalid_params("Peer address", e)), Err(e) => Err(errors::invalid_params("Peer address", e)),
} }
})
} }
fn remove_reserved_peer(&self, params: Params) -> Result<Value, Error> { fn remove_reserved_peer(&self, peer: String) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
from_params::<(String,)>(params).and_then(|(peer,)| {
match take_weak!(self.net).remove_reserved_peer(peer) { match take_weak!(self.net).remove_reserved_peer(peer) {
Ok(()) => Ok(to_value(&true)), Ok(()) => Ok(true),
Err(e) => Err(errors::invalid_params("Peer address", e)), Err(e) => Err(errors::invalid_params("Peer address", e)),
} }
})
} }
fn drop_non_reserved_peers(&self, params: Params) -> Result<Value, Error> { fn drop_non_reserved_peers(&self) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
take_weak!(self.net).deny_unreserved_peers(); take_weak!(self.net).deny_unreserved_peers();
Ok(to_value(&true)) Ok(true)
} }
fn accept_non_reserved_peers(&self, params: Params) -> Result<Value, Error> { fn accept_non_reserved_peers(&self) -> Result<bool, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params));
take_weak!(self.net).accept_unreserved_peers(); take_weak!(self.net).accept_unreserved_peers();
Ok(to_value(&true)) Ok(true)
} }
fn start_network(&self, params: Params) -> Result<Value, Error> { fn start_network(&self) -> Result<bool, Error> {
try!(expect_no_params(params));
take_weak!(self.net).start_network(); take_weak!(self.net).start_network();
Ok(Value::Bool(true)) Ok(true)
} }
fn stop_network(&self, params: Params) -> Result<Value, Error> { fn stop_network(&self) -> Result<bool, Error> {
try!(expect_no_params(params));
take_weak!(self.net).stop_network(); take_weak!(self.net).stop_network();
Ok(Value::Bool(true)) Ok(true)
} }
} }

View File

@ -16,10 +16,9 @@
//! Net rpc implementation. //! Net rpc implementation.
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use jsonrpc_core::*; use jsonrpc_core::Error;
use ethsync::SyncProvider; use ethsync::SyncProvider;
use v1::traits::Net; use v1::traits::Net;
use v1::helpers::params::expect_no_params;
/// Net rpc implementation. /// Net rpc implementation.
pub struct NetClient<S: ?Sized> where S: SyncProvider { pub struct NetClient<S: ?Sized> where S: SyncProvider {
@ -36,20 +35,19 @@ impl<S: ?Sized> NetClient<S> where S: SyncProvider {
} }
impl<S: ?Sized> Net for NetClient<S> where S: SyncProvider + 'static { impl<S: ?Sized> Net for NetClient<S> where S: SyncProvider + 'static {
fn version(&self, params: Params) -> Result<Value, Error> { fn version(&self) -> Result<String, Error> {
try!(expect_no_params(params)); Ok(format!("{}", take_weak!(self.sync).status().network_id).to_owned())
Ok(Value::String(format!("{}", take_weak!(self.sync).status().network_id).to_owned()))
} }
fn peer_count(&self, params: Params) -> Result<Value, Error> { fn peer_count(&self) -> Result<String, Error> {
try!(expect_no_params(params)); Ok(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned())
Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned()))
} }
fn is_listening(&self, params: Params) -> Result<Value, Error> { fn is_listening(&self) -> Result<bool, Error> {
try!(expect_no_params(params));
// right now (11 march 2016), we are always listening for incoming connections // right now (11 march 2016), we are always listening for incoming connections
Ok(Value::Bool(true)) //
// (this may not be true now -- 26 september 2016)
Ok(true)
} }
} }

View File

@ -16,9 +16,8 @@
//! RPC generic methods implementation. //! RPC generic methods implementation.
use std::collections::BTreeMap; use std::collections::BTreeMap;
use jsonrpc_core::*; use jsonrpc_core::Error;
use v1::traits::Rpc; use v1::traits::Rpc;
use v1::helpers::params::expect_no_params;
/// RPC generic methods implementation. /// RPC generic methods implementation.
pub struct RpcClient { pub struct RpcClient {
@ -40,26 +39,26 @@ impl RpcClient {
} }
impl Rpc for RpcClient { impl Rpc for RpcClient {
fn rpc_modules(&self, params: Params) -> Result<Value, Error> { fn rpc_modules(&self) -> Result<BTreeMap<String, String>, Error> {
try!(expect_no_params(params));
let modules = self.modules.iter() let modules = self.modules.iter()
.fold(BTreeMap::new(), |mut map, (k, v)| { .fold(BTreeMap::new(), |mut map, (k, v)| {
map.insert(k.to_owned(), Value::String(v.to_owned())); map.insert(k.to_owned(), v.to_owned());
map map
}); });
Ok(Value::Object(modules))
Ok(modules)
} }
fn modules(&self, params: Params) -> Result<Value, Error> { fn modules(&self) -> Result<BTreeMap<String, String>, Error> {
try!(expect_no_params(params));
let modules = self.modules.iter() let modules = self.modules.iter()
.filter(|&(k, _v)| { .filter(|&(k, _v)| {
self.valid_apis.contains(k) self.valid_apis.contains(k)
}) })
.fold(BTreeMap::new(), |mut map, (k, v)| { .fold(BTreeMap::new(), |mut map, (k, v)| {
map.insert(k.to_owned(), Value::String(v.to_owned())); map.insert(k.to_owned(), v.to_owned());
map map
}); });
Ok(Value::Object(modules))
Ok(modules)
} }
} }

View File

@ -249,7 +249,7 @@ impl MinerService for TestMinerService {
} }
fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> { fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
self.latest_closed_block.lock().as_ref().map_or(None, |b| b.block().fields().state.code(address).clone()) self.latest_closed_block.lock().as_ref().map_or(None, |b| b.block().fields().state.code(address).map(|c| (*c).clone()))
} }
} }

View File

@ -115,4 +115,4 @@ fn rpc_ethcore_set_transactions_limit() {
assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
assert_eq!(miner.transactions_limit(), 10_240_240); assert_eq!(miner.transactions_limit(), 10_240_240);
} }

View File

@ -28,174 +28,173 @@ build_rpc_trait! {
/// Eth rpc interface. /// Eth rpc interface.
pub trait Eth { pub trait Eth {
/// Returns protocol version encoded as a string (quotes are necessary). /// Returns protocol version encoded as a string (quotes are necessary).
#[name("eth_protocolVersion")] #[rpc(name = "eth_protocolVersion")]
fn protocol_version(&self) -> Result<String, Error>; fn protocol_version(&self) -> Result<String, Error>;
/// Returns an object with data about the sync status or false. (wtf?) /// Returns an object with data about the sync status or false. (wtf?)
#[name("eth_syncing")] #[rpc(name = "eth_syncing")]
fn syncing(&self) -> Result<SyncStatus, Error>; fn syncing(&self) -> Result<SyncStatus, Error>;
/// Returns the number of hashes per second that the node is mining with. /// Returns the number of hashes per second that the node is mining with.
#[name("eth_hashrate")] #[rpc(name = "eth_hashrate")]
fn hashrate(&self) -> Result<U256, Error>; fn hashrate(&self) -> Result<U256, Error>;
/// Returns block author. /// Returns block author.
#[name("eth_coinbase")] #[rpc(name = "eth_coinbase")]
fn author(&self) -> Result<H160, Error>; fn author(&self) -> Result<H160, Error>;
/// Returns true if client is actively mining new blocks. /// Returns true if client is actively mining new blocks.
#[name("eth_mining")] #[rpc(name = "eth_mining")]
fn is_mining(&self) -> Result<bool, Error>; fn is_mining(&self) -> Result<bool, Error>;
/// Returns current gas_price. /// Returns current gas_price.
#[name("eth_gasPrice")] #[rpc(name = "eth_gasPrice")]
fn gas_price(&self) -> Result<U256, Error>; fn gas_price(&self) -> Result<U256, Error>;
/// Returns accounts list. /// Returns accounts list.
#[name("eth_accounts")] #[rpc(name = "eth_accounts")]
fn accounts(&self) -> Result<Vec<H160>, Error>; fn accounts(&self) -> Result<Vec<H160>, Error>;
/// Returns highest block number. /// Returns highest block number.
#[name("eth_blockNumber")] #[rpc(name = "eth_blockNumber")]
fn block_number(&self) -> Result<U256, Error>; fn block_number(&self) -> Result<U256, Error>;
/// Returns balance of the given account. /// Returns balance of the given account.
#[name("eth_getBalance")] #[rpc(name = "eth_getBalance")]
fn balance(&self, H160, Trailing<BlockNumber>) -> Result<U256, Error>; fn balance(&self, H160, Trailing<BlockNumber>) -> Result<U256, Error>;
/// Returns content of the storage at given address. /// Returns content of the storage at given address.
#[name("eth_getStorageAt")] #[rpc(name = "eth_getStorageAt")]
fn storage_at(&self, H160, U256, Trailing<BlockNumber>) -> Result<H256, Error>; fn storage_at(&self, H160, U256, Trailing<BlockNumber>) -> Result<H256, Error>;
/// Returns block with given hash. /// Returns block with given hash.
#[name("eth_getBlockByHash")] #[rpc(name = "eth_getBlockByHash")]
fn block_by_hash(&self, H256, bool) -> Result<Option<Block>, Error>; fn block_by_hash(&self, H256, bool) -> Result<Option<Block>, Error>;
/// Returns block with given number. /// Returns block with given number.
#[name("eth_getBlockByNumber")] #[rpc(name = "eth_getBlockByNumber")]
fn block_by_number(&self, BlockNumber, bool) -> Result<Option<Block>, Error>; fn block_by_number(&self, BlockNumber, bool) -> Result<Option<Block>, Error>;
/// Returns the number of transactions sent from given address at given time (block number). /// Returns the number of transactions sent from given address at given time (block number).
#[name("eth_getTransactionCount")] #[rpc(name = "eth_getTransactionCount")]
fn transaction_count(&self, H160, Trailing<BlockNumber>) -> Result<U256, Error>; fn transaction_count(&self, H160, Trailing<BlockNumber>) -> Result<U256, Error>;
/// Returns the number of transactions in a block with given hash. /// Returns the number of transactions in a block with given hash.
#[name("eth_getBlockTransactionCountByHash")] #[rpc(name = "eth_getBlockTransactionCountByHash")]
fn block_transaction_count_by_hash(&self, H256) -> Result<Option<U256>, Error>; fn block_transaction_count_by_hash(&self, H256) -> Result<Option<U256>, Error>;
/// Returns the number of transactions in a block with given block number. /// Returns the number of transactions in a block with given block number.
#[name("eth_getBlockTransactionCountByNumber")] #[rpc(name = "eth_getBlockTransactionCountByNumber")]
fn block_transaction_count_by_number(&self, BlockNumber) -> Result<Option<U256>, Error>; fn block_transaction_count_by_number(&self, BlockNumber) -> Result<Option<U256>, Error>;
/// Returns the number of uncles in a block with given hash. /// Returns the number of uncles in a block with given hash.
#[name("eth_getUncleCountByBlockHash")] #[rpc(name = "eth_getUncleCountByBlockHash")]
fn block_uncles_count_by_hash(&self, H256) -> Result<Option<U256>, Error>; fn block_uncles_count_by_hash(&self, H256) -> Result<Option<U256>, Error>;
/// Returns the number of uncles in a block with given block number. /// Returns the number of uncles in a block with given block number.
#[name("eth_getUncleCountByBlockNumber")] #[rpc(name = "eth_getUncleCountByBlockNumber")]
fn block_uncles_count_by_number(&self, BlockNumber) -> Result<Option<U256>, Error>; fn block_uncles_count_by_number(&self, BlockNumber) -> Result<Option<U256>, Error>;
/// Returns the code at given address at given time (block number). /// Returns the code at given address at given time (block number).
#[name("eth_getCode")] #[rpc(name = "eth_getCode")]
fn code_at(&self, H160, Trailing<BlockNumber>) -> Result<Bytes, Error>; fn code_at(&self, H160, Trailing<BlockNumber>) -> Result<Bytes, Error>;
/// Sends signed transaction, returning its hash. /// Sends signed transaction, returning its hash.
#[name("eth_sendRawTransaction")] #[rpc(name = "eth_sendRawTransaction")]
fn send_raw_transaction(&self, Bytes) -> Result<H256, Error>; fn send_raw_transaction(&self, Bytes) -> Result<H256, Error>;
/// Call contract, returning the output data. /// Call contract, returning the output data.
#[name("eth_call")] #[rpc(name = "eth_call")]
fn call(&self, CallRequest, Trailing<BlockNumber>) -> Result<Bytes, Error>; fn call(&self, CallRequest, Trailing<BlockNumber>) -> Result<Bytes, Error>;
/// Estimate gas needed for execution of given contract. /// Estimate gas needed for execution of given contract.
#[name("eth_estimateGas")] #[rpc(name = "eth_estimateGas")]
fn estimate_gas(&self, CallRequest, Trailing<BlockNumber>) -> Result<U256, Error>; fn estimate_gas(&self, CallRequest, Trailing<BlockNumber>) -> Result<U256, Error>;
/// Get transaction by its hash. /// Get transaction by its hash.
#[name("eth_getTransactionByHash")] #[rpc(name = "eth_getTransactionByHash")]
fn transaction_by_hash(&self, H256) -> Result<Option<Transaction>, Error>; fn transaction_by_hash(&self, H256) -> Result<Option<Transaction>, Error>;
/// Returns transaction at given block hash and index. /// Returns transaction at given block hash and index.
#[name("eth_getTransactionByBlockHashAndIndex")] #[rpc(name = "eth_getTransactionByBlockHashAndIndex")]
fn transaction_by_block_hash_and_index(&self, H256, Index) -> Result<Option<Transaction>, Error>; fn transaction_by_block_hash_and_index(&self, H256, Index) -> Result<Option<Transaction>, Error>;
/// Returns transaction by given block number and index. /// Returns transaction by given block number and index.
#[name("eth_getTransactionByBlockNumberAndIndex")] #[rpc(name = "eth_getTransactionByBlockNumberAndIndex")]
fn transaction_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<Transaction>, Error>; fn transaction_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<Transaction>, Error>;
/// Returns transaction receipt. /// Returns transaction receipt.
#[name("eth_getTransactionReceipt")] #[rpc(name = "eth_getTransactionReceipt")]
fn transaction_receipt(&self, H256) -> Result<Option<Receipt>, Error>; fn transaction_receipt(&self, H256) -> Result<Option<Receipt>, Error>;
/// Returns an uncles at given block and index. /// Returns an uncles at given block and index.
#[name("eth_getUncleByBlockHashAndIndex")] #[rpc(name = "eth_getUncleByBlockHashAndIndex")]
fn uncle_by_block_hash_and_index(&self, H256, Index) -> Result<Option<Block>, Error>; fn uncle_by_block_hash_and_index(&self, H256, Index) -> Result<Option<Block>, Error>;
/// Returns an uncles at given block and index. /// Returns an uncles at given block and index.
#[name("eth_getUncleByBlockNumberAndIndex")] #[rpc(name = "eth_getUncleByBlockNumberAndIndex")]
fn uncle_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<Block>, Error>; fn uncle_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<Block>, Error>;
/// Returns available compilers. /// Returns available compilers.
#[name("eth_getCompilers")] #[rpc(name = "eth_getCompilers")]
fn compilers(&self) -> Result<Vec<String>, Error>; fn compilers(&self) -> Result<Vec<String>, Error>;
/// Compiles lll code. /// Compiles lll code.
#[name("eth_compileLLL")] #[rpc(name = "eth_compileLLL")]
fn compile_lll(&self, String) -> Result<Bytes, Error>; fn compile_lll(&self, String) -> Result<Bytes, Error>;
/// Compiles solidity. /// Compiles solidity.
#[name("eth_compileSolidity")] #[rpc(name = "eth_compileSolidity")]
fn compile_solidity(&self, String) -> Result<Bytes, Error>; fn compile_solidity(&self, String) -> Result<Bytes, Error>;
/// Compiles serpent. /// Compiles serpent.
#[name("eth_compileSerpent")] #[rpc(name = "eth_compileSerpent")]
fn compile_serpent(&self, String) -> Result<Bytes, Error>; fn compile_serpent(&self, String) -> Result<Bytes, Error>;
/// Returns logs matching given filter object. /// Returns logs matching given filter object.
#[name("eth_getLogs")] #[rpc(name = "eth_getLogs")]
fn logs(&self, Filter) -> Result<Vec<Log>, Error>; fn logs(&self, Filter) -> Result<Vec<Log>, Error>;
/// Returns the hash of the current block, the seedHash, and the boundary condition to be met. /// Returns the hash of the current block, the seedHash, and the boundary condition to be met.
#[name("eth_getWork")] #[rpc(name = "eth_getWork")]
fn work(&self, Trailing<u64>) -> Result<Work, Error>; fn work(&self, Trailing<u64>) -> Result<Work, Error>;
/// Used for submitting a proof-of-work solution. /// Used for submitting a proof-of-work solution.
#[name("eth_submitWork")] #[rpc(name = "eth_submitWork")]
fn submit_work(&self, H64, H256, H256) -> Result<bool, Error>; fn submit_work(&self, H64, H256, H256) -> Result<bool, Error>;
/// Used for submitting mining hashrate. /// Used for submitting mining hashrate.
#[name("eth_submitHashrate")] #[rpc(name = "eth_submitHashrate")]
fn submit_hashrate(&self, U256, H256) -> Result<bool, Error>; fn submit_hashrate(&self, U256, H256) -> Result<bool, Error>;
} }
} }
build_rpc_trait! { build_rpc_trait! {
/// Eth filters rpc api (polling). /// Eth filters rpc api (polling).
// TODO: do filters api properly // TODO: do filters api properly
pub trait EthFilter { pub trait EthFilter {
/// Returns id of new filter. /// Returns id of new filter.
#[name("eth_newFilter")] #[rpc(name = "eth_newFilter")]
fn new_filter(&self, Filter) -> Result<U256, Error>; fn new_filter(&self, Filter) -> Result<U256, Error>;
/// Returns id of new block filter. /// Returns id of new block filter.
#[name("eth_newBlockFilter")] #[rpc(name = "eth_newBlockFilter")]
fn new_block_filter(&self) -> Result<U256, Error>; fn new_block_filter(&self) -> Result<U256, Error>;
/// Returns id of new block filter. /// Returns id of new block filter.
#[name("eth_newPendingTransactionFilter")] #[rpc(name = "eth_newPendingTransactionFilter")]
fn new_pending_transaction_filter(&self) -> Result<U256, Error>; fn new_pending_transaction_filter(&self) -> Result<U256, Error>;
/// Returns filter changes since last poll. /// Returns filter changes since last poll.
#[name("eth_getFilterChanges")] #[rpc(name = "eth_getFilterChanges")]
fn filter_changes(&self, Index) -> Result<FilterChanges, Error>; fn filter_changes(&self, Index) -> Result<FilterChanges, Error>;
/// Returns all logs matching given filter (in a range 'from' - 'to'). /// Returns all logs matching given filter (in a range 'from' - 'to').
#[name("eth_getFilterLogs")] #[rpc(name = "eth_getFilterLogs")]
fn filter_logs(&self, Index) -> Result<Vec<Log>, Error>; fn filter_logs(&self, Index) -> Result<Vec<Log>, Error>;
/// Uninstalls filter. /// Uninstalls filter.
#[name("eth_uninstallFilter")] #[rpc(name = "eth_uninstallFilter")]
fn uninstall_filter(&self, Index) -> Result<bool, Error>; fn uninstall_filter(&self, Index) -> Result<bool, Error>;
} }
} }

View File

@ -15,103 +15,107 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Ethcore-specific rpc interface. //! Ethcore-specific rpc interface.
use std::sync::Arc; use jsonrpc_core::Error;
use jsonrpc_core::*;
/// Ethcore-specific rpc interface. use v1::helpers::auto_args::{Wrap, WrapAsync, Ready};
pub trait Ethcore: Sized + Send + Sync + 'static { use v1::types::{H160, H256, H512, U256, Bytes, Peers, Transaction, RpcSettings};
/// Returns current transactions limit. build_rpc_trait! {
fn transactions_limit(&self, _: Params) -> Result<Value, Error>; /// Ethcore-specific rpc interface.
pub trait Ethcore {
/// Returns current transactions limit.
#[rpc(name = "ethcore_transactionsLimit")]
fn transactions_limit(&self) -> Result<usize, Error>;
/// Returns mining extra data. /// Returns mining extra data.
fn extra_data(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_extraData")]
fn extra_data(&self) -> Result<Bytes, Error>;
/// Returns mining gas floor target. /// Returns mining gas floor target.
fn gas_floor_target(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_gasFloorTarget")]
fn gas_floor_target(&self) -> Result<U256, Error>;
/// Returns mining gas floor cap. /// Returns mining gas floor cap.
fn gas_ceil_target(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_gasCeilTarget")]
fn gas_ceil_target(&self) -> Result<U256, Error>;
/// Returns minimal gas price for transaction to be included in queue. /// Returns minimal gas price for transaction to be included in queue.
fn min_gas_price(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_minGasPrice")]
fn min_gas_price(&self) -> Result<U256, Error>;
/// Returns latest logs /// Returns latest logs
fn dev_logs(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_devLogs")]
fn dev_logs(&self) -> Result<Vec<String>, Error>;
/// Returns logs levels /// Returns logs levels
fn dev_logs_levels(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_devLogsLevels")]
fn dev_logs_levels(&self) -> Result<String, Error>;
/// Returns chain name /// Returns chain name
fn net_chain(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_netChain")]
fn net_chain(&self) -> Result<String, Error>;
/// Returns peers details /// Returns peers details
fn net_peers(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_netPeers")]
fn net_peers(&self) -> Result<Peers, Error>;
/// Returns network port /// Returns network port
fn net_port(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_netPort")]
fn net_port(&self) -> Result<u16, Error>;
/// Returns rpc settings /// Returns rpc settings
fn rpc_settings(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_rpcSettings")]
fn rpc_settings(&self) -> Result<RpcSettings, Error>;
/// Returns node name /// Returns node name
fn node_name(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_nodeName")]
fn node_name(&self) -> Result<String, Error>;
/// Returns default extra data /// Returns default extra data
fn default_extra_data(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_defaultExtraData")]
fn default_extra_data(&self) -> Result<Bytes, Error>;
/// Returns distribution of gas price in latest blocks. /// Returns distribution of gas price in latest blocks.
fn gas_price_statistics(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_gasPriceStatistics")]
fn gas_price_statistics(&self) -> Result<Vec<U256>, Error>;
/// Returns number of unsigned transactions waiting in the signer queue (if signer enabled) /// Returns number of unsigned transactions waiting in the signer queue (if signer enabled)
/// Returns error when signer is disabled /// Returns error when signer is disabled
fn unsigned_transactions_count(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_unsignedTransactionsCount")]
fn unsigned_transactions_count(&self) -> Result<usize, Error>;
/// Returns a cryptographically random phrase sufficient for securely seeding a secret key. /// Returns a cryptographically random phrase sufficient for securely seeding a secret key.
fn generate_secret_phrase(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_generateSecretPhrase")]
fn generate_secret_phrase(&self) -> Result<String, Error>;
/// Returns whatever address would be derived from the given phrase if it were to seed a brainwallet. /// Returns whatever address would be derived from the given phrase if it were to seed a brainwallet.
fn phrase_to_address(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_phraseToAddress")]
fn phrase_to_address(&self, String) -> Result<H160, Error>;
/// Returns the value of the registrar for this network. /// Returns the value of the registrar for this network.
fn registry_address(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_registryAddress")]
fn registry_address(&self) -> Result<Option<H160>, Error>;
/// Encrypt some data with a public key under ECIES. /// Returns all addresses if Fat DB is enabled (`--fat-db`), or null if not.
/// First parameter is the 512-byte destination public key, second is the message. #[rpc(name = "ethcore_listAccounts")]
fn encrypt_message(&self, _: Params) -> Result<Value, Error>; fn list_accounts(&self) -> Result<Option<Vec<H160>>, Error>;
/// Returns all pending (current) transactions from transaction queue. /// Returns all storage keys of the given address (first parameter) if Fat DB is enabled (`--fat-db`),
fn pending_transactions(&self, _: Params) -> Result<Value, Error>; /// or null if not.
#[rpc(name = "ethcore_listStorageKeys")]
fn list_storage_keys(&self, H160) -> Result<Option<Vec<H256>>, Error>;
/// Hash a file content under given URL. /// Encrypt some data with a public key under ECIES.
fn hash_content(&self, _: Params, _: Ready); /// First parameter is the 512-byte destination public key, second is the message.
#[rpc(name = "ethcore_encryptMessage")]
fn encrypt_message(&self, H512, Bytes) -> Result<Bytes, Error>;
/// Should be used to convert object to io delegate. /// Returns all pending transactions from transaction queue.
fn to_delegate(self) -> IoDelegate<Self> { #[rpc(name = "ethcore_pendingTransactions")]
let mut delegate = IoDelegate::new(Arc::new(self)); fn pending_transactions(&self) -> Result<Vec<Transaction>, Error>;
delegate.add_method("ethcore_extraData", Ethcore::extra_data); /// Hash a file content under given URL.
delegate.add_method("ethcore_gasFloorTarget", Ethcore::gas_floor_target); #[rpc(async, name = "ethcore_hashContent")]
delegate.add_method("ethcore_gasCeilTarget", Ethcore::gas_ceil_target); fn hash_content(&self, Ready<H256>, String);
delegate.add_method("ethcore_minGasPrice", Ethcore::min_gas_price);
delegate.add_method("ethcore_transactionsLimit", Ethcore::transactions_limit);
delegate.add_method("ethcore_devLogs", Ethcore::dev_logs);
delegate.add_method("ethcore_devLogsLevels", Ethcore::dev_logs_levels);
delegate.add_method("ethcore_netChain", Ethcore::net_chain);
delegate.add_method("ethcore_netPeers", Ethcore::net_peers);
delegate.add_method("ethcore_netPort", Ethcore::net_port);
delegate.add_method("ethcore_rpcSettings", Ethcore::rpc_settings);
delegate.add_method("ethcore_nodeName", Ethcore::node_name);
delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data);
delegate.add_method("ethcore_gasPriceStatistics", Ethcore::gas_price_statistics);
delegate.add_method("ethcore_unsignedTransactionsCount", Ethcore::unsigned_transactions_count);
delegate.add_method("ethcore_generateSecretPhrase", Ethcore::generate_secret_phrase);
delegate.add_method("ethcore_phraseToAddress", Ethcore::phrase_to_address);
delegate.add_method("ethcore_registryAddress", Ethcore::registry_address);
delegate.add_method("ethcore_encryptMessage", Ethcore::encrypt_message);
delegate.add_method("ethcore_pendingTransactions", Ethcore::pending_transactions);
delegate.add_async_method("ethcore_hashContent", Ethcore::hash_content);
delegate
} }
} }

View File

@ -16,66 +16,64 @@
//! Ethcore-specific rpc interface for operations altering the settings. //! Ethcore-specific rpc interface for operations altering the settings.
use std::sync::Arc; use jsonrpc_core::Error;
use jsonrpc_core::*;
/// Ethcore-specific rpc interface for operations altering the settings. use v1::helpers::auto_args::Wrap;
pub trait EthcoreSet: Sized + Send + Sync + 'static { use v1::types::{Bytes, H160, U256};
/// Sets new minimal gas price for mined blocks. build_rpc_trait! {
fn set_min_gas_price(&self, _: Params) -> Result<Value, Error>; /// Ethcore-specific rpc interface for operations altering the settings.
pub trait EthcoreSet {
/// Sets new minimal gas price for mined blocks.
#[rpc(name = "ethcore_setMinGasPrice")]
fn set_min_gas_price(&self, U256) -> Result<bool, Error>;
/// Sets new gas floor target for mined blocks. /// Sets new gas floor target for mined blocks.
fn set_gas_floor_target(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_setGasFloorTarget")]
fn set_gas_floor_target(&self, U256) -> Result<bool, Error>;
/// Sets new gas ceiling target for mined blocks. /// Sets new gas ceiling target for mined blocks.
fn set_gas_ceil_target(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_setGasCeilTarget")]
fn set_gas_ceil_target(&self, U256) -> Result<bool, Error>;
/// Sets new extra data for mined blocks. /// Sets new extra data for mined blocks.
fn set_extra_data(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_setExtraData")]
fn set_extra_data(&self, Bytes) -> Result<bool, Error>;
/// Sets new author for mined block. /// Sets new author for mined block.
fn set_author(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_setAuthor")]
fn set_author(&self, H160) -> Result<bool, Error>;
/// Sets the limits for transaction queue. /// Sets the limits for transaction queue.
fn set_transactions_limit(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_setTransactionsLimit")]
fn set_transactions_limit(&self, usize) -> Result<bool, Error>;
/// Sets the maximum amount of gas a single transaction may consume. /// Sets the maximum amount of gas a single transaction may consume.
fn set_tx_gas_limit(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_setMaxTransactionGas")]
fn set_tx_gas_limit(&self, U256) -> Result<bool, Error>;
/// Add a reserved peer. /// Add a reserved peer.
fn add_reserved_peer(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_addReservedPeer")]
fn add_reserved_peer(&self, String) -> Result<bool, Error>;
/// Remove a reserved peer. /// Remove a reserved peer.
fn remove_reserved_peer(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_removeReservedPeer")]
fn remove_reserved_peer(&self, String) -> Result<bool, Error>;
/// Drop all non-reserved peers. /// Drop all non-reserved peers.
fn drop_non_reserved_peers(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_dropNonReservedPeers")]
fn drop_non_reserved_peers(&self) -> Result<bool, Error>;
/// Accept non-reserved peers (default behavior) /// Accept non-reserved peers (default behavior)
fn accept_non_reserved_peers(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_acceptNonReservedPeers")]
fn accept_non_reserved_peers(&self) -> Result<bool, Error>;
/// Start the network. /// Start the network.
fn start_network(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_startNetwork")]
fn start_network(&self) -> Result<bool, Error>;
/// Stop the network. /// Stop the network.
fn stop_network(&self, _: Params) -> Result<Value, Error>; #[rpc(name = "ethcore_stopNetwork")]
fn stop_network(&self) -> Result<bool, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
let mut delegate = IoDelegate::new(Arc::new(self));
delegate.add_method("ethcore_setMinGasPrice", EthcoreSet::set_min_gas_price);
delegate.add_method("ethcore_setGasFloorTarget", EthcoreSet::set_gas_floor_target);
delegate.add_method("ethcore_setGasCeilTarget", EthcoreSet::set_gas_ceil_target);
delegate.add_method("ethcore_setExtraData", EthcoreSet::set_extra_data);
delegate.add_method("ethcore_setAuthor", EthcoreSet::set_author);
delegate.add_method("ethcore_setMaxTransactionGas", EthcoreSet::set_tx_gas_limit);
delegate.add_method("ethcore_setTransactionsLimit", EthcoreSet::set_transactions_limit);
delegate.add_method("ethcore_addReservedPeer", EthcoreSet::add_reserved_peer);
delegate.add_method("ethcore_removeReservedPeer", EthcoreSet::remove_reserved_peer);
delegate.add_method("ethcore_dropNonReservedPeers", EthcoreSet::drop_non_reserved_peers);
delegate.add_method("ethcore_acceptNonReservedPeers", EthcoreSet::accept_non_reserved_peers);
delegate
} }
} }

View File

@ -15,27 +15,24 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Net rpc interface. //! Net rpc interface.
use std::sync::Arc; use jsonrpc_core::Error;
use jsonrpc_core::*;
/// Net rpc interface. use v1::helpers::auto_args::Wrap;
pub trait Net: Sized + Send + Sync + 'static {
/// Returns protocol version.
fn version(&self, _: Params) -> Result<Value, Error>;
/// Returns number of peers connected to node. build_rpc_trait! {
fn peer_count(&self, _: Params) -> Result<Value, Error>; /// Net rpc interface.
pub trait Net {
/// Returns protocol version.
#[rpc(name = "net_version")]
fn version(&self) -> Result<String, Error>;
/// Returns true if client is actively listening for network connections. /// Returns number of peers connected to node.
/// Otherwise false. #[rpc(name = "net_peerCount")]
fn is_listening(&self, _: Params) -> Result<Value, Error>; fn peer_count(&self) -> Result<String, Error>;
/// Should be used to convert object to io delegate. /// Returns true if client is actively listening for network connections.
fn to_delegate(self) -> IoDelegate<Self> { /// Otherwise false.
let mut delegate = IoDelegate::new(Arc::new(self)); #[rpc(name = "net_listening")]
delegate.add_method("net_version", Net::version); fn is_listening(&self) -> Result<bool, Error>;
delegate.add_method("net_peerCount", Net::peer_count);
delegate.add_method("net_listening", Net::is_listening);
delegate
} }
} }

View File

@ -16,26 +16,21 @@
//! RPC interface. //! RPC interface.
use std::sync::Arc; use jsonrpc_core::Error;
use jsonrpc_core::*;
/// RPC Interface. use v1::helpers::auto_args::Wrap;
pub trait Rpc: Sized + Send + Sync + 'static {
/// Returns supported modules for Geth 1.3.6 use std::collections::BTreeMap;
fn modules(&self, _: Params) -> Result<Value, Error>;
/// Returns supported modules for Geth 1.4.0 build_rpc_trait! {
fn rpc_modules(&self, _: Params) -> Result<Value, Error>; /// RPC Interface.
pub trait Rpc {
/// Returns supported modules for Geth 1.3.6
#[rpc(name = "modules")]
fn modules(&self) -> Result<BTreeMap<String, String>, Error>;
/// Should be used to convert object to io delegate. /// Returns supported modules for Geth 1.4.0
fn to_delegate(self) -> IoDelegate<Self> { #[rpc(name = "rpc_modules")]
let mut delegate = IoDelegate::new(Arc::new(self)); fn rpc_modules(&self) -> Result<BTreeMap<String, String>, Error>;
// Geth 1.3.6 compatibility
delegate.add_method("modules", Rpc::modules);
// Geth 1.4.0 compatibility
delegate.add_method("rpc_modules", Rpc::rpc_modules);
delegate
} }
} }

View File

@ -27,6 +27,7 @@ mod sync;
mod transaction; mod transaction;
mod transaction_request; mod transaction_request;
mod receipt; mod receipt;
mod rpc_settings;
mod trace; mod trace;
mod trace_filter; mod trace_filter;
mod uint; mod uint;
@ -45,6 +46,7 @@ pub use self::sync::{SyncStatus, SyncInfo, Peers};
pub use self::transaction::Transaction; pub use self::transaction::Transaction;
pub use self::transaction_request::TransactionRequest; pub use self::transaction_request::TransactionRequest;
pub use self::receipt::Receipt; pub use self::receipt::Receipt;
pub use self::rpc_settings::RpcSettings;
pub use self::trace::{LocalizedTrace, TraceResults}; pub use self::trace::{LocalizedTrace, TraceResults};
pub use self::trace_filter::TraceFilter; pub use self::trace_filter::TraceFilter;
pub use self::uint::U256; pub use self::uint::U256;

View File

@ -0,0 +1,28 @@
// 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/>.
//! RPC Settings data.
/// Values of RPC settings.
#[derive(Serialize, Deserialize)]
pub struct RpcSettings {
/// Whether RPC is enabled.
pub enabled: bool,
/// The interface being listened on.
pub interface: String,
/// The port being listened on.
pub port: u64,
}

View File

@ -32,7 +32,6 @@ impl From<std::io::Error> for Error {
} }
} }
#[derive(Ipc)]
#[ipc(client_ident="RemoteJobDispatcher")] #[ipc(client_ident="RemoteJobDispatcher")]
/// Interface that can provide pow/blockchain-specific responses for the clients /// Interface that can provide pow/blockchain-specific responses for the clients
pub trait JobDispatcher: Send + Sync { pub trait JobDispatcher: Send + Sync {
@ -44,7 +43,6 @@ pub trait JobDispatcher: Send + Sync {
fn job(&self, _worker_id: String) -> Option<String> { None } fn job(&self, _worker_id: String) -> Option<String> { None }
} }
#[derive(Ipc)]
#[ipc(client_ident="RemoteWorkHandler")] #[ipc(client_ident="RemoteWorkHandler")]
/// Interface that can handle requests to push job for workers /// Interface that can handle requests to push job for workers
pub trait PushWorkHandler: Send + Sync { pub trait PushWorkHandler: Send + Sync {

View File

@ -29,5 +29,6 @@ ethcore-ipc-nano = { path = "../ipc/nano" }
parking_lot = "0.2.6" parking_lot = "0.2.6"
[features] [features]
default = [] default = ["ipc"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev"]
ipc = []

View File

@ -98,7 +98,6 @@ impl EthSync {
} }
} }
#[derive(Ipc)]
#[ipc(client_ident="SyncClient")] #[ipc(client_ident="SyncClient")]
impl SyncProvider for EthSync { impl SyncProvider for EthSync {
/// Get sync status /// Get sync status
@ -232,7 +231,6 @@ pub trait ManageNetwork : Send + Sync {
} }
#[derive(Ipc)]
#[ipc(client_ident="NetworkManagerClient")] #[ipc(client_ident="NetworkManagerClient")]
impl ManageNetwork for EthSync { impl ManageNetwork for EthSync {
fn accept_unreserved_peers(&self) { fn accept_unreserved_peers(&self) {

View File

@ -34,6 +34,7 @@ using_queue = { path = "using_queue" }
table = { path = "table" } table = { path = "table" }
ansi_term = "0.7" ansi_term = "0.7"
tiny-keccak= "1.0" tiny-keccak= "1.0"
ethcore-bloom-journal = { path = "bloom" }
[features] [features]
default = [] default = []

9
util/bloom/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[project]
name = "ethcore-bloom-journal"
version = "0.1.0"
authors = ["Ethcore<admin@ethcore.io>"]
description = "Journaling bloom filter"
license = "GPL3"
[lib]
path = "src/lib.rs"

247
util/bloom/src/lib.rs Normal file
View File

@ -0,0 +1,247 @@
// 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::cmp;
use std::mem;
use std::f64;
use std::hash::{Hash, Hasher, SipHasher};
use std::collections::HashSet;
/// BitVec structure with journalling
/// Every time any of the blocks is getting set it's index is tracked
/// and can be then drained by `drain` method
struct BitVecJournal {
elems: Vec<u64>,
journal: HashSet<usize>,
}
impl BitVecJournal {
pub fn new(size: usize) -> BitVecJournal {
let extra = if size % 8 > 0 { 1 } else { 0 };
BitVecJournal {
elems: vec![0u64; size / 8 + extra],
journal: HashSet::new(),
}
}
pub fn from_parts(parts: &[u64]) -> BitVecJournal {
BitVecJournal {
elems: parts.to_vec(),
journal: HashSet::new(),
}
}
pub fn set(&mut self, index: usize) {
let e_index = index / 64;
let bit_index = index % 64;
let val = self.elems.get_mut(e_index).unwrap();
*val |= 1u64 << bit_index;
self.journal.insert(e_index);
}
pub fn get(&self, index: usize) -> bool {
let e_index = index / 64;
let bit_index = index % 64;
self.elems[e_index] & (1 << bit_index) != 0
}
pub fn drain(&mut self) -> Vec<(usize, u64)> {
let journal = mem::replace(&mut self.journal, HashSet::new()).into_iter();
journal.map(|idx| (idx, self.elems[idx])).collect::<Vec<(usize, u64)>>()
}
pub fn saturation(&self) -> f64 {
self.elems.iter().fold(0u64, |acc, e| acc + e.count_ones() as u64) as f64 / (self.elems.len() * 64) as f64
}
}
/// Bloom filter structure
pub struct Bloom {
bitmap: BitVecJournal,
bitmap_bits: u64,
k_num: u32,
sips: [SipHasher; 2],
}
impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
assert!(bitmap_size > 0 && items_count > 0);
let bitmap_bits = (bitmap_size as u64) * 8u64;
let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
let bitmap = BitVecJournal::new(bitmap_bits as usize);
let sips = [Bloom::sip_new(), Bloom::sip_new()];
Bloom {
bitmap: bitmap,
bitmap_bits: bitmap_bits,
k_num: k_num,
sips: sips,
}
}
/// Initializes bloom filter from saved state
pub fn from_parts(parts: &[u64], k_num: u32) -> Bloom {
let bitmap_size = parts.len() * 8;
let bitmap_bits = (bitmap_size as u64) * 8u64;
let bitmap = BitVecJournal::from_parts(parts);
let sips = [Bloom::sip_new(), Bloom::sip_new()];
Bloom {
bitmap: bitmap,
bitmap_bits: bitmap_bits,
k_num: k_num,
sips: sips,
}
}
/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
Bloom::new(bitmap_size, items_count)
}
/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
assert!(items_count > 0);
assert!(fp_p > 0.0 && fp_p < 1.0);
let log2 = f64::consts::LN_2;
let log2_2 = log2 * log2;
((items_count as f64) * f64::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
}
/// Records the presence of an item.
pub fn set<T>(&mut self, item: T)
where T: Hash
{
let mut hashes = [0u64, 0u64];
for k_i in 0..self.k_num {
let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
self.bitmap.set(bit_offset);
}
}
/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
pub fn check<T>(&self, item: T) -> bool
where T: Hash
{
let mut hashes = [0u64, 0u64];
for k_i in 0..self.k_num {
let bit_offset = (self.bloom_hash(&mut hashes, &item, k_i) % self.bitmap_bits) as usize;
if !self.bitmap.get(bit_offset) {
return false;
}
}
true
}
/// Return the number of bits in the filter
pub fn number_of_bits(&self) -> u64 {
self.bitmap_bits
}
/// Return the number of hash functions used for `check` and `set`
pub fn number_of_hash_functions(&self) -> u32 {
self.k_num
}
fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
let m = bitmap_bits as f64;
let n = items_count as f64;
let k_num = (m / n * f64::ln(2.0f64)).ceil() as u32;
cmp::max(k_num, 1)
}
fn bloom_hash<T>(&self, hashes: &mut [u64; 2], item: &T, k_i: u32) -> u64
where T: Hash
{
if k_i < 2 {
let sip = &mut self.sips[k_i as usize].clone();
item.hash(sip);
let hash = sip.finish();
hashes[k_i as usize] = hash;
hash
} else {
hashes[0].wrapping_add((k_i as u64).wrapping_mul(hashes[1]) % 0xffffffffffffffc5)
}
}
fn sip_new() -> SipHasher {
SipHasher::new()
}
/// Drains the bloom journal returning the updated bloom part
pub fn drain_journal(&mut self) -> BloomJournal {
BloomJournal {
entries: self.bitmap.drain(),
hash_functions: self.k_num,
}
}
/// Returns the ratio of set bits in the bloom filter to the total bits
pub fn saturation(&self) -> f64 {
self.bitmap.saturation()
}
}
/// Bloom journal
/// Returns the tuple of (bloom part index, bloom part value) where each one is representing
/// an index of bloom parts that was updated since the last drain
pub struct BloomJournal {
pub hash_functions: u32,
pub entries: Vec<(usize, u64)>,
}
#[cfg(test)]
mod tests {
use super::Bloom;
#[test]
fn get_set() {
let mut bloom = Bloom::new(10, 80);
let key = vec![115u8, 99];
assert!(!bloom.check(&key));
bloom.set(&key);
assert!(bloom.check(&key));
}
#[test]
fn journalling() {
let initial = vec![0u64; 8];
let mut bloom = Bloom::from_parts(&initial, 3);
bloom.set(&vec![5u8, 4]);
let drain = bloom.drain_journal();
assert_eq!(2, drain.entries.len())
}
#[test]
fn saturation() {
let initial = vec![0u64; 8];
let mut bloom = Bloom::from_parts(&initial, 3);
bloom.set(&vec![5u8, 4]);
let full = bloom.saturation();
// 2/8/64 = 0.00390625
assert!(full >= 0.0039f64 && full <= 0.004f64);
}
}

View File

@ -22,6 +22,7 @@ use std::collections::BTreeMap;
use std::fs; use std::fs;
use std::fmt; use std::fmt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc;
use ::kvdb::{CompactionProfile, Database, DatabaseConfig, DBTransaction}; use ::kvdb::{CompactionProfile, Database, DatabaseConfig, DBTransaction};
@ -114,6 +115,12 @@ impl From<::std::io::Error> for Error {
} }
} }
impl From<String> for Error {
fn from(e: String) -> Self {
Error::Custom(e)
}
}
/// A generalized migration from the given db to a destination db. /// A generalized migration from the given db to a destination db.
pub trait Migration: 'static { pub trait Migration: 'static {
/// Number of columns in the database before the migration. /// Number of columns in the database before the migration.
@ -123,7 +130,7 @@ pub trait Migration: 'static {
/// Version of the database after the migration. /// Version of the database after the migration.
fn version(&self) -> u32; fn version(&self) -> u32;
/// Migrate a source to a destination. /// Migrate a source to a destination.
fn migrate(&mut self, source: &Database, config: &Config, destination: &mut Database, col: Option<u32>) -> Result<(), Error>; fn migrate(&mut self, source: Arc<Database>, config: &Config, destination: &mut Database, col: Option<u32>) -> Result<(), Error>;
} }
/// A simple migration over key-value pairs. /// A simple migration over key-value pairs.
@ -142,7 +149,7 @@ impl<T: SimpleMigration> Migration for T {
fn version(&self) -> u32 { SimpleMigration::version(self) } fn version(&self) -> u32 { SimpleMigration::version(self) }
fn migrate(&mut self, source: &Database, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> { fn migrate(&mut self, source: Arc<Database>, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> {
let mut batch = Batch::new(config, col); let mut batch = Batch::new(config, col);
for (key, value) in source.iter(col) { for (key, value) in source.iter(col) {
@ -221,10 +228,12 @@ impl Manager {
pub fn execute(&mut self, old_path: &Path, version: u32) -> Result<PathBuf, Error> { pub fn execute(&mut self, old_path: &Path, version: u32) -> Result<PathBuf, Error> {
let config = self.config.clone(); let config = self.config.clone();
let migrations = self.migrations_from(version); let migrations = self.migrations_from(version);
trace!(target: "migration", "Total migrations to execute for version {}: {}", version, migrations.len());
if migrations.is_empty() { return Err(Error::MigrationImpossible) }; if migrations.is_empty() { return Err(Error::MigrationImpossible) };
let columns = migrations.iter().find(|m| m.version() == version).and_then(|m| m.pre_columns()); let columns = migrations.iter().nth(0).and_then(|m| m.pre_columns());
trace!(target: "migration", "Expecting database to contain {:?} columns", columns);
let mut db_config = DatabaseConfig { let mut db_config = DatabaseConfig {
max_open_files: 64, max_open_files: 64,
cache_sizes: Default::default(), cache_sizes: Default::default(),
@ -239,7 +248,7 @@ impl Manager {
// start with the old db. // start with the old db.
let old_path_str = try!(old_path.to_str().ok_or(Error::MigrationImpossible)); let old_path_str = try!(old_path.to_str().ok_or(Error::MigrationImpossible));
let mut cur_db = try!(Database::open(&db_config, old_path_str).map_err(Error::Custom)); let mut cur_db = Arc::new(try!(Database::open(&db_config, old_path_str).map_err(Error::Custom)));
for migration in migrations { for migration in migrations {
// Change number of columns in new db // Change number of columns in new db
@ -254,16 +263,16 @@ impl Manager {
// perform the migration from cur_db to new_db. // perform the migration from cur_db to new_db.
match current_columns { match current_columns {
// migrate only default column // migrate only default column
None => try!(migration.migrate(&cur_db, &config, &mut new_db, None)), None => try!(migration.migrate(cur_db.clone(), &config, &mut new_db, None)),
Some(v) => { Some(v) => {
// Migrate all columns in previous DB // Migrate all columns in previous DB
for col in 0..v { for col in 0..v {
try!(migration.migrate(&cur_db, &config, &mut new_db, Some(col))) try!(migration.migrate(cur_db.clone(), &config, &mut new_db, Some(col)))
} }
} }
} }
// next iteration, we will migrate from this db into the other temp. // next iteration, we will migrate from this db into the other temp.
cur_db = new_db; cur_db = Arc::new(new_db);
temp_idx.swap(); temp_idx.swap();
// remove the other temporary migration database. // remove the other temporary migration database.

View File

@ -91,7 +91,7 @@ impl Migration for AddsColumn {
fn version(&self) -> u32 { 1 } fn version(&self) -> u32 { 1 }
fn migrate(&mut self, source: &Database, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> { fn migrate(&mut self, source: Arc<Database>, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> {
let mut batch = Batch::new(config, col); let mut batch = Batch::new(config, col);
for (key, value) in source.iter(col) { for (key, value) in source.iter(col) {

View File

@ -23,7 +23,7 @@ use target_info::Target;
include!(concat!(env!("OUT_DIR"), "/version.rs")); include!(concat!(env!("OUT_DIR"), "/version.rs"));
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
#[derive(PartialEq,Eq,Clone,Copy)] #[derive(PartialEq, Eq, Clone, Copy, Debug)]
/// Boolean type for clean/dirty status. /// Boolean type for clean/dirty status.
pub enum Filth { pub enum Filth {
/// Data has not been changed. /// Data has not been changed.

View File

@ -46,4 +46,4 @@ pub use rustc_serialize::hex::{FromHex, FromHexError};
pub use heapsize::HeapSizeOf; pub use heapsize::HeapSizeOf;
pub use itertools::Itertools; pub use itertools::Itertools;
pub use parking_lot::{Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; pub use parking_lot::{Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};

View File

@ -233,4 +233,7 @@ impl TrieFactory {
TrieSpec::Fat => Ok(Box::new(try!(FatDBMut::from_existing(db, root)))), TrieSpec::Fat => Ok(Box::new(try!(FatDBMut::from_existing(db, root)))),
} }
} }
/// Returns true iff the trie DB is a fat DB (allows enumeration of keys).
pub fn is_fat(&self) -> bool { self.spec == TrieSpec::Fat }
} }