Compare commits

...

5 Commits

Author SHA1 Message Date
Arkadiy Paronyan
425e1ce04c Check pruning by db modification date (#1924) 2016-08-12 17:48:11 +02:00
Tomasz Drwięga
8741d0d155 Bumping Parity UI (#1920) 2016-08-12 12:58:31 +02:00
Arkadiy Paronyan
dfb2ddfdc2 Backports to beta (#1919)
* RPC errors & logs (#1845)

* Refactoring errors in RPC

* Updating jsonrpc-core

* Fixing code_at

* Avoid mentioning obvious segments in proof

[ci:skip]

* fixed cache_manager lock order

* Purging .derefs, fixing clippy warnings. (#1890)

* Fixing clippy warnings

* Purging derefs

* Simplifying engine derefs

* Simplifying more engine derefs

* Adding more details to miner log

* fixed #1889, .DS_Store is no longer treated as key file (#1892)

* fixed #1889, .DS_Store is no longer treated as key file

* ethstore filters directories, hidden files and common system files

* fixed compiling

* fix regression with geth dir

* fix regression with geth dir

* Fix ipc compilation and add ipc feature to test targets (#1902)

* fix compilation and add it to the ci run

* no separator?

* use quotes and spaces

* RocksDB version bump

* Don't return deleted nodes that are not yet flushed (#1908)

* polling & connection timeouts (#1910)

* Peers RPC + UI displaying active/connected/max peers (#1915)

* Peers API

* Bumping Parity-UI

* Fixing tests

* Save nodes removed from backing_overlay until commit (#1917)
2016-08-12 12:16:20 +02:00
Arkadiy Paronyan
52ac5a00f5 Backports for beta (#1888)
* Sync to peers with confirmed fork block only (#1863)

* Fixing gas conversion

* Validating u256->usize conversion

* Update cache usage on commiting block info (#1871)

* Use UntrustedRlp for block verification (#1872)

* take snapshot at specified block and slightly better informants (#1873)

* prettier informant for snapshot creation

* allow taking snapshot at a given block

* minor tweaks

* elaborate on cli

* Send new block hashes to all peers (#1875)

* Reduce max open files (#1876)

* ws-rs update

* Fixing test

* Fixing miner deadlock (#1885)
2016-08-09 14:05:02 +02:00
arkpar
6336bdecf3 Version set to beta 2016-08-06 08:08:27 +02:00
86 changed files with 1480 additions and 992 deletions

177
Cargo.lock generated
View File

@@ -113,14 +113,17 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "0.5.2"
name = "bytes"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
version = "0.4.0-dev"
source = "git+https://github.com/carllerche/bytes#6529f6392a9717585b8d67e1db96e6fa0fb6cb1f"
dependencies = [
"stable-heap 0.1.0 (git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47)",
]
[[package]]
name = "cfg-if"
@@ -155,7 +158,7 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -274,21 +277,21 @@ dependencies = [
"ethcore-rpc 1.3.0",
"ethcore-util 1.3.0",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-home 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-status 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-wallet 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-home 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-status 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-wallet 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -414,7 +417,7 @@ dependencies = [
"ethjson 0.1.0",
"ethsync 1.3.0",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -434,12 +437,12 @@ dependencies = [
"ethcore-io 1.3.0",
"ethcore-rpc 1.3.0",
"ethcore-util 1.3.0",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps-signer 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ws 0.5.0 (git+https://github.com/ethcore/ws-rs.git?branch=stable)",
"ws 0.5.2 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)",
]
[[package]]
@@ -614,7 +617,7 @@ dependencies = [
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -635,7 +638,7 @@ dependencies = [
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -682,23 +685,23 @@ source = "git+https://github.com/ethcore/json-ipc-server.git#56b6307130710ebc73c
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-core"
version = "2.0.7"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -707,7 +710,7 @@ version = "6.1.0"
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#4e3f93eb79125e91a46e04d77c25ff8885498b86"
dependencies = [
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -780,7 +783,7 @@ dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -796,7 +799,7 @@ dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -804,9 +807,24 @@ dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.6.0-dev"
source = "git+https://github.com/carllerche/mio?rev=62ec763c9cc34d8a452ed0392c575c50ddd5fc8d#62ec763c9cc34d8a452ed0392c575c50ddd5fc8d"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -854,6 +872,19 @@ dependencies = [
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nodrop"
version = "0.1.6"
@@ -956,8 +987,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parity-dapps"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -970,34 +1001,34 @@ dependencies = [
[[package]]
name = "parity-dapps-home"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-signer"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-status"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-wallet"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
@@ -1152,7 +1183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rocksdb"
version = "0.4.5"
source = "git+https://github.com/ethcore/rust-rocksdb#eadce7f74cfe92b99ce63a77af425b47857239b8"
source = "git+https://github.com/ethcore/rust-rocksdb#84c5ac0bbd6901b6279a5480708e93eb3da6caa4"
dependencies = [
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
@@ -1161,7 +1192,7 @@ dependencies = [
[[package]]
name = "rocksdb-sys"
version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#eadce7f74cfe92b99ce63a77af425b47857239b8"
source = "git+https://github.com/ethcore/rust-rocksdb#84c5ac0bbd6901b6279a5480708e93eb3da6caa4"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1255,11 +1286,8 @@ dependencies = [
[[package]]
name = "sha1"
version = "0.1.1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sha3"
@@ -1273,6 +1301,11 @@ name = "slab"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.2.0"
source = "git+https://github.com/carllerche/slab?rev=5476efcafb#5476efcafbc5ef4d7315b1bea3f756d8a1fe975e"
[[package]]
name = "slab"
version = "0.2.0"
@@ -1297,6 +1330,11 @@ name = "spmc"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stable-heap"
version = "0.1.0"
source = "git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47#3c5cd1ca4706f167a1de85658b5af0d6d3e65165"
[[package]]
name = "strsim"
version = "0.3.0"
@@ -1447,7 +1485,7 @@ dependencies = [
[[package]]
name = "url"
version = "1.1.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1506,15 +1544,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws"
version = "0.5.0"
source = "git+https://github.com/ethcore/ws-rs.git?branch=stable#a876fc115c3ef50a17c8822c9bd2f6e94473e005"
version = "0.5.2"
source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#afbff59776ce16ccec5ee9e218b8891830ee6fdf"
dependencies = [
"bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)",
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
"mio 0.6.0-dev (git+https://github.com/carllerche/mio?rev=62ec763c9cc34d8a452ed0392c575c50ddd5fc8d)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1549,16 +1589,13 @@ dependencies = [
"checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a"
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
"checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c"
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
"checksum bitflags 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "72cd7314bd4ee024071241147222c706e80385a1605ac7d4cd2fcc339da2ae46"
"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 byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e68d0b3b234a583993a53d5b0063fb5fe8713590fe733d41b98a2cee6a9c26e"
"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 cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum chrono 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "a714b6792cb4bb07643c35d2a051d92988d4e296322a60825549dd0764bcd396"
"checksum clippy 0.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "e96469b413984c78285727f94f9c626a1f2006cecdcf813b5d6893c0c85df42f"
"checksum clippy_lints 0.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "f11938c4b10c556903bb1c1e717eb038658324bf7197e4cfc159a16417327345"
"checksum cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90266f45846f14a1e986c77d1e9c2626b8c342ed806fe60241ec38cc8697b245"
@@ -1577,13 +1614,14 @@ dependencies = [
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
"checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae"
"checksum hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb0f4d00bb781e559b6e66ae4b5479df0fdf9ab15949f52fa2f1f5de16d4cc07"
"checksum hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "eb27e8a3e8f17ac43ffa41bbda9cf5ad3f9f13ef66fa4873409d4902310275f7"
"checksum hyper 0.9.4 (git+https://github.com/ethcore/hyper)" = "<none>"
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
"checksum igd 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5b93df68d6152576e9bc9f371e33e00b40738d528b3566ff41ea11d04401dc"
"checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484"
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
"checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76"
"checksum json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)" = "<none>"
"checksum jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "91755680900913f73576065c85359ee793ac3883bc461dbca90fc4a603be84cc"
"checksum jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec4477e4e8218da23caa5dd31f4eb39999aa0ea9035660617eccfb19a23bf5ad"
"checksum jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)" = "<none>"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
@@ -1596,11 +1634,13 @@ dependencies = [
"checksum mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e50bf542f81754ef69e5cea856946a3819f7c09ea97b4903c8bc8a89f74e7b6"
"checksum mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)" = "<none>"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4e93d633d34b8ff65a24566d67d49703e7a5c7ac2844d6139a9fc441a799e89a"
"checksum mio 0.6.0-dev (git+https://github.com/carllerche/mio?rev=62ec763c9cc34d8a452ed0392c575c50ddd5fc8d)" = "<none>"
"checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a"
"checksum nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>"
"checksum nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>"
"checksum net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a816012ca11cb47009693c1e0c6130e26d39e4d97ee2a13c50e868ec83e3204"
"checksum nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f05c2fc965fc1cd6b73fa57fa7b89f288178737f2f3ce9e63e4a6a141189000e"
"checksum nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a7bb1da2be7da3cbffda73fc681d509ffd9e665af478d2bee1907cee0bc64b2"
"checksum nodrop 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4d9a22dbcebdeef7bf275cbf444d6521d4e7a2fee187b72d80dba0817120dd8f"
"checksum nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6caab12c5f97aa316cb249725aa32115118e1522b445e26c257dd77cad5ffd4e"
"checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2"
@@ -1613,11 +1653,11 @@ dependencies = [
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
"checksum number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "084d05f4bf60621a9ac9bde941a410df548f4de9545f06e5ee9d3aef4b97cd77"
"checksum odds 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "b28c06e81b0f789122d415d6394b5fe849bde8067469f4c2980d3cdc10c78ec1"
"checksum parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-home 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-signer 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-status 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-wallet 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-home 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-status 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-wallet 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parking_lot 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0fd1be2c3cf5fef20a6d18fec252c4f3c87c14fc3039002eb7d4ed91e436826"
"checksum phf 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "447d9d45f2e0b4a9b532e808365abf18fc211be6ca217202fcd45236ef12f026"
"checksum phf_codegen 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8af7ae7c3f75a502292b491e5cc0a1f69e3407744abe6e57e2a3b712bb82f01d"
@@ -1648,12 +1688,14 @@ dependencies = [
"checksum serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b76133a8a02f1c6ebd3fb9a2ecaab3d54302565a51320e80931adba571aadb1b"
"checksum serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c5b74ff4fb34013cc0b917dd182fefc05ee9af233b9d0d557078334554284d0e"
"checksum serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c88a751caa8f0000058fb971cd443ed2e6b653f33f5a47f29892a8bd44ca4c1"
"checksum sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a307a40d5834140e4213a6952483b84e9ad53bdcab918b7335a6e305e505a53c"
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
"checksum slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)" = "<none>"
"checksum slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6dbdd334bd28d328dad1c41b0ea662517883d8880d8533895ef96c8003dec9c4"
"checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
"checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2"
"checksum spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93bdab61c1a413e591c4d17388ffa859eaff2df27f1e13a5ec8b716700605adf"
"checksum stable-heap 0.1.0 (git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47)" = "<none>"
"checksum strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825"
"checksum syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393b6dd0889df2b064beeea954cfda6bc2571604ac460deeae0fed55a53988af"
"checksum syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44bded3cabafc65c90b663b1071bd2d198a9ab7515e6ce729e4570aaf53c407e"
@@ -1673,7 +1715,7 @@ dependencies = [
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb"
"checksum url 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f6d04073d0fcd045a1cf57aea560d1be5ba812d8f28814e1e1cf0e90ff4d2f03"
"checksum url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8ab4ca6f0107350f41a59a51cb0e71a04d905bc6a29181d2cb42fa4f040c65c9"
"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum uuid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9767696a9e1bc7a73f2d5f8e0f5428b076cecd9199c200c0364aa0b2d57b8dfa"
"checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24"
@@ -1681,8 +1723,7 @@ dependencies = [
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum ws 0.5.0 (git+https://github.com/ethcore/ws-rs.git?branch=stable)" = "<none>"
"checksum ws 0.5.2 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)" = "<none>"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac8fd82b24db2dd3b54aa7b29f336d8b5ca1830065ce3aada71bce6f661519"
"checksum xml-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f11ef7864e55d06a38755beaf03ab70139a04e619acfe94ef800b11bd79eb52c"
"checksum xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "65e74b96bd3179209dc70a980da6df843dff09e46eee103a0376c0949257e3ef"
"checksum xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "472a9d37c7c53ab2391161df5b89b1f3bf76dab6ab150d7941ecbdd832282082"

View File

@@ -10,7 +10,7 @@ build = "build.rs"
[dependencies]
log = "0.3"
jsonrpc-core = "2.0"
jsonrpc-core = "2.1"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
unicase = "1.3"
@@ -21,11 +21,11 @@ serde_json = "0.7.0"
serde_macros = { version = "0.7.0", optional = true }
ethcore-rpc = { path = "../rpc" }
ethcore-util = { path = "../util" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
# List of apps
parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6", optional = true }
parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true }
mime_guess = { version = "1.6.1" }
clippy = { version = "0.0.80", optional = true}

View File

@@ -582,23 +582,22 @@ mod tests {
fn open_block() {
use spec::*;
let spec = Spec::new_test();
let engine = &spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(&*spec.engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]);
let _ = b.seal(&*spec.engine, vec![]);
}
#[test]
fn enact_block() {
use spec::*;
let spec = Spec::new_test();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
@@ -606,15 +605,15 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
@@ -627,7 +626,7 @@ mod tests {
fn enact_block_with_uncle() {
use spec::*;
let spec = Spec::new_test();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
@@ -635,14 +634,14 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut open_block = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();
uncle2_header.extra_data = b"uncle2".to_vec();
open_block.push_uncle(uncle1_header).unwrap();
open_block.push_uncle(uncle2_header).unwrap();
let b = open_block.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let b = open_block.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
@@ -650,7 +649,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);

View File

@@ -133,8 +133,9 @@ enum CacheID {
impl bc::group::BloomGroupDatabase for BlockChain {
fn blooms_at(&self, position: &bc::group::GroupPosition) -> Option<bc::group::BloomGroup> {
let position = LogGroupPosition::from(position.clone());
self.note_used(CacheID::BlocksBlooms(position.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.blocks_blooms, &position).map(Into::into)
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.blocks_blooms, &position).map(Into::into);
self.note_used(CacheID::BlocksBlooms(position));
result
}
}
@@ -211,9 +212,7 @@ impl BlockProvider for BlockChain {
let opt = self.db.get(DB_COL_HEADERS, hash)
.expect("Low level database error. Some issue with disk?");
self.note_used(CacheID::BlockHeader(hash.clone()));
match opt {
let result = match opt {
Some(b) => {
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
let mut write = self.block_headers.write();
@@ -221,7 +220,10 @@ impl BlockProvider for BlockChain {
Some(bytes)
},
None => None
}
};
self.note_used(CacheID::BlockHeader(hash.clone()));
result
}
/// Get block body data
@@ -246,9 +248,7 @@ impl BlockProvider for BlockChain {
let opt = self.db.get(DB_COL_BODIES, hash)
.expect("Low level database error. Some issue with disk?");
self.note_used(CacheID::BlockBody(hash.clone()));
match opt {
let result = match opt {
Some(b) => {
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
let mut write = self.block_bodies.write();
@@ -256,31 +256,39 @@ impl BlockProvider for BlockChain {
Some(bytes)
},
None => None
}
};
self.note_used(CacheID::BlockBody(hash.clone()));
result
}
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_details, hash);
self.note_used(CacheID::BlockDetails(hash.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.block_details, hash)
result
}
/// Get the hash of given block's number.
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_hashes, &index);
self.note_used(CacheID::BlockHashes(index));
self.db.read_with_cache(DB_COL_EXTRA, &self.block_hashes, &index)
result
}
/// Get the address of transaction with given hash.
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.transaction_addresses, hash);
self.note_used(CacheID::TransactionAddresses(hash.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.transaction_addresses, hash)
result
}
/// Get receipts of block with given hash.
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_receipts, hash);
self.note_used(CacheID::BlockReceipts(hash.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.block_receipts, hash)
result
}
/// Returns numbers of blocks containing given bloom.
@@ -635,11 +643,12 @@ impl BlockChain {
let mut update = HashMap::new();
update.insert(block_hash, parent_details);
self.note_used(CacheID::BlockDetails(block_hash));
let mut write_details = self.block_details.write();
batch.extend_with_cache(DB_COL_EXTRA, &mut *write_details, update, CacheUpdatePolicy::Overwrite);
self.note_used(CacheID::BlockDetails(block_hash));
self.db.write(batch).unwrap();
}
@@ -730,12 +739,14 @@ impl BlockChain {
/// Prepares extras update.
fn prepare_update(&self, batch: &DBTransaction, update: ExtrasUpdate, is_best: bool) {
{
for hash in update.block_details.keys().cloned() {
self.note_used(CacheID::BlockDetails(hash));
}
let block_hashes: Vec<_> = update.block_details.keys().cloned().collect();
let mut write_details = self.block_details.write();
batch.extend_with_cache(DB_COL_EXTRA, &mut *write_details, update.block_details, CacheUpdatePolicy::Overwrite);
for hash in block_hashes.into_iter() {
self.note_used(CacheID::BlockDetails(hash));
}
}
{
@@ -775,19 +786,31 @@ impl BlockChain {
/// Applt pending insertion updates
pub fn commit(&self) {
let mut best_block = self.best_block.write();
let mut write_hashes = self.block_hashes.write();
let mut write_txs = self.transaction_addresses.write();
let mut pending_best_block = self.pending_best_block.write();
let mut pending_write_hashes = self.pending_block_hashes.write();
let mut pending_write_txs = self.pending_transaction_addresses.write();
let mut best_block = self.best_block.write();
let mut write_hashes = self.block_hashes.write();
let mut write_txs = self.transaction_addresses.write();
// update best block
if let Some(block) = pending_best_block.take() {
*best_block = block;
}
let pending_hashes_keys: Vec<_> = pending_write_hashes.keys().cloned().collect();
let pending_txs_keys: Vec<_> = pending_write_txs.keys().cloned().collect();
write_hashes.extend(mem::replace(&mut *pending_write_hashes, HashMap::new()));
write_txs.extend(mem::replace(&mut *pending_write_txs, HashMap::new()));
for n in pending_hashes_keys.into_iter() {
self.note_used(CacheID::BlockHashes(n));
}
for hash in pending_txs_keys.into_iter() {
self.note_used(CacheID::TransactionAddresses(hash));
}
}
/// Iterator that lists `first` and then all of `first`'s ancestors, by hash.
@@ -992,16 +1015,18 @@ impl BlockChain {
/// Ticks our cache system and throws out any old data.
pub fn collect_garbage(&self) {
let mut cache_man = self.cache_man.write();
cache_man.collect_garbage(|| self.cache_size().total(), | ids | {
let mut block_headers = self.block_headers.write();
let mut block_bodies = self.block_bodies.write();
let mut block_details = self.block_details.write();
let mut block_hashes = self.block_hashes.write();
let mut transaction_addresses = self.transaction_addresses.write();
let mut blocks_blooms = self.blocks_blooms.write();
let mut block_receipts = self.block_receipts.write();
let current_size = self.cache_size().total();
let mut block_headers = self.block_headers.write();
let mut block_bodies = self.block_bodies.write();
let mut block_details = self.block_details.write();
let mut block_hashes = self.block_hashes.write();
let mut transaction_addresses = self.transaction_addresses.write();
let mut blocks_blooms = self.blocks_blooms.write();
let mut block_receipts = self.block_receipts.write();
let mut cache_man = self.cache_man.write();
cache_man.collect_garbage(current_size, | ids | {
for id in &ids {
match *id {
CacheID::BlockHeader(ref h) => { block_headers.remove(h); },
@@ -1013,6 +1038,7 @@ impl BlockChain {
CacheID::BlockReceipts(ref h) => { block_receipts.remove(h); }
}
}
block_headers.shrink_to_fit();
block_bodies.shrink_to_fit();
block_details.shrink_to_fit();
@@ -1020,6 +1046,14 @@ impl BlockChain {
transaction_addresses.shrink_to_fit();
blocks_blooms.shrink_to_fit();
block_receipts.shrink_to_fit();
block_headers.heap_size_of_children() +
block_bodies.heap_size_of_children() +
block_details.heap_size_of_children() +
block_hashes.heap_size_of_children() +
transaction_addresses.heap_size_of_children() +
blocks_blooms.heap_size_of_children() +
block_receipts.heap_size_of_children()
});
}

View File

@@ -45,16 +45,19 @@ impl<T> CacheManager<T> where T: Eq + Hash {
}
}
pub fn collect_garbage<C, F>(&mut self, current_size: C, mut notify_unused: F) where C: Fn() -> usize, F: FnMut(HashSet<T>) {
if current_size() < self.pref_cache_size {
/// Collects unused objects from cache.
/// First params is the current size of the cache.
/// Second one is an with objects to remove. It should also return new size of the cache.
pub fn collect_garbage<F>(&mut self, current_size: usize, mut notify_unused: F) where F: FnMut(HashSet<T>) -> usize {
if current_size < self.pref_cache_size {
self.rotate_cache_if_needed();
return;
}
for _ in 0..COLLECTION_QUEUE_SIZE {
notify_unused(self.cache_usage.pop_back().unwrap());
let current_size = notify_unused(self.cache_usage.pop_back().unwrap());
self.cache_usage.push_front(Default::default());
if current_size() < self.max_cache_size {
if current_size < self.max_cache_size {
break;
}
}

View File

@@ -594,19 +594,35 @@ impl Client {
}
}
/// Take a snapshot.
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W) -> Result<(), ::error::Error> {
/// Take a snapshot at the given block.
/// If the ID given is "latest", this will default to 1000 blocks behind.
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockID, p: &snapshot::Progress) -> Result<(), ::error::Error> {
let db = self.state_db.lock().boxed_clone();
let best_block_number = self.chain_info().best_block_number;
let start_block_number = if best_block_number > 1000 {
best_block_number - 1000
} else {
0
};
let start_hash = self.block_hash(BlockID::Number(start_block_number))
.expect("blocks within HISTORY are always stored.");
let block_number = try!(self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at)));
try!(snapshot::take_snapshot(&self.chain, start_hash, db.as_hashdb(), writer));
if best_block_number > HISTORY + block_number && db.is_pruned() {
return Err(snapshot::Error::OldBlockPrunedDB.into());
}
let start_hash = match at {
BlockID::Latest => {
let start_num = if best_block_number > 1000 {
best_block_number - 1000
} else {
0
};
self.block_hash(BlockID::Number(start_num))
.expect("blocks within HISTORY are always stored.")
}
_ => match self.block_hash(at) {
Some(hash) => hash,
None => return Err(snapshot::Error::InvalidStartingBlock(at).into()),
},
};
try!(snapshot::take_snapshot(&self.chain, start_hash, db.as_hashdb(), writer, p));
Ok(())
}
@@ -784,8 +800,8 @@ impl BlockChainClient for Client {
Self::block_hash(&self.chain, id)
}
fn code(&self, address: &Address) -> Option<Bytes> {
self.state().code(address)
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>> {
self.state_at(id).map(|s| s.code(address))
}
fn balance(&self, address: &Address, id: BlockID) -> Option<U256> {

View File

@@ -258,7 +258,7 @@ pub fn get_temp_journal_db() -> GuardedTempResult<Box<JournalDB>> {
impl MiningBlockChainClient for TestBlockChainClient {
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
let engine = &self.spec.engine;
let engine = &*self.spec.engine;
let genesis_header = self.spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
@@ -266,7 +266,7 @@ impl MiningBlockChainClient for TestBlockChainClient {
let last_hashes = vec![genesis_header.hash()];
let mut open_block = OpenBlock::new(
engine.deref(),
engine,
self.vm_factory(),
Default::default(),
false,
@@ -319,8 +319,11 @@ impl BlockChainClient for TestBlockChainClient {
self.nonce(address, BlockID::Latest).unwrap()
}
fn code(&self, address: &Address) -> Option<Bytes> {
self.code.read().get(address).cloned()
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>> {
match id {
BlockID::Latest => Some(self.code.read().get(address).cloned()),
_ => None,
}
}
fn balance(&self, address: &Address, id: BlockID) -> Option<U256> {
@@ -479,9 +482,9 @@ impl BlockChainClient for TestBlockChainClient {
if number == len {
{
let mut difficulty = self.difficulty.write();
*difficulty.deref_mut() = *difficulty.deref() + header.difficulty;
*difficulty = *difficulty + header.difficulty;
}
mem::replace(self.last_hash.write().deref_mut(), h.clone());
mem::replace(&mut *self.last_hash.write(), h.clone());
self.blocks.write().insert(h.clone(), b);
self.numbers.write().insert(number, h.clone());
let mut parent_hash = header.parent_hash;

View File

@@ -81,8 +81,14 @@ pub trait BlockChainClient : Sync + Send {
/// Get block hash.
fn block_hash(&self, id: BlockID) -> Option<H256>;
/// Get address code.
fn code(&self, address: &Address) -> Option<Bytes>;
/// Get address code at given block's state.
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>>;
/// Get address code at the latest block's state.
fn latest_code(&self, address: &Address) -> Option<Bytes> {
self.code(address, BlockID::Latest)
.expect("code will return Some if given BlockID::Latest; qed")
}
/// Get address balance at the given block's state.
///

View File

@@ -246,16 +246,16 @@ mod tests {
tap.unlock_account_permanently(addr, "".into()).unwrap();
let spec = new_test_authority();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
assert!(b.try_seal(engine.deref(), seal).is_ok());
assert!(b.try_seal(engine, seal).is_ok());
}
}

View File

@@ -80,18 +80,18 @@ mod tests {
let addr = tap.insert_account("".sha3(), "").unwrap();
let spec = new_test_instant();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
// Seal with empty AccountProvider.
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
assert!(b.try_seal(engine.deref(), seal).is_ok());
assert!(b.try_seal(engine, seal).is_ok());
}
#[test]

View File

@@ -350,14 +350,14 @@ mod tests {
#[test]
fn on_close_block() {
let spec = new_morden();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
}
@@ -365,14 +365,14 @@ mod tests {
#[test]
fn on_close_block_with_uncle() {
let spec = new_morden();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone();

View File

@@ -151,10 +151,14 @@ impl CostType for usize {
}
fn from_u256(val: U256) -> Result<Self> {
if U256::from(val.low_u64()) != val {
let res = val.low_u64() as usize;
// validate if value fits into usize
if U256::from(res) != val {
return Err(Error::OutOfGas);
}
Ok(val.low_u64() as usize)
Ok(res)
}
fn as_usize(&self) -> usize {
@@ -191,6 +195,7 @@ pub trait Evm {
#[test]
#[cfg(test)]
fn should_calculate_overflow_mul_shr_without_overflow() {
// given
let num = 1048576;
@@ -207,6 +212,7 @@ fn should_calculate_overflow_mul_shr_without_overflow() {
}
#[test]
#[cfg(test)]
fn should_calculate_overflow_mul_shr_with_overflow() {
// given
let max = ::std::u64::MAX;
@@ -225,3 +231,15 @@ fn should_calculate_overflow_mul_shr_with_overflow() {
assert!(o1);
}
#[test]
#[cfg(test)]
fn should_validate_u256_to_usize_conversion() {
// given
let v = U256::from(::std::usize::MAX) + U256::from(1);
// when
let res = usize::from_u256(v);
// then
assert!(res.is_err());
}

View File

@@ -515,11 +515,11 @@ impl<Cost: CostType> Interpreter<Cost> {
Ok(InstructionResult::Ok)
}
fn copy_data_to_memory(&mut self, stack: &mut Stack<U256>, data: &[u8]) {
fn copy_data_to_memory(&mut self, stack: &mut Stack<U256>, source: &[u8]) {
let dest_offset = stack.pop_back();
let source_offset = stack.pop_back();
let size = stack.pop_back();
let source_size = U256::from(data.len());
let source_size = U256::from(source.len());
let output_end = match source_offset > source_size || size > source_size || source_offset + size > source_size {
true => {
@@ -531,14 +531,14 @@ impl<Cost: CostType> Interpreter<Cost> {
for i in zero_slice.iter_mut() {
*i = 0;
}
data.len()
source.len()
},
false => (size.low_u64() + source_offset.low_u64()) as usize
};
if source_offset < source_size {
let output_begin = source_offset.low_u64() as usize;
self.mem.write_slice(dest_offset, &data[output_begin..output_end]);
self.mem.write_slice(dest_offset, &source[output_begin..output_end]);
}
}

View File

@@ -65,7 +65,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
state.commit()
.expect(&format!("State test {} failed due to internal error.", name));
let vm_factory = Default::default();
let res = state.apply(&env, engine.deref(), &vm_factory, &transaction, false);
let res = state.apply(&env, &*engine, &vm_factory, &transaction, false);
if fail_unless(state.root() == &post_state_root) {
println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root);

View File

@@ -26,6 +26,8 @@
#![cfg_attr(feature="dev", allow(match_bool))]
// Keeps consistency (all lines with `.clone()`).
#![cfg_attr(feature="dev", allow(clone_on_copy))]
// Complains on Box<E> when implementing From<Box<E>>
#![cfg_attr(feature="dev", allow(boxed_local))]
// TODO [todr] a lot of warnings to be fixed
#![cfg_attr(feature="dev", allow(assign_op_pattern))]

View File

@@ -168,12 +168,11 @@ pub struct Miner {
// NOTE [ToDr] When locking always lock in this order!
transaction_queue: Arc<Mutex<TransactionQueue>>,
sealing_work: Mutex<SealingWork>,
next_allowed_reseal: Mutex<Instant>,
sealing_block_last_request: Mutex<u64>,
// for sealing...
options: MinerOptions,
next_allowed_reseal: Mutex<Instant>,
sealing_block_last_request: Mutex<u64>,
gas_range_target: RwLock<(U256, U256)>,
author: RwLock<Address>,
extra_data: RwLock<Bytes>,
@@ -291,8 +290,8 @@ impl Miner {
for tx in transactions {
let hash = tx.hash();
match open_block.push_transaction(tx, None) {
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => {
debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash);
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) => {
debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?})", hash, gas_limit, gas_used, gas);
// Exit early if gas left is smaller then min_tx_gas
let min_tx_gas: U256 = 21000.into(); // TODO: figure this out properly.
if gas_limit - gas_used < min_tx_gas {
@@ -301,8 +300,8 @@ impl Miner {
},
// Invalid nonce error can happen only if previous transaction is skipped because of gas limit.
// If there is errornous state of transaction queue it will be fixed when next block is imported.
Err(Error::Execution(ExecutionError::InvalidNonce { .. })) => {
debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?}", hash);
Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) => {
debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got);
},
// already have transaction - ignore
Err(Error::Transaction(TransactionError::AlreadyImported)) => {},
@@ -528,7 +527,7 @@ impl MinerService for Miner {
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
let sealing_work = self.sealing_work.lock();
sealing_work.queue.peek_last_ref().map_or_else(|| chain.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))
}
fn set_author(&self, author: Address) {
@@ -736,11 +735,11 @@ impl MinerService for Miner {
fn update_sealing(&self, chain: &MiningBlockChainClient) {
trace!(target: "miner", "update_sealing");
let requires_reseal = {
let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions();
let mut sealing_work = self.sealing_work.lock();
if sealing_work.enabled {
trace!(target: "miner", "update_sealing: sealing enabled");
let current_no = chain.chain_info().best_block_number;
let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions();
let last_request = *self.sealing_block_last_request.lock();
let should_disable_sealing = !self.forced_sealing()
&& !has_local_transactions

View File

@@ -1467,7 +1467,7 @@ mod test {
let keypair = KeyPair::create().unwrap();
let tx = new_unsigned_tx(U256::from(123)).sign(keypair.secret());
let tx2 = {
let mut tx2 = tx.deref().clone();
let mut tx2 = (*tx).clone();
tx2.gas_price = U256::from(200);
tx2.sign(keypair.secret())
};
@@ -1490,12 +1490,12 @@ mod test {
let keypair = KeyPair::create().unwrap();
let tx0 = new_unsigned_tx(U256::from(123)).sign(keypair.secret());
let tx1 = {
let mut tx1 = tx0.deref().clone();
let mut tx1 = (*tx0).clone();
tx1.nonce = U256::from(124);
tx1.sign(keypair.secret())
};
let tx2 = {
let mut tx2 = tx1.deref().clone();
let mut tx2 = (*tx1).clone();
tx2.gas_price = U256::from(200);
tx2.sign(keypair.secret())
};

View File

@@ -18,6 +18,8 @@
use std::fmt;
use ids::BlockID;
use util::H256;
use util::trie::TrieError;
use util::rlp::DecoderError;
@@ -26,9 +28,13 @@ use util::rlp::DecoderError;
#[derive(Debug)]
pub enum Error {
/// Invalid starting block for snapshot.
InvalidStartingBlock(H256),
InvalidStartingBlock(BlockID),
/// Block not found.
BlockNotFound(H256),
/// Incomplete chain.
IncompleteChain,
/// Old starting block in a pruned database.
OldBlockPrunedDB,
/// Trie error.
Trie(TrieError),
/// Decoder error.
@@ -40,8 +46,11 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InvalidStartingBlock(ref hash) => write!(f, "Invalid starting block hash: {}", hash),
Error::InvalidStartingBlock(ref id) => write!(f, "Invalid starting block: {:?}", id),
Error::BlockNotFound(ref hash) => write!(f, "Block not found in chain: {}", hash),
Error::IncompleteChain => write!(f, "Cannot create snapshot due to incomplete chain."),
Error::OldBlockPrunedDB => write!(f, "Attempted to create a snapshot at an old block while using \
a pruned database. Please re-run with the --pruning archive flag."),
Error::Io(ref err) => err.fmt(f),
Error::Decoder(ref err) => err.fmt(f),
Error::Trie(ref err) => err.fmt(f),
@@ -55,9 +64,9 @@ impl From<::std::io::Error> for Error {
}
}
impl From<Box<TrieError>> for Error {
fn from(err: Box<TrieError>) -> Self {
Error::Trie(*err)
impl From<TrieError> for Error {
fn from(err: TrieError) -> Self {
Error::Trie(err)
}
}
@@ -65,4 +74,10 @@ impl From<DecoderError> for Error {
fn from(err: DecoderError) -> Self {
Error::Decoder(err)
}
}
}
impl<E> From<Box<E>> for Error where Error: From<E> {
fn from(err: Box<E>) -> Self {
Error::from(*err)
}
}

View File

@@ -18,10 +18,12 @@
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use account_db::{AccountDB, AccountDBMut};
use blockchain::{BlockChain, BlockProvider};
use engines::Engine;
use ids::BlockID;
use views::BlockView;
use util::{Bytes, Hashable, HashDB, snappy, TrieDB, TrieDBMut, TrieMut};
@@ -58,9 +60,39 @@ const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024;
// How many blocks to include in a snapshot, starting from the head of the chain.
const SNAPSHOT_BLOCKS: u64 = 30000;
/// A progress indicator for snapshots.
#[derive(Debug, Default)]
pub struct Progress {
accounts: AtomicUsize,
blocks: AtomicUsize,
size: AtomicUsize, // Todo [rob] use Atomicu64 when it stabilizes.
done: AtomicBool,
}
impl Progress {
/// Get the number of accounts snapshotted thus far.
pub fn accounts(&self) -> usize { self.accounts.load(Ordering::Relaxed) }
/// Get the number of blocks snapshotted thus far.
pub fn blocks(&self) -> usize { self.blocks.load(Ordering::Relaxed) }
/// Get the written size of the snapshot in bytes.
pub fn size(&self) -> usize { self.size.load(Ordering::Relaxed) }
/// Whether the snapshot is complete.
pub fn done(&self) -> bool { self.done.load(Ordering::SeqCst) }
}
/// Take a snapshot using the given blockchain, starting block hash, and database, writing into the given writer.
pub fn take_snapshot<W: SnapshotWriter + Send>(chain: &BlockChain, start_block_hash: H256, state_db: &HashDB, writer: W) -> Result<(), Error> {
let start_header = try!(chain.block_header(&start_block_hash).ok_or(Error::InvalidStartingBlock(start_block_hash)));
pub fn take_snapshot<W: SnapshotWriter + Send>(
chain: &BlockChain,
block_at: H256,
state_db: &HashDB,
writer: W,
p: &Progress
) -> Result<(), Error> {
let start_header = try!(chain.block_header(&block_at)
.ok_or(Error::InvalidStartingBlock(BlockID::Hash(block_at))));
let state_root = start_header.state_root();
let number = start_header.number();
@@ -68,8 +100,8 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(chain: &BlockChain, start_block_h
let writer = Mutex::new(writer);
let (state_hashes, block_hashes) = try!(scope(|scope| {
let block_guard = scope.spawn(|| chunk_blocks(chain, (number, start_block_hash), &writer));
let state_res = chunk_state(state_db, state_root, &writer);
let block_guard = scope.spawn(|| chunk_blocks(chain, (number, block_at), &writer, p));
let state_res = chunk_state(state_db, state_root, &writer, p);
state_res.and_then(|state_hashes| {
block_guard.join().map(|block_hashes| (state_hashes, block_hashes))
@@ -83,11 +115,13 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(chain: &BlockChain, start_block_h
block_hashes: block_hashes,
state_root: *state_root,
block_number: number,
block_hash: start_block_hash,
block_hash: block_at,
};
try!(writer.into_inner().finish(manifest_data));
p.done.store(true, Ordering::SeqCst);
Ok(())
}
@@ -100,6 +134,7 @@ struct BlockChunker<'a> {
hashes: Vec<H256>,
snappy_buffer: Vec<u8>,
writer: &'a Mutex<SnapshotWriter + 'a>,
progress: &'a Progress,
}
impl<'a> BlockChunker<'a> {
@@ -162,7 +197,8 @@ impl<'a> BlockChunker<'a> {
let parent_total_difficulty = parent_details.total_difficulty;
let mut rlp_stream = RlpStream::new_list(3 + self.rlps.len());
let num_entries = self.rlps.len();
let mut rlp_stream = RlpStream::new_list(3 + num_entries);
rlp_stream.append(&parent_number).append(&parent_hash).append(&parent_total_difficulty);
for pair in self.rlps.drain(..) {
@@ -178,6 +214,9 @@ impl<'a> BlockChunker<'a> {
try!(self.writer.lock().write_block_chunk(hash, compressed));
trace!(target: "snapshot", "wrote block chunk. hash: {}, size: {}, uncompressed size: {}", hash.hex(), size, raw_data.len());
self.progress.size.fetch_add(size, Ordering::SeqCst);
self.progress.blocks.fetch_add(num_entries, Ordering::SeqCst);
self.hashes.push(hash);
Ok(())
}
@@ -189,7 +228,7 @@ impl<'a> BlockChunker<'a> {
/// The path parameter is the directory to store the block chunks in.
/// This function assumes the directory exists already.
/// Returns a list of chunk hashes, with the first having the blocks furthest from the genesis.
pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), writer: &Mutex<SnapshotWriter + 'a>) -> Result<Vec<H256>, Error> {
pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress) -> Result<Vec<H256>, Error> {
let (start_number, start_hash) = start_block_info;
let first_hash = if start_number < SNAPSHOT_BLOCKS {
@@ -197,8 +236,7 @@ pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), wr
chain.genesis_hash()
} else {
let first_num = start_number - SNAPSHOT_BLOCKS;
chain.block_hash(first_num)
.expect("number before best block number; whole chain is stored; qed")
try!(chain.block_hash(first_num).ok_or(Error::IncompleteChain))
};
let mut chunker = BlockChunker {
@@ -208,6 +246,7 @@ pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), wr
hashes: Vec::new(),
snappy_buffer: vec![0; snappy::max_compressed_len(PREFERRED_CHUNK_SIZE)],
writer: writer,
progress: progress,
};
try!(chunker.chunk_all(first_hash));
@@ -222,6 +261,7 @@ struct StateChunker<'a> {
cur_size: usize,
snappy_buffer: Vec<u8>,
writer: &'a Mutex<SnapshotWriter + 'a>,
progress: &'a Progress,
}
impl<'a> StateChunker<'a> {
@@ -249,7 +289,8 @@ impl<'a> StateChunker<'a> {
// Write out the buffer to disk, pushing the created chunk's hash to
// the list.
fn write_chunk(&mut self) -> Result<(), Error> {
let mut stream = RlpStream::new_list(self.rlps.len());
let num_entries = self.rlps.len();
let mut stream = RlpStream::new_list(num_entries);
for rlp in self.rlps.drain(..) {
stream.append_raw(&rlp, 1);
}
@@ -263,6 +304,9 @@ impl<'a> StateChunker<'a> {
try!(self.writer.lock().write_state_chunk(hash, compressed));
trace!(target: "snapshot", "wrote state chunk. size: {}, uncompressed size: {}", compressed_size, raw_data.len());
self.progress.accounts.fetch_add(num_entries, Ordering::SeqCst);
self.progress.size.fetch_add(compressed_size, Ordering::SeqCst);
self.hashes.push(hash);
self.cur_size = 0;
@@ -275,7 +319,7 @@ impl<'a> StateChunker<'a> {
///
/// Returns a list of hashes of chunks created, or any error it may
/// have encountered.
pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter + 'a>) -> Result<Vec<H256>, Error> {
pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress) -> Result<Vec<H256>, Error> {
let account_trie = try!(TrieDB::new(db, &root));
let mut chunker = StateChunker {
@@ -284,10 +328,9 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter +
cur_size: 0,
snappy_buffer: vec![0; snappy::max_compressed_len(PREFERRED_CHUNK_SIZE)],
writer: writer,
progress: progress,
};
trace!(target: "snapshot", "beginning state chunking");
// account_key here is the address' hash.
for (account_key, account_data) in account_trie.iter() {
let account = Account::from_thin_rlp(account_data);
@@ -383,6 +426,7 @@ impl StateRebuilder {
let chunk_size = account_fat_rlps.len() / ::num_cpus::get() + 1;
// build account tries in parallel.
// Todo [rob] keep a thread pool around so we don't do this per-chunk.
try!(scope(|scope| {
let mut handles = Vec::new();
for (account_chunk, out_pairs_chunk) in account_fat_rlps.chunks(chunk_size).zip(pairs.chunks_mut(chunk_size)) {
@@ -456,12 +500,12 @@ fn rebuild_account_trie(db: &mut HashDB, account_chunk: &[&[u8]], out_chunk: &mu
Ok(())
}
/// Proportion of blocks which we will verify PoW for.
/// Proportion of blocks which we will verify `PoW` for.
const POW_VERIFY_RATE: f32 = 0.02;
/// Rebuilds the blockchain from chunks.
///
/// Does basic verification for all blocks, but PoW verification for some.
/// Does basic verification for all blocks, but `PoW` verification for some.
/// Blocks must be fed in-order.
///
/// The first block in every chunk is disconnected from the last block in the

View File

@@ -101,7 +101,7 @@ impl Restoration {
fn new(manifest: &ManifestData, pruning: Algorithm, path: &Path, gb: &[u8]) -> Result<Self, Error> {
let cfg = DatabaseConfig::with_columns(::client::DB_NO_OF_COLUMNS);
let raw_db = Arc::new(try!(Database::open(&cfg, &*path.to_string_lossy())
.map_err(|s| UtilError::SimpleString(s))));
.map_err(UtilError::SimpleString)));
let chain = BlockChain::new(Default::default(), gb, raw_db.clone());
let blocks = try!(BlockRebuilder::new(chain, manifest.block_number));
@@ -207,23 +207,17 @@ impl Service {
};
// create the snapshot dir if it doesn't exist.
match fs::create_dir_all(service.snapshot_dir()) {
Err(e) => {
if e.kind() != ErrorKind::AlreadyExists {
return Err(e.into())
}
if let Err(e) = fs::create_dir_all(service.snapshot_dir()) {
if e.kind() != ErrorKind::AlreadyExists {
return Err(e.into())
}
_ => {}
}
// delete the temporary restoration dir if it does exist.
match fs::remove_dir_all(service.restoration_dir()) {
Err(e) => {
if e.kind() != ErrorKind::NotFound {
return Err(e.into())
}
if let Err(e) = fs::remove_dir_all(service.restoration_dir()) {
if e.kind() != ErrorKind::NotFound {
return Err(e.into())
}
_ => {}
}
Ok(service)
@@ -434,4 +428,4 @@ impl SnapshotService for Service {
self.io_channel.send(ClientIoMessage::FeedBlockChunk(hash, chunk))
.expect("snapshot service and io service are kept alive by client service; qed");
}
}
}

View File

@@ -20,7 +20,7 @@ use devtools::RandomTempPath;
use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
use blockchain::BlockChain;
use snapshot::{chunk_blocks, BlockRebuilder};
use snapshot::{chunk_blocks, BlockRebuilder, Progress};
use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter};
use util::{Mutex, snappy};
@@ -55,7 +55,7 @@ fn chunk_and_restore(amount: u64) {
// snapshot it.
let writer = Mutex::new(PackedWriter::new(&snapshot_path).unwrap());
let block_hashes = chunk_blocks(&bc, (amount, best_hash), &writer).unwrap();
let block_hashes = chunk_blocks(&bc, (amount, best_hash), &writer, &Progress::default()).unwrap();
writer.into_inner().finish(::snapshot::ManifestData {
state_hashes: Vec::new(),
block_hashes: block_hashes,
@@ -88,4 +88,4 @@ fn chunk_and_restore(amount: u64) {
fn chunk_and_restore_500() { chunk_and_restore(500) }
#[test]
fn chunk_and_restore_40k() { chunk_and_restore(40000) }
fn chunk_and_restore_40k() { chunk_and_restore(40000) }

View File

@@ -116,7 +116,7 @@ pub fn fill_storage(mut db: AccountDBMut, root: &mut H256, seed: &mut H256) {
pub fn compare_dbs(one: &HashDB, two: &HashDB) {
let keys = one.keys();
for (key, _) in keys {
for key in keys.keys() {
assert_eq!(one.get(&key).unwrap(), two.get(&key).unwrap());
}
}
}

View File

@@ -16,7 +16,7 @@
//! State snapshotting tests.
use snapshot::{chunk_state, StateRebuilder};
use snapshot::{chunk_state, Progress, StateRebuilder};
use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter};
use super::helpers::{compare_dbs, StateProducer};
@@ -48,7 +48,7 @@ fn snap_and_restore() {
let state_root = producer.state_root();
let writer = Mutex::new(PackedWriter::new(&snap_file).unwrap());
let state_hashes = chunk_state(&old_db, &state_root, &writer).unwrap();
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default()).unwrap();
writer.into_inner().finish(::snapshot::ManifestData {
state_hashes: state_hashes,
@@ -79,4 +79,4 @@ fn snap_and_restore() {
let new_db = journaldb::new(db, Algorithm::Archive, ::client::DB_COL_STATE);
compare_dbs(&old_db, new_db.as_hashdb());
}
}

View File

@@ -347,7 +347,7 @@ impl State {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let maybe_acc = match db.get(&a) {
let maybe_acc = match db.get(a) {
Ok(acc) => acc.map(Account::from_rlp),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
};
@@ -375,7 +375,7 @@ impl State {
let contains_key = self.cache.borrow().contains_key(a);
if !contains_key {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let maybe_acc = match db.get(&a) {
let maybe_acc = match db.get(a) {
Ok(acc) => acc.map(Account::from_rlp),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
};
@@ -630,7 +630,7 @@ fn should_trace_call_transaction_to_builtin() {
let mut info = EnvInfo::default();
info.gas_limit = 1_000_000.into();
let engine = Spec::new_test().engine;
let engine = &*Spec::new_test().engine;
let t = Transaction {
nonce: 0.into(),
@@ -642,7 +642,7 @@ fn should_trace_call_transaction_to_builtin() {
}.sign(&"".sha3());
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -673,7 +673,7 @@ fn should_not_trace_subcall_transaction_to_builtin() {
let mut info = EnvInfo::default();
info.gas_limit = 1_000_000.into();
let engine = Spec::new_test().engine;
let engine = &*Spec::new_test().engine;
let t = Transaction {
nonce: 0.into(),
@@ -686,7 +686,7 @@ fn should_not_trace_subcall_transaction_to_builtin() {
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -717,7 +717,7 @@ fn should_not_trace_callcode() {
let mut info = EnvInfo::default();
info.gas_limit = 1_000_000.into();
let engine = Spec::new_test().engine;
let engine = &*Spec::new_test().engine;
let t = Transaction {
nonce: 0.into(),
@@ -731,7 +731,7 @@ fn should_not_trace_callcode() {
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -778,7 +778,7 @@ fn should_not_trace_delegatecall() {
let mut info = EnvInfo::default();
info.gas_limit = 1_000_000.into();
info.number = 0x789b0;
let engine = Spec::new_test().engine;
let engine = &*Spec::new_test().engine;
println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call);
@@ -794,7 +794,7 @@ fn should_not_trace_delegatecall() {
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -1489,4 +1489,4 @@ fn create_empty() {
assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421");
}
}
}

View File

@@ -134,7 +134,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let test_spec = get_test_spec();
let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected()).unwrap();
let test_engine = &test_spec.engine;
let test_engine = &*test_spec.engine;
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
@@ -155,7 +155,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
// forge block.
let mut b = OpenBlock::new(
test_engine.deref(),
test_engine,
&vm_factory,
Default::default(),
false,
@@ -183,7 +183,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
n += 1;
}
let b = b.close_and_lock().seal(test_engine.deref(), vec![]).unwrap();
let b = b.close_and_lock().seal(test_engine, vec![]).unwrap();
if let Err(e) = client.import_block(b.rlp_bytes()) {
panic!("error importing block which is valid by definition: {:?}", e);

View File

@@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Trace database.
use std::ops::{Deref, DerefMut};
use std::ops::Deref;
use std::collections::HashMap;
use std::sync::Arc;
use bloomchain::{Number, Config as BloomConfig};
@@ -119,8 +119,9 @@ pub struct TraceDB<T> where T: DatabaseExtras {
impl<T> BloomGroupDatabase for TraceDB<T> where T: DatabaseExtras {
fn blooms_at(&self, position: &GroupPosition) -> Option<BloomGroup> {
let position = TraceGroupPosition::from(position.clone());
self.note_used(CacheID::Bloom(position.clone()));
self.tracesdb.read_with_cache(DB_COL_TRACE, &self.blooms, &position).map(Into::into)
let result = self.tracesdb.read_with_cache(DB_COL_TRACE, &self.blooms, &position).map(Into::into);
self.note_used(CacheID::Bloom(position));
result
}
}
@@ -174,11 +175,13 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
/// Ticks our cache system and throws out any old data.
pub fn collect_garbage(&self) {
let mut cache_manager = self.cache_manager.write();
cache_manager.collect_garbage(|| self.cache_size(), | ids | {
let mut traces = self.traces.write();
let mut blooms = self.blooms.write();
let current_size = self.cache_size();
let mut traces = self.traces.write();
let mut blooms = self.blooms.write();
let mut cache_manager = self.cache_manager.write();
cache_manager.collect_garbage(current_size, | ids | {
for id in &ids {
match *id {
CacheID::Trace(ref h) => { traces.remove(h); },
@@ -187,13 +190,16 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
}
traces.shrink_to_fit();
blooms.shrink_to_fit();
traces.heap_size_of_children() + blooms.heap_size_of_children()
});
}
/// Returns traces for block with hash.
fn traces(&self, block_hash: &H256) -> Option<FlatBlockTraces> {
let result = self.tracesdb.read_with_cache(DB_COL_TRACE, &self.traces, block_hash);
self.note_used(CacheID::Trace(block_hash.clone()));
self.tracesdb.read_with_cache(DB_COL_TRACE, &self.traces, block_hash)
result
}
/// Returns vector of transaction traces for given block.
@@ -264,12 +270,12 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
// at first, let's insert new block traces
{
// note_used must be called before locking traces to avoid cache/traces deadlock on garbage collection
self.note_used(CacheID::Trace(request.block_hash.clone()));
let mut traces = self.traces.write();
// it's important to use overwrite here,
// cause this value might be queried by hash later
batch.write_with_cache(DB_COL_TRACE, traces.deref_mut(), request.block_hash, request.traces, CacheUpdatePolicy::Overwrite);
batch.write_with_cache(DB_COL_TRACE, &mut *traces, request.block_hash, request.traces, CacheUpdatePolicy::Overwrite);
// note_used must be called after locking traces to avoid cache/traces deadlock on garbage collection
self.note_used(CacheID::Trace(request.block_hash.clone()));
}
// now let's rebuild the blooms
@@ -294,12 +300,13 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
.map(|p| (From::from(p.0), From::from(p.1)))
.collect::<HashMap<TraceGroupPosition, blooms::BloomGroup>>();
// note_used must be called before locking blooms to avoid cache/traces deadlock on garbage collection
for key in blooms_to_insert.keys() {
self.note_used(CacheID::Bloom(key.clone()));
}
let blooms_keys: Vec<_> = blooms_to_insert.keys().cloned().collect();
let mut blooms = self.blooms.write();
batch.extend_with_cache(DB_COL_TRACE, blooms.deref_mut(), blooms_to_insert, CacheUpdatePolicy::Remove);
batch.extend_with_cache(DB_COL_TRACE, &mut *blooms, blooms_to_insert, CacheUpdatePolicy::Remove);
// note_used must be called after locking blooms to avoid cache/traces deadlock on garbage collection
for key in blooms_keys.into_iter() {
self.note_used(CacheID::Bloom(key));
}
}
}

View File

@@ -40,7 +40,8 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
try!(verify_header(&header, engine));
try!(verify_block_integrity(bytes, &header.transactions_root, &header.uncles_hash));
try!(engine.verify_block_basic(&header, Some(bytes)));
for u in Rlp::new(bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
for u in try!(UntrustedRlp::new(bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
let u = try!(u);
try!(verify_header(&u, engine));
try!(engine.verify_block_basic(&u, None));
}
@@ -58,8 +59,8 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
/// Returns a `PreverifiedBlock` structure populated with transactions
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreverifiedBlock, Error> {
try!(engine.verify_block_unordered(&header, Some(&bytes)));
for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&u, None));
for u in try!(UntrustedRlp::new(&bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&try!(u), None));
}
// Verify transactions.
let mut transactions = Vec::new();
@@ -84,7 +85,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
try!(verify_parent(&header, &parent));
try!(engine.verify_block_family(&header, &parent, Some(bytes)));
let num_uncles = Rlp::new(bytes).at(2).item_count();
let num_uncles = try!(UntrustedRlp::new(bytes).at(2)).item_count();
if num_uncles != 0 {
if num_uncles > engine.maximum_uncle_count() {
return Err(From::from(BlockError::TooManyUncles(OutOfBounds { min: None, max: Some(engine.maximum_uncle_count()), found: num_uncles })));
@@ -106,7 +107,8 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
}
}
for uncle in Rlp::new(bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
for uncle in try!(UntrustedRlp::new(bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
let uncle = try!(uncle);
if excluded.contains(&uncle.hash()) {
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
}
@@ -210,13 +212,13 @@ fn verify_parent(header: &Header, parent: &Header) -> Result<(), Error> {
/// Verify block data against header: transactions root and uncles hash.
fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), Error> {
let block = Rlp::new(block);
let tx = block.at(1);
let block = UntrustedRlp::new(block);
let tx = try!(block.at(1));
let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw().to_vec()).collect()); //TODO: get rid of vectors here
if expected_root != transactions_root {
return Err(From::from(BlockError::InvalidTransactionsRoot(Mismatch { expected: expected_root.clone(), found: transactions_root.clone() })))
}
let expected_uncles = &block.at(2).as_raw().sha3();
let expected_uncles = &try!(block.at(2)).as_raw().sha3();
if expected_uncles != uncles_hash {
return Err(From::from(BlockError::InvalidUnclesHash(Mismatch { expected: expected_uncles.clone(), found: uncles_hash.clone() })))
}
@@ -342,7 +344,7 @@ mod tests {
// Test against morden
let mut good = Header::new();
let spec = Spec::new_test();
let engine = &spec.engine;
let engine = &*spec.engine;
let min_gas_limit = engine.params().min_gas_limit;
good.gas_limit = min_gas_limit;
@@ -423,69 +425,69 @@ mod tests {
bc.insert(create_test_block(&parent7));
bc.insert(create_test_block(&parent8));
check_ok(basic_test(&create_test_block(&good), engine.deref()));
check_ok(basic_test(&create_test_block(&good), engine));
let mut header = good.clone();
header.transactions_root = good_transactions_root.clone();
header.uncles_hash = good_uncles_hash.clone();
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()));
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
header.gas_limit = min_gas_limit - From::from(1);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit }));
header = good.clone();
header.number = BlockNumber::max_value();
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
RidiculousNumber(OutOfBounds { max: Some(BlockNumber::max_value()), min: None, found: header.number }));
header = good.clone();
header.gas_used = header.gas_limit + From::from(1);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit), min: None, found: header.gas_used }));
header = good.clone();
header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() }));
header = good.clone();
header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() }));
header = good.clone();
header.uncles_hash = good_uncles_hash.clone();
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()),
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
InvalidTransactionsRoot(Mismatch { expected: good_transactions_root.clone(), found: header.transactions_root }));
header = good.clone();
header.transactions_root = good_transactions_root.clone();
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()),
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
InvalidUnclesHash(Mismatch { expected: good_uncles_hash.clone(), found: header.uncles_hash }));
check_ok(family_test(&create_test_block(&good), engine.deref(), &bc));
check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine.deref(), &bc));
check_ok(family_test(&create_test_block(&good), engine, &bc));
check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine, &bc));
header = good.clone();
header.parent_hash = H256::random();
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
UnknownParent(header.parent_hash));
header = good.clone();
header.timestamp = 10;
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp }));
header = good.clone();
header.number = 9;
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number }));
header = good.clone();
let mut bad_uncles = good_uncles.clone();
bad_uncles.push(good_uncle1.clone());
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
// TODO: some additional uncle checks

View File

@@ -136,7 +136,7 @@ pub fn verify_public(public: &Public, signature: &Signature, message: &Message)
let pdata: [u8; 65] = {
let mut temp = [4u8; 65];
temp[1..65].copy_from_slice(public.deref());
temp[1..65].copy_from_slice(&**public);
temp
};

View File

@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::ops::{Deref, DerefMut};
use ethkey::{KeyPair, sign, Address, Secret, Signature, Message};
use {json, Error, crypto};
use crypto::Keccak256;
@@ -87,7 +86,7 @@ impl Crypto {
let mut ciphertext = [0u8; 32];
// aes-128-ctr with initial vector of iv
crypto::aes::encrypt(&derived_left_bits, &iv, secret.deref(), &mut ciphertext);
crypto::aes::encrypt(&derived_left_bits, &iv, &**secret, &mut ciphertext);
// KECCAK(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
let mac = crypto::derive_mac(&derived_right_bits, &ciphertext).keccak256();
@@ -123,7 +122,7 @@ impl Crypto {
match self.cipher {
Cipher::Aes128Ctr(ref params) => {
crypto::aes::decrypt(&derived_left_bits, &params.iv, &self.ciphertext, secret.deref_mut())
crypto::aes::decrypt(&derived_left_bits, &params.iv, &self.ciphertext, &mut *secret)
},
}

View File

@@ -143,7 +143,7 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
} else if args.cmd_import {
let src = try!(key_dir(&args.flag_src));
let dst = try!(key_dir(&args.flag_dir));
let accounts = try!(import_accounts(src.deref(), dst.deref()));
let accounts = try!(import_accounts(*src, *dst));
Ok(format_accounts(&accounts))
} else if args.cmd_import_wallet {
let wallet = try!(PresaleWallet::open(&args.arg_path));

View File

@@ -22,6 +22,8 @@ use ethkey::Address;
use {json, SafeAccount, Error};
use super::KeyDirectory;
const IGNORED_FILES: &'static [&'static str] = &["thumbs.db"];
#[cfg(not(windows))]
fn restrict_permissions_to_owner(file_path: &Path) -> Result<(), i32> {
use std::ffi;
@@ -62,7 +64,14 @@ impl DiskDirectory {
.flat_map(Result::ok)
.filter(|entry| {
let metadata = entry.metadata();
metadata.is_ok() && !metadata.unwrap().is_dir()
let file_name = entry.file_name();
let name = file_name.to_str().unwrap();
// filter directories
metadata.is_ok() && !metadata.unwrap().is_dir() &&
// hidden files
!name.starts_with(".") &&
// other ignored files
!IGNORED_FILES.contains(&name)
})
.map(|entry| entry.path())
.collect::<Vec<PathBuf>>();

View File

@@ -27,8 +27,8 @@ use std::sync::*;
use nanomsg::{Socket, Protocol, Error, Endpoint, PollRequest, PollFd, PollInOut};
use std::ops::Deref;
const POLL_TIMEOUT: isize = 100;
const CLIENT_CONNECTION_TIMEOUT: isize = 2500;
const POLL_TIMEOUT: isize = 200;
const CLIENT_CONNECTION_TIMEOUT: isize = 15000;
/// Generic worker to handle service (binded) sockets
pub struct Worker<S: ?Sized> where S: IpcInterface {
@@ -68,7 +68,6 @@ pub fn init_duplex_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, Sock
SocketError::DuplexLink
}));
// 2500 ms default timeout
socket.set_receive_timeout(CLIENT_CONNECTION_TIMEOUT).unwrap();
let endpoint = try!(socket.connect(socket_addr).map_err(|e| {
@@ -91,7 +90,6 @@ pub fn init_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError
SocketError::RequestLink
}));
// 2500 ms default timeout
socket.set_receive_timeout(CLIENT_CONNECTION_TIMEOUT).unwrap();
let endpoint = try!(socket.connect(socket_addr).map_err(|e| {

View File

@@ -48,10 +48,10 @@ macro_rules! impl_hash {
0 => $inner::from(0),
2 if value == "0x" => $inner::from(0),
_ if value.starts_with("0x") => try!($inner::from_str(&value[2..]).map_err(|_| {
Error::custom(format!("Invalid hex value {}.", value).as_ref())
Error::custom(format!("Invalid hex value {}.", value).as_str())
})),
_ => try!($inner::from_str(value).map_err(|_| {
Error::custom(format!("Invalid hex value {}.", value).as_ref())
Error::custom(format!("Invalid hex value {}.", value).as_str())
}))
};

View File

@@ -70,10 +70,10 @@ impl Visitor for UintVisitor {
0 => U256::from(0),
2 if value.starts_with("0x") => U256::from(0),
_ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| {
Error::custom(format!("Invalid hex value {}.", value).as_ref())
Error::custom(format!("Invalid hex value {}.", value).as_str())
})),
_ => try!(U256::from_dec_str(value).map_err(|_| {
Error::custom(format!("Invalid decimal value {}.", value).as_ref())
Error::custom(format!("Invalid decimal value {}.", value).as_str())
}))
};

View File

@@ -231,6 +231,12 @@ Import/Export Options:
--format FORMAT For import/export in given format. FORMAT must be
one of 'hex' and 'binary'.
Snapshot Options:
--at BLOCK Take a snapshot at the given block, which may be an
index, hash, or 'latest'. Note that taking snapshots at
non-recent blocks will only work with --pruning archive
[default: latest]
Virtual Machine Options:
--jitvm Enable the JIT VM.
@@ -365,6 +371,7 @@ pub struct Args {
pub flag_version: bool,
pub flag_from: String,
pub flag_to: String,
pub flag_at: String,
pub flag_format: Option<String>,
pub flag_jitvm: bool,
pub flag_log_file: Option<String>,

View File

@@ -171,6 +171,7 @@ impl Configuration {
file_path: self.args.arg_file.clone(),
wal: wal,
kind: snapshot::Kind::Take,
block_at: try!(to_block_id(&self.args.flag_at)),
};
Cmd::Snapshot(snapshot_cmd)
} else if self.args.cmd_restore {
@@ -186,6 +187,7 @@ impl Configuration {
file_path: self.args.arg_file.clone(),
wal: wal,
kind: snapshot::Kind::Restore,
block_at: try!(to_block_id("latest")), // unimportant.
};
Cmd::Snapshot(restore_cmd)
} else {
@@ -499,8 +501,6 @@ impl Configuration {
NetworkSettings {
name: self.args.flag_identity.clone(),
chain: self.chain(),
max_peers: self.max_peers(),
min_peers: self.min_peers(),
network_port: self.args.flag_port,
rpc_enabled: !self.args.flag_jsonrpc_off && !self.args.flag_no_jsonrpc,
rpc_interface: self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()),
@@ -509,6 +509,8 @@ impl Configuration {
}
fn directories(&self) -> Directories {
use util::path;
let db_path = replace_home(self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path));
let keys_path = replace_home(
@@ -522,6 +524,12 @@ impl Configuration {
let dapps_path = replace_home(&self.args.flag_dapps_path);
let signer_path = replace_home(&self.args.flag_signer_path);
if self.args.flag_geth {
let geth_path = path::ethereum::default();
::std::fs::create_dir_all(geth_path.as_path()).unwrap_or_else(
|e| warn!("Failed to create '{}' for geth mode: {}", &geth_path.to_str().unwrap(), e));
}
Directories {
keys: keys_path,
db: db_path,
@@ -769,8 +777,6 @@ mod tests {
assert_eq!(conf.network_settings(), NetworkSettings {
name: "testname".to_owned(),
chain: "morden".to_owned(),
max_peers: 50,
min_peers: 25,
network_port: 30303,
rpc_enabled: true,
rpc_interface: "local".to_owned(),

View File

@@ -21,7 +21,6 @@ use self::ansi_term::Style;
use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
use std::time::{Instant, Duration};
use std::ops::{Deref, DerefMut};
use isatty::{stdout_isatty};
use ethsync::{SyncProvider, ManageNetwork};
use util::{Uint, RwLock, Mutex, H256, Colour};
@@ -112,7 +111,7 @@ impl Informant {
paint(White.bold(), format!("{:>8}", format!("#{}", chain_info.best_block_number))),
paint(White.bold(), format!("{}", chain_info.best_block_hash)),
{
let last_report = match write_report.deref() { &Some(ref last_report) => last_report.clone(), _ => ClientReport::default() };
let last_report = match *write_report { Some(ref last_report) => last_report.clone(), _ => ClientReport::default() };
format!("{} blk/s {} tx/s {} Mgas/s",
paint(Yellow.bold(), format!("{:4}", ((report.blocks_imported - last_report.blocks_imported) * 1000) as u64 / elapsed.as_milliseconds())),
paint(Yellow.bold(), format!("{:4}", ((report.transactions_applied - last_report.transactions_applied) * 1000) as u64 / elapsed.as_milliseconds())),
@@ -132,7 +131,7 @@ impl Informant {
},
paint(Cyan.bold(), format!("{:2}", sync_info.num_active_peers)),
paint(Cyan.bold(), format!("{:2}", sync_info.num_peers)),
paint(Cyan.bold(), format!("{:2}", if sync_info.num_peers as u32 > net_config.min_peers { net_config.max_peers} else { net_config.min_peers} ))
paint(Cyan.bold(), format!("{:2}", sync_info.current_max_peers(net_config.min_peers, net_config.max_peers))),
),
_ => String::new(),
},
@@ -147,9 +146,9 @@ impl Informant {
)
);
*self.chain_info.write().deref_mut() = Some(chain_info);
*self.cache_info.write().deref_mut() = Some(cache_info);
*write_report.deref_mut() = Some(report);
*self.chain_info.write() = Some(chain_info);
*self.cache_info.write() = Some(cache_info);
*write_report = Some(report);
}
}

View File

@@ -15,11 +15,10 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::str::FromStr;
use std::sync::Arc;
use std::fs;
use std::time::Duration;
use util::{contents, Database, DatabaseConfig, journaldb, H256, Address, U256, version_data};
use util::{contents, H256, Address, U256, version_data};
use util::journaldb::Algorithm;
use ethcore::client;
use ethcore::spec::Spec;
use ethcore::ethereum;
use ethcore::miner::{GasPricer, GasPriceCalibratorOptions};
@@ -100,20 +99,13 @@ impl Pruning {
fn find_best_db(dirs: &Directories, genesis_hash: H256, fork_name: Option<&String>) -> Algorithm {
let mut algo_types = Algorithm::all_types();
// if all dbs have the same latest era, the last element is the default one
// if all dbs have the same modification time, the last element is the default one
algo_types.push(Algorithm::default());
algo_types.into_iter().max_by_key(|i| {
let client_path = dirs.client_path(genesis_hash, fork_name, *i);
let config = DatabaseConfig::with_columns(client::DB_NO_OF_COLUMNS);
let db = match Database::open(&config, client_path.to_str().unwrap()) {
Ok(db) => db,
Err(_) => return 0,
};
let db = journaldb::new(Arc::new(db), *i, client::DB_COL_STATE);
trace!(target: "parity", "Looking for best DB: {} at {:?}", i, db.latest_era());
db.latest_era().unwrap_or(0)
let mut client_path = dirs.client_path(genesis_hash, fork_name, *i);
client_path.push("CURRENT");
fs::metadata(&client_path).and_then(|m| m.modified()).ok()
}).unwrap()
}
}

View File

@@ -186,7 +186,7 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
},
Api::Ethcore => {
let queue = deps.signer_port.map(|_| deps.signer_queue.clone());
server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone(), queue).to_delegate())
server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, &deps.sync, &deps.net_service, deps.logger.clone(), deps.settings.clone(), queue).to_delegate())
},
Api::EthcoreSet => {
server.add_delegate(EthcoreSetClient::new(&deps.client, &deps.miner, &deps.net_service).to_delegate())

View File

@@ -30,8 +30,6 @@ use ethcore::account_provider::AccountProvider;
use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions};
use ethsync::SyncConfig;
use informant::Informant;
#[cfg(feature="ipc")]
use ethcore::client::ChainNotify;
use rpc::{HttpServer, IpcServer, HttpConfiguration, IpcConfiguration};
use signer::SignerServer;
@@ -82,9 +80,6 @@ pub struct RunCmd {
}
pub fn execute(cmd: RunCmd) -> Result<(), String> {
// create supervisor
let mut hypervisor = modules::hypervisor();
// increase max number of open files
raise_fd_limit();
@@ -167,6 +162,9 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
net_conf.boot_nodes = spec.nodes.clone();
}
// create supervisor
let mut hypervisor = modules::hypervisor();
// create client service.
let service = try!(ClientService::start(
client_config,

View File

@@ -19,12 +19,15 @@
use std::time::Duration;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use ethcore_logger::{setup_log, Config as LogConfig};
use ethcore::snapshot::{RestorationStatus, SnapshotService};
use ethcore::snapshot::{Progress, RestorationStatus, SnapshotService};
use ethcore::snapshot::io::{SnapshotReader, PackedReader, PackedWriter};
use ethcore::service::ClientService;
use ethcore::client::{Mode, DatabaseCompactionProfile, Switch, VMType};
use ethcore::miner::Miner;
use ethcore::ids::BlockID;
use cache::CacheConfig;
use params::{SpecType, Pruning};
use helpers::{to_client_config, execute_upgrades};
@@ -56,6 +59,7 @@ pub struct SnapshotCommand {
pub file_path: Option<String>,
pub wal: bool,
pub kind: Kind,
pub block_at: BlockID,
}
impl SnapshotCommand {
@@ -105,7 +109,7 @@ impl SnapshotCommand {
warn!("Snapshot restoration is experimental and the format may be subject to change.");
let snapshot = service.snapshot_service();
let reader = PackedReader::new(&Path::new(&file))
let reader = PackedReader::new(Path::new(&file))
.map_err(|e| format!("Couldn't open snapshot file: {}", e))
.and_then(|x| x.ok_or("Snapshot file has invalid format.".into()));
@@ -168,6 +172,7 @@ impl SnapshotCommand {
pub fn take_snapshot(self) -> Result<(), String> {
let file_path = try!(self.file_path.clone().ok_or("No file path provided.".to_owned()));
let file_path: PathBuf = file_path.into();
let block_at = self.block_at;
let (service, _panic_handler) = try!(self.start_service());
warn!("Snapshots are currently experimental. File formats may be subject to change.");
@@ -175,11 +180,35 @@ impl SnapshotCommand {
let writer = try!(PackedWriter::new(&file_path)
.map_err(|e| format!("Failed to open snapshot writer: {}", e)));
if let Err(e) = service.client().take_snapshot(writer) {
let progress = Arc::new(Progress::default());
let p = progress.clone();
let informant_handle = ::std::thread::spawn(move || {
::std::thread::sleep(Duration::from_secs(5));
let mut last_size = 0;
while !p.done() {
let cur_size = p.size();
if cur_size != last_size {
last_size = cur_size;
info!("Snapshot: {} accounts {} blocks {} bytes", p.accounts(), p.blocks(), p.size());
} else {
info!("Snapshot: No progress since last update.");
}
::std::thread::sleep(Duration::from_secs(5));
}
});
if let Err(e) = service.client().take_snapshot(writer, block_at, &*progress) {
let _ = ::std::fs::remove_file(&file_path);
return Err(format!("Encountered fatal error while creating snapshot: {}", e));
}
info!("snapshot creation complete");
assert!(progress.done());
try!(informant_handle.join().map_err(|_| "failed to join logger thread"));
Ok(())
}
}
@@ -192,4 +221,4 @@ pub fn execute(cmd: SnapshotCommand) -> Result<String, String> {
}
Ok(String::new())
}
}

View File

@@ -12,7 +12,7 @@ build = "build.rs"
log = "0.3"
serde = "0.7.0"
serde_json = "0.7.0"
jsonrpc-core = "2.0"
jsonrpc-core = "2.1"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
ethcore-io = { path = "../util/io" }
ethcore-util = { path = "../util" }

View File

@@ -0,0 +1,96 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::numbers::*;
use util::rlp::encode;
use util::bytes::ToPretty;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use ethcore::transaction::{Action, SignedTransaction, Transaction};
use ethcore::account_provider::AccountProvider;
use jsonrpc_core::{Error, Value, to_value};
use v1::helpers::TransactionRequest;
use v1::types::{H256 as RpcH256, H520 as RpcH520};
use v1::helpers::errors;
fn prepare_transaction<C, M>(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService {
Transaction {
nonce: request.nonce
.or_else(|| miner
.last_nonce(&request.from)
.map(|nonce| nonce + U256::one()))
.unwrap_or_else(|| client.latest_nonce(&request.from)),
action: request.to.map_or(Action::Create, Action::Call),
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
value: request.value.unwrap_or_else(U256::zero),
data: request.data.map_or_else(Vec::new, |b| b.to_vec()),
}
}
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
where C: MiningBlockChainClient, M: MinerService {
let hash = RpcH256::from(signed_transaction.hash());
let import = miner.import_own_transaction(client, signed_transaction);
import
.map_err(errors::from_transaction_error)
.and_then(|_| to_value(&hash))
}
pub fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result<Value, Error> {
accounts.sign_with_password(address, pass, hash)
.map_err(errors::from_password_error)
.and_then(|hash| to_value(&RpcH520::from(hash)))
}
pub fn unlock_sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result<Value, Error>
where C: MiningBlockChainClient, M: MinerService {
let address = request.from;
let signed_transaction = {
let t = prepare_transaction(client, miner, request);
let hash = t.hash();
let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(errors::from_password_error));
t.with_signature(signature)
};
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
dispatch_transaction(&*client, &*miner, signed_transaction)
}
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result<Value, Error>
where C: MiningBlockChainClient, M: MinerService {
let signed_transaction = {
let t = prepare_transaction(client, miner, request);
let hash = t.hash();
let signature = try!(account_provider.sign(address, hash).map_err(errors::from_signing_error));
t.with_signature(signature)
};
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
dispatch_transaction(&*client, &*miner, signed_transaction)
}
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService {
client
.gas_price_statistics(100, 8)
.map(|x| x[4])
.unwrap_or_else(|_| miner.sensible_gas_price())
}

View File

@@ -0,0 +1,188 @@
// 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 Error codes and error objects
macro_rules! rpc_unimplemented {
() => (Err(::v1::helpers::errors::unimplemented()))
}
use std::fmt;
use ethcore::error::Error as EthcoreError;
use ethcore::account_provider::{Error as AccountError};
use jsonrpc_core::{Error, ErrorCode, Value};
mod codes {
// NOTE [ToDr] Codes from [-32099, -32000]
pub const UNSUPPORTED_REQUEST: i64 = -32000;
pub const NO_WORK: i64 = -32001;
pub const NO_AUTHOR: i64 = -32002;
pub const UNKNOWN_ERROR: i64 = -32009;
pub const TRANSACTION_ERROR: i64 = -32010;
pub const ACCOUNT_LOCKED: i64 = -32020;
pub const PASSWORD_INVALID: i64 = -32021;
pub const ACCOUNT_ERROR: i64 = -32023;
pub const SIGNER_DISABLED: i64 = -32030;
pub const REQUEST_REJECTED: i64 = -32040;
pub const REQUEST_NOT_FOUND: i64 = -32041;
pub const COMPILATION_ERROR: i64 = -32050;
}
pub fn unimplemented() -> Error {
Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "This request is not implemented yet. Please create an issue on Github repo.".into(),
data: None
}
}
pub fn request_not_found() -> Error {
Error {
code: ErrorCode::ServerError(codes::REQUEST_NOT_FOUND),
message: "Request not found.".into(),
data: None,
}
}
pub fn request_rejected() -> Error {
Error {
code: ErrorCode::ServerError(codes::REQUEST_REJECTED),
message: "Request has been rejected.".into(),
data: None,
}
}
pub fn account<T: fmt::Debug>(error: &str, details: T) -> Error {
Error {
code: ErrorCode::ServerError(codes::ACCOUNT_ERROR),
message: error.into(),
data: Some(Value::String(format!("{:?}", details))),
}
}
pub fn compilation<T: fmt::Debug>(error: T) -> Error {
Error {
code: ErrorCode::ServerError(codes::COMPILATION_ERROR),
message: "Error while compiling code.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
pub fn internal<T: fmt::Debug>(error: &str, data: T) -> Error {
Error {
code: ErrorCode::InternalError,
message: format!("Internal error occurred: {}", error),
data: Some(Value::String(format!("{:?}", data))),
}
}
pub fn invalid_params<T: fmt::Debug>(param: &str, details: T) -> Error {
Error {
code: ErrorCode::InvalidParams,
message: format!("Couldn't parse parameters: {}", param),
data: Some(Value::String(format!("{:?}", details))),
}
}
pub fn state_pruned() -> Error {
Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "This request is not supported because your node is running with state pruning. Run with --pruning=archive.".into(),
data: None
}
}
pub fn no_work() -> Error {
Error {
code: ErrorCode::ServerError(codes::NO_WORK),
message: "Still syncing.".into(),
data: None
}
}
pub fn no_author() -> Error {
Error {
code: ErrorCode::ServerError(codes::NO_AUTHOR),
message: "Author not configured. Run Parity with --author to configure.".into(),
data: None
}
}
pub fn signer_disabled() -> Error {
Error {
code: ErrorCode::ServerError(codes::SIGNER_DISABLED),
message: "Trusted Signer is disabled. This API is not available.".into(),
data: None
}
}
pub fn from_signing_error(error: AccountError) -> Error {
Error {
code: ErrorCode::ServerError(codes::ACCOUNT_LOCKED),
message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
pub fn from_password_error(error: AccountError) -> Error {
Error {
code: ErrorCode::ServerError(codes::PASSWORD_INVALID),
message: "Account password is invalid or account does not exist.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
pub fn from_transaction_error(error: EthcoreError) -> Error {
use ethcore::error::TransactionError::*;
if let EthcoreError::Transaction(e) = error {
let msg = match e {
AlreadyImported => "Transaction with the same hash was already imported.".into(),
Old => "Transaction nonce is too low. Try incrementing the nonce.".into(),
TooCheapToReplace => {
"Transaction fee is too low. There is another transaction with same nonce in the queue. Try increasing the fee or incrementing the nonce.".into()
},
LimitReached => {
"There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into()
},
InsufficientGasPrice { minimal, got } => {
format!("Transaction fee is too low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got)
},
InsufficientBalance { balance, cost } => {
format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
},
GasLimitExceeded { limit, got } => {
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
},
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
};
Error {
code: ErrorCode::ServerError(codes::TRANSACTION_ERROR),
message: msg,
data: None,
}
} else {
Error {
code: ErrorCode::ServerError(codes::UNKNOWN_ERROR),
message: "Unknown error when sending transaction.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
}

View File

@@ -14,6 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
#[macro_use]
pub mod errors;
pub mod dispatch;
pub mod params;
mod poll_manager;
mod poll_filter;
mod requests;

View File

@@ -22,10 +22,6 @@ pub struct NetworkSettings {
pub name: String,
/// Name of the chain we are connected to
pub chain: String,
/// Min number of peers
pub min_peers: u32,
/// Max number of peers
pub max_peers: u32,
/// Networking port
pub network_port: u16,
/// Is JSON-RPC server enabled?
@@ -41,8 +37,6 @@ impl Default for NetworkSettings {
NetworkSettings {
name: "".into(),
chain: "homestead".into(),
min_peers: 25,
max_peers: 50,
network_port: 30303,
rpc_enabled: true,
rpc_interface: "local".into(),

View File

@@ -0,0 +1,53 @@
// 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/>.
//! Parameters parsing helpers
use serde;
use jsonrpc_core::{Error, Params, from_params};
use v1::types::BlockNumber;
use v1::helpers::errors;
pub fn expect_no_params(params: Params) -> Result<(), Error> {
match params {
Params::None => Ok(()),
p => Err(errors::invalid_params("No parameters were expected", p)),
}
}
fn params_len(params: &Params) -> usize {
match params {
&Params::Array(ref vec) => vec.len(),
_ => 0,
}
}
/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
pub fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
match params_len(&params) {
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
_ => from_params::<(F, BlockNumber)>(params),
}
}
/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
pub fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
match params_len(&params) {
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
_ => from_params::<(F1, F2, BlockNumber)>(params)
}
}

View File

@@ -23,7 +23,6 @@ use std::process::{Command, Stdio};
use std::thread;
use std::time::{Instant, Duration};
use std::sync::{Arc, Weak};
use std::ops::Deref;
use ethsync::{SyncProvider, SyncState};
use ethcore::miner::{MinerService, ExternalMinerService};
use jsonrpc_core::*;
@@ -43,8 +42,9 @@ use ethcore::filter::Filter as EthcoreFilter;
use self::ethash::SeedHashCompute;
use v1::traits::Eth;
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256};
use v1::helpers::CallRequest as CRequest;
use v1::impls::{default_gas_price, dispatch_transaction, error_codes, from_params_default_second, from_params_default_third};
use v1::helpers::{CallRequest as CRequest, errors};
use v1::helpers::dispatch::{default_gas_price, dispatch_transaction};
use v1::helpers::params::{expect_no_params, from_params_default_second, from_params_default_third};
/// Eth RPC options
pub struct EthClientOptions {
@@ -214,30 +214,6 @@ pub fn pending_logs<M>(miner: &M, filter: &EthcoreFilter) -> Vec<Log> where M: M
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
fn make_unsupported_err() -> Error {
Error {
code: ErrorCode::ServerError(error_codes::UNSUPPORTED_REQUEST_CODE),
message: "Unsupported request.".into(),
data: None
}
}
fn no_work_err() -> Error {
Error {
code: ErrorCode::ServerError(error_codes::NO_WORK_CODE),
message: "Still syncing.".into(),
data: None
}
}
fn no_author_err() -> Error {
Error {
code: ErrorCode::ServerError(error_codes::NO_AUTHOR_CODE),
message: "Author not configured. Run parity with --author to configure.".into(),
data: None
}
}
impl<C, S: ?Sized, M, EM> EthClient<C, S, M, EM> where
C: MiningBlockChainClient + 'static,
S: SyncProvider + 'static,
@@ -265,94 +241,80 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())),
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned()))
}
fn syncing(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let status = take_weak!(self.sync).status();
let res = match status.state {
SyncState::Idle => SyncStatus::None,
SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => {
let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number);
let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number));
try!(expect_no_params(params));
if highest_block > current_block + U256::from(6) {
let info = SyncInfo {
starting_block: status.start_block_number.into(),
current_block: current_block.into(),
highest_block: highest_block.into(),
};
SyncStatus::Info(info)
} else {
SyncStatus::None
}
}
};
to_value(&res)
let status = take_weak!(self.sync).status();
let res = match status.state {
SyncState::Idle => SyncStatus::None,
SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => {
let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number);
let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number));
if highest_block > current_block + U256::from(6) {
let info = SyncInfo {
starting_block: status.start_block_number.into(),
current_block: current_block.into(),
highest_block: highest_block.into(),
};
SyncStatus::Info(info)
} else {
SyncStatus::None
}
}
_ => Err(Error::invalid_params()),
}
};
to_value(&res)
}
fn author(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => to_value(&RpcH160::from(take_weak!(self.miner).author())),
_ => Err(Error::invalid_params()),
}
try!(expect_no_params(params));
to_value(&RpcH160::from(take_weak!(self.miner).author()))
}
fn is_mining(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => to_value(&(take_weak!(self.miner).is_sealing())),
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
to_value(&(take_weak!(self.miner).is_sealing()))
}
fn hashrate(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => to_value(&RpcU256::from(self.external_miner.hashrate())),
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
to_value(&RpcU256::from(self.external_miner.hashrate()))
}
fn gas_price(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
to_value(&RpcU256::from(default_gas_price(&*client, &*miner)))
}
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
to_value(&RpcU256::from(default_gas_price(&*client, &*miner)))
}
fn accounts(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|_| Error::internal_error()));
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
},
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e)));
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
}
fn block_number(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => to_value(&RpcU256::from(take_weak!(self.client).chain_info().best_block_number)),
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
to_value(&RpcU256::from(take_weak!(self.client).chain_info().best_block_number))
}
fn balance(&self, params: Params) -> Result<Value, Error> {
@@ -361,8 +323,11 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
.and_then(|(address, block_number,)| {
let address: Address = RpcH160::into(address);
match block_number {
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).balance(take_weak!(self.client).deref(), &address))),
id => to_value(&RpcU256::from(try!(take_weak!(self.client).balance(&address, id.into()).ok_or_else(make_unsupported_err)))),
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).balance(&*take_weak!(self.client), &address))),
id => match take_weak!(self.client).balance(&address, id.into()) {
Some(balance) => to_value(&RpcU256::from(balance)),
None => Err(errors::state_pruned()),
}
}
})
}
@@ -377,7 +342,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position)))),
id => match take_weak!(self.client).storage_at(&address, &H256::from(position), id.into()) {
Some(s) => to_value(&RpcH256::from(s)),
None => Err(make_unsupported_err()), // None is only returned on unsupported requests.
None => Err(errors::state_pruned()),
}
}
})
@@ -390,8 +355,11 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
.and_then(|(address, block_number,)| {
let address: Address = RpcH160::into(address);
match block_number {
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).nonce(take_weak!(self.client).deref(), &address))),
id => to_value(&take_weak!(self.client).nonce(&address, id.into()).map(RpcU256::from)),
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address))),
id => match take_weak!(self.client).nonce(&address, id.into()) {
Some(nonce) => to_value(&RpcU256::from(nonce)),
None => Err(errors::state_pruned()),
}
}
})
}
@@ -440,9 +408,11 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
.and_then(|(address, block_number,)| {
let address: Address = RpcH160::into(address);
match block_number {
BlockNumber::Pending => to_value(&take_weak!(self.miner).code(take_weak!(self.client).deref(), &address).map_or_else(Bytes::default, Bytes::new)),
BlockNumber::Latest => to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new)),
_ => Err(Error::invalid_params()),
BlockNumber::Pending => to_value(&take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)),
_ => match take_weak!(self.client).code(&address, block_number.into()) {
Some(code) => to_value(&code.map_or_else(Bytes::default, Bytes::new)),
None => Err(errors::state_pruned()),
},
}
})
}
@@ -515,16 +485,13 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
fn compilers(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let mut compilers = vec![];
if Command::new(SOLC).output().is_ok() {
compilers.push("solidity".to_owned())
}
to_value(&compilers)
}
_ => Err(Error::invalid_params())
try!(expect_no_params(params));
let mut compilers = vec![];
if Command::new(SOLC).output().is_ok() {
compilers.push("solidity".to_owned())
}
to_value(&compilers)
}
fn logs(&self, params: Params) -> Result<Value, Error> {
@@ -539,7 +506,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
.collect::<Vec<Log>>();
if include_pending {
let pending = pending_logs(take_weak!(self.miner).deref(), &filter);
let pending = pending_logs(&*take_weak!(self.miner), &filter);
logs.extend(pending);
}
@@ -549,45 +516,42 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
fn work(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let client = take_weak!(self.client);
// check if we're still syncing and return empty strings in that case
{
//TODO: check if initial sync is complete here
//let sync = take_weak!(self.sync);
if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON {
trace!(target: "miner", "Syncing. Cannot give any work.");
return Err(no_work_err());
}
try!(expect_no_params(params));
// Otherwise spin until our submitted block has been included.
let timeout = Instant::now() + Duration::from_millis(1000);
while Instant::now() < timeout && client.queue_info().total_queue_size() > 0 {
thread::sleep(Duration::from_millis(1));
}
}
let client = take_weak!(self.client);
// check if we're still syncing and return empty strings in that case
{
//TODO: check if initial sync is complete here
//let sync = take_weak!(self.sync);
if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON {
trace!(target: "miner", "Syncing. Cannot give any work.");
return Err(errors::no_work());
}
let miner = take_weak!(self.miner);
if miner.author().is_zero() {
warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!");
return Err(no_author_err())
}
miner.map_sealing_work(client.deref(), |b| {
let pow_hash = b.hash();
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
let seed_hash = self.seed_compute.lock().get_seedhash(b.block().header().number());
if self.options.send_block_number_in_get_work {
let block_number = RpcU256::from(b.block().header().number());
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target), block_number))
} else {
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target)))
}
}).unwrap_or(Err(Error::internal_error())) // no work found.
},
_ => Err(Error::invalid_params())
// Otherwise spin until our submitted block has been included.
let timeout = Instant::now() + Duration::from_millis(1000);
while Instant::now() < timeout && client.queue_info().total_queue_size() > 0 {
thread::sleep(Duration::from_millis(1));
}
}
let miner = take_weak!(self.miner);
if miner.author().is_zero() {
warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!");
return Err(errors::no_author())
}
miner.map_sealing_work(&*client, |b| {
let pow_hash = b.hash();
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
let seed_hash = self.seed_compute.lock().get_seedhash(b.block().header().number());
if self.options.send_block_number_in_get_work {
let block_number = RpcU256::from(b.block().header().number());
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target), block_number))
} else {
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target)))
}
}).unwrap_or(Err(Error::internal_error())) // no work found.
}
fn submit_work(&self, params: Params) -> Result<Value, Error> {
@@ -600,7 +564,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
let miner = take_weak!(self.miner);
let client = take_weak!(self.client);
let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()];
let r = miner.submit_seal(client.deref(), pow_hash, seal);
let r = miner.submit_seal(&*client, pow_hash, seal);
to_value(&r.is_ok())
})
}
@@ -627,13 +591,12 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
fn call(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
trace!(target: "jsonrpc", "call: {:?}", params);
from_params_default_second(params)
.and_then(|(request, block_number,)| {
let request = CallRequest::into(request);
let signed = try!(self.sign_call(request));
let r = match block_number {
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()),
block_number => take_weak!(self.client).call(&signed, block_number.into(), Default::default()),
};
to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![])))
@@ -647,7 +610,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
let request = CallRequest::into(request);
let signed = try!(self.sign_call(request));
let r = match block_number {
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()),
block => take_weak!(self.client).call(&signed, block.into(), Default::default()),
};
to_value(&RpcU256::from(r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))))
@@ -675,17 +638,23 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn();
if let Ok(mut child) = maybe_child {
if let Ok(_) = child.stdin.as_mut().expect("we called child.stdin(Stdio::piped()) before spawn; qed").write_all(code.as_bytes()) {
if let Ok(output) = child.wait_with_output() {
let s = String::from_utf8_lossy(&output.stdout);
if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() {
return to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![])));
}
maybe_child
.map_err(errors::compilation)
.and_then(|mut child| {
try!(child.stdin.as_mut()
.expect("we called child.stdin(Stdio::piped()) before spawn; qed")
.write_all(code.as_bytes())
.map_err(errors::compilation));
let output = try!(child.wait_with_output().map_err(errors::compilation));
let s = String::from_utf8_lossy(&output.stdout);
if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() {
to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![])))
} else {
Err(errors::compilation("Unexpected output."))
}
}
}
Err(Error::invalid_params())
})
})
}
}

View File

@@ -16,7 +16,6 @@
//! Eth Filter RPC implementation
use std::ops::Deref;
use std::sync::{Arc, Weak};
use std::collections::HashSet;
use jsonrpc_core::*;
@@ -27,6 +26,7 @@ use util::Mutex;
use v1::traits::EthFilter;
use v1::types::{BlockNumber, Index, Filter, Log, H256 as RpcH256, U256 as RpcU256};
use v1::helpers::{PollFilter, PollManager};
use v1::helpers::params::expect_no_params;
use v1::impls::eth::pending_logs;
/// Eth filter rpc implementation.
@@ -76,28 +76,22 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
fn new_block_filter(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let mut polls = self.polls.lock();
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
to_value(&RpcU256::from(id))
},
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
let mut polls = self.polls.lock();
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
to_value(&RpcU256::from(id))
}
fn new_pending_transaction_filter(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let mut polls = self.polls.lock();
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes();
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
try!(expect_no_params(params));
to_value(&RpcU256::from(id))
},
_ => Err(Error::invalid_params())
}
let mut polls = self.polls.lock();
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes();
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
to_value(&RpcU256::from(id))
}
fn filter_changes(&self, params: Params) -> Result<Value, Error> {
@@ -165,7 +159,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
// additionally retrieve pending logs
if include_pending {
let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter);
let pending_logs = pending_logs(&*take_weak!(self.miner), &filter);
// remove logs about which client was already notified about
let new_pending_logs: Vec<_> = pending_logs.iter()
@@ -206,7 +200,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
.collect::<Vec<Log>>();
if include_pending {
logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter));
logs.extend(pending_logs(&*take_weak!(self.miner), &filter));
}
to_value(&logs)

View File

@@ -23,10 +23,10 @@ use ethcore::client::MiningBlockChainClient;
use util::{U256, Address, H256, Mutex};
use transient_hashmap::TransientHashMap;
use ethcore::account_provider::AccountProvider;
use v1::helpers::{SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationsQueue, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest};
use v1::helpers::{errors, SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationsQueue, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest};
use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch};
use v1::traits::EthSigning;
use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U256 as RpcU256};
use v1::impls::{default_gas_price, sign_and_dispatch, request_rejected_error, request_not_found_error, signer_disabled_error};
fn fill_optional_fields<C, M>(request: TRequest, client: &C, miner: &M) -> FilledRequest
where C: MiningBlockChainClient, M: MinerService {
@@ -151,10 +151,10 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
let res = match pending.get(&id) {
Some(ref promise) => match promise.result() {
ConfirmationResult::Waiting => { return Ok(Value::Null); }
ConfirmationResult::Rejected => Err(request_rejected_error()),
ConfirmationResult::Rejected => Err(errors::request_rejected()),
ConfirmationResult::Confirmed(rpc_response) => rpc_response,
},
_ => { return Err(request_not_found_error()); }
_ => { return Err(errors::request_not_found()); }
};
pending.remove(&id);
res
@@ -217,16 +217,16 @@ impl<C, M> EthSigning for EthSigningUnsafeClient<C, M> where
fn post_sign(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(signer_disabled_error())
Err(errors::signer_disabled())
}
fn post_transaction(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(signer_disabled_error())
Err(errors::signer_disabled())
}
fn check_request(&self, _: Params) -> Result<Value, Error> {
// We don't support this in non-signer mode.
Err(signer_disabled_error())
Err(errors::signer_disabled())
}
}

View File

@@ -18,34 +18,48 @@
use util::{RotatingLogger};
use util::misc::version_data;
use std::sync::{Arc, Weak};
use std::ops::Deref;
use std::collections::{BTreeMap};
use ethcore::client::{MiningBlockChainClient};
use jsonrpc_core::*;
use ethsync::{SyncProvider, ManageNetwork};
use ethcore::miner::MinerService;
use ethcore::client::{MiningBlockChainClient};
use jsonrpc_core::*;
use v1::traits::Ethcore;
use v1::types::{Bytes, U256};
use v1::helpers::{SigningQueue, ConfirmationsQueue, NetworkSettings};
use v1::impls::signer_disabled_error;
use v1::types::{Bytes, U256, Peers};
use v1::helpers::{errors, SigningQueue, ConfirmationsQueue, NetworkSettings};
use v1::helpers::params::expect_no_params;
/// Ethcore implementation.
pub struct EthcoreClient<C, M> where
pub struct EthcoreClient<C, M, S: ?Sized> where
C: MiningBlockChainClient,
M: MinerService {
M: MinerService,
S: SyncProvider {
client: Weak<C>,
miner: Weak<M>,
sync: Weak<S>,
net: Weak<ManageNetwork>,
logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>,
confirmations_queue: Option<Arc<ConfirmationsQueue>>,
}
impl<C, M> EthcoreClient<C, M> where C: MiningBlockChainClient, M: MinerService {
impl<C, M, S: ?Sized> EthcoreClient<C, M, S> where C: MiningBlockChainClient, M: MinerService, S: SyncProvider {
/// Creates new `EthcoreClient`.
pub fn new(client: &Arc<C>, miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>, queue: Option<Arc<ConfirmationsQueue>>) -> Self {
pub fn new(
client: &Arc<C>,
miner: &Arc<M>,
sync: &Arc<S>,
net: &Arc<ManageNetwork>,
logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>,
queue: Option<Arc<ConfirmationsQueue>>
) -> Self {
EthcoreClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
sync: Arc::downgrade(sync),
net: Arc::downgrade(net),
logger: logger,
settings: settings,
confirmations_queue: queue,
@@ -59,66 +73,86 @@ impl<C, M> EthcoreClient<C, M> where C: MiningBlockChainClient, M: MinerService
}
}
impl<C, M> Ethcore for EthcoreClient<C, M> where M: MinerService + 'static, C: MiningBlockChainClient + 'static {
impl<C, M, S: ?Sized> Ethcore for EthcoreClient<C, M, S> where M: MinerService + 'static, C: MiningBlockChainClient + 'static, S: SyncProvider + 'static {
fn transactions_limit(&self, _: Params) -> Result<Value, Error> {
fn transactions_limit(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&take_weak!(self.miner).transactions_limit())
}
fn min_gas_price(&self, _: Params) -> Result<Value, Error> {
fn min_gas_price(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&U256::from(take_weak!(self.miner).minimal_gas_price()))
}
fn extra_data(&self, _: Params) -> Result<Value, Error> {
fn extra_data(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&Bytes::new(take_weak!(self.miner).extra_data()))
}
fn gas_floor_target(&self, _: Params) -> Result<Value, Error> {
fn gas_floor_target(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&U256::from(take_weak!(self.miner).gas_floor_target()))
}
fn gas_ceil_target(&self, _: Params) -> Result<Value, Error> {
fn gas_ceil_target(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&U256::from(take_weak!(self.miner).gas_ceil_target()))
}
fn dev_logs(&self, _params: Params) -> Result<Value, Error> {
fn dev_logs(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
let logs = self.logger.logs();
to_value(&logs.deref().as_slice())
to_value(&logs.as_slice())
}
fn dev_logs_levels(&self, _params: Params) -> Result<Value, Error> {
fn dev_logs_levels(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&self.logger.levels())
}
fn net_chain(&self, _params: Params) -> Result<Value, Error> {
fn net_chain(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&self.settings.chain)
}
fn net_max_peers(&self, _params: Params) -> Result<Value, Error> {
fn net_peers(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
to_value(&self.settings.max_peers)
try!(expect_no_params(params));
let sync_status = take_weak!(self.sync).status();
let net_config = take_weak!(self.net).network_config();
to_value(&Peers {
active: sync_status.num_active_peers,
connected: sync_status.num_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, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&self.settings.network_port)
}
fn node_name(&self, _params: Params) -> Result<Value, Error> {
fn node_name(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
to_value(&self.settings.name)
}
fn rpc_settings(&self, _params: Params) -> Result<Value, Error> {
fn rpc_settings(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
let mut map = BTreeMap::new();
map.insert("enabled".to_owned(), Value::Bool(self.settings.rpc_enabled));
map.insert("interface".to_owned(), Value::String(self.settings.rpc_interface.clone()));
@@ -128,30 +162,29 @@ impl<C, M> Ethcore for EthcoreClient<C, M> where M: MinerService + 'static, C: M
fn default_extra_data(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => to_value(&Bytes::new(version_data())),
_ => Err(Error::invalid_params()),
}
try!(expect_no_params(params));
to_value(&Bytes::new(version_data()))
}
fn gas_price_statistics(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => match take_weak!(self.client).gas_price_statistics(100, 8) {
Ok(stats) => to_value(&stats
.into_iter()
.map(|x| to_value(&U256::from(x)).expect("x must be U256; qed"))
.collect::<Vec<_>>()),
_ => Err(Error::internal_error()),
},
_ => Err(Error::invalid_params()),
try!(expect_no_params(params));
match take_weak!(self.client).gas_price_statistics(100, 8) {
Ok(stats) => to_value(&stats
.into_iter()
.map(|x| to_value(&U256::from(x)).expect("x must be U256; qed"))
.collect::<Vec<_>>()),
_ => Err(Error::internal_error()),
}
}
fn unsigned_transactions_count(&self, _params: Params) -> Result<Value, Error> {
fn unsigned_transactions_count(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
match self.confirmations_queue {
None => Err(signer_disabled_error()),
None => Err(errors::signer_disabled()),
Some(ref queue) => to_value(&queue.len()),
}
}

View File

@@ -20,6 +20,8 @@ use jsonrpc_core::*;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use ethsync::ManageNetwork;
use v1::helpers::errors;
use v1::helpers::params::expect_no_params;
use v1::traits::EthcoreSet;
use v1::types::{Bytes, H160, U256};
@@ -117,7 +119,7 @@ impl<C, M> EthcoreSet for EthcoreSetClient<C, M> where
from_params::<(String,)>(params).and_then(|(peer,)| {
match take_weak!(self.net).add_reserved_peer(peer) {
Ok(()) => to_value(&true),
Err(_) => Err(Error::invalid_params()),
Err(e) => Err(errors::invalid_params("Peer address", e)),
}
})
}
@@ -127,29 +129,33 @@ impl<C, M> EthcoreSet for EthcoreSetClient<C, M> where
from_params::<(String,)>(params).and_then(|(peer,)| {
match take_weak!(self.net).remove_reserved_peer(peer) {
Ok(()) => to_value(&true),
Err(_) => Err(Error::invalid_params()),
Err(e) => Err(errors::invalid_params("Peer address", e)),
}
})
}
fn drop_non_reserved_peers(&self, _: Params) -> Result<Value, Error> {
fn drop_non_reserved_peers(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
take_weak!(self.net).deny_unreserved_peers();
to_value(&true)
}
fn accept_non_reserved_peers(&self, _: Params) -> Result<Value, Error> {
fn accept_non_reserved_peers(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
take_weak!(self.net).accept_unreserved_peers();
to_value(&true)
}
fn start_network(&self, _: Params) -> Result<Value, Error> {
fn start_network(&self, params: Params) -> Result<Value, Error> {
try!(expect_no_params(params));
take_weak!(self.net).start_network();
Ok(Value::Bool(true))
}
fn stop_network(&self, _: Params) -> Result<Value, Error> {
fn stop_network(&self, params: Params) -> Result<Value, Error> {
try!(expect_no_params(params));
take_weak!(self.net).stop_network();
Ok(Value::Bool(true))
}

View File

@@ -25,21 +25,17 @@ macro_rules! take_weak {
}
}
macro_rules! rpc_unimplemented {
() => (Err(Error::internal_error()))
}
mod web3;
mod eth;
mod eth_filter;
mod eth_signing;
mod ethcore;
mod ethcore_set;
mod net;
mod personal;
mod personal_signer;
mod ethcore;
mod ethcore_set;
mod traces;
mod rpc;
mod traces;
mod web3;
pub use self::web3::Web3Client;
pub use self::eth::{EthClient, EthClientOptions};
@@ -53,202 +49,3 @@ pub use self::ethcore_set::EthcoreSetClient;
pub use self::traces::TracesClient;
pub use self::rpc::RpcClient;
use serde;
use v1::helpers::TransactionRequest;
use v1::types::{H256 as RpcH256, H520 as RpcH520, BlockNumber};
use ethcore::error::Error as EthcoreError;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
use ethcore::transaction::{Action, SignedTransaction, Transaction};
use ethcore::account_provider::{AccountProvider, Error as AccountError};
use util::numbers::*;
use util::rlp::encode;
use util::bytes::ToPretty;
use jsonrpc_core::{Error, ErrorCode, Value, to_value, from_params, Params};
mod error_codes {
// NOTE [ToDr] Codes from [-32099, -32000]
pub const UNSUPPORTED_REQUEST_CODE: i64 = -32000;
pub const NO_WORK_CODE: i64 = -32001;
pub const NO_AUTHOR_CODE: i64 = -32002;
pub const UNKNOWN_ERROR: i64 = -32009;
pub const TRANSACTION_ERROR: i64 = -32010;
pub const ACCOUNT_LOCKED: i64 = -32020;
pub const PASSWORD_INVALID: i64 = -32021;
pub const SIGNER_DISABLED: i64 = -32030;
pub const REQUEST_REJECTED: i64 = -32040;
pub const REQUEST_NOT_FOUND: i64 = -32041;
}
fn params_len(params: &Params) -> usize {
match params {
&Params::Array(ref vec) => vec.len(),
_ => 0,
}
}
/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
pub fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
match params_len(&params) {
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
_ => from_params::<(F, BlockNumber)>(params),
}
}
/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
pub fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
match params_len(&params) {
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
_ => from_params::<(F1, F2, BlockNumber)>(params)
}
}
fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
where C: MiningBlockChainClient, M: MinerService {
let hash = RpcH256::from(signed_transaction.hash());
let import = miner.import_own_transaction(client, signed_transaction);
import
.map_err(transaction_error)
.and_then(|_| to_value(&hash))
}
fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result<Value, Error> {
accounts.sign_with_password(address, pass, hash)
.map_err(password_error)
.and_then(|hash| to_value(&RpcH520::from(hash)))
}
fn prepare_transaction<C, M>(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService {
Transaction {
nonce: request.nonce
.or_else(|| miner
.last_nonce(&request.from)
.map(|nonce| nonce + U256::one()))
.unwrap_or_else(|| client.latest_nonce(&request.from)),
action: request.to.map_or(Action::Create, Action::Call),
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
value: request.value.unwrap_or_else(U256::zero),
data: request.data.map_or_else(Vec::new, |b| b.to_vec()),
}
}
fn unlock_sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result<Value, Error>
where C: MiningBlockChainClient, M: MinerService {
let address = request.from;
let signed_transaction = {
let t = prepare_transaction(client, miner, request);
let hash = t.hash();
let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(password_error));
t.with_signature(signature)
};
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
dispatch_transaction(&*client, &*miner, signed_transaction)
}
fn sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result<Value, Error>
where C: MiningBlockChainClient, M: MinerService {
let signed_transaction = {
let t = prepare_transaction(client, miner, request);
let hash = t.hash();
let signature = try!(account_provider.sign(address, hash).map_err(signing_error));
t.with_signature(signature)
};
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
dispatch_transaction(&*client, &*miner, signed_transaction)
}
fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService {
client
.gas_price_statistics(100, 8)
.map(|x| x[4])
.unwrap_or_else(|_| miner.sensible_gas_price())
}
fn signer_disabled_error() -> Error {
Error {
code: ErrorCode::ServerError(error_codes::SIGNER_DISABLED),
message: "Trusted Signer is disabled. This API is not available.".into(),
data: None
}
}
fn signing_error(error: AccountError) -> Error {
Error {
code: ErrorCode::ServerError(error_codes::ACCOUNT_LOCKED),
message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
fn password_error(error: AccountError) -> Error {
Error {
code: ErrorCode::ServerError(error_codes::PASSWORD_INVALID),
message: "Account password is invalid or account does not exist.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
/// Error returned when request is rejected (in Trusted Signer).
pub fn request_rejected_error() -> Error {
Error {
code: ErrorCode::ServerError(error_codes::REQUEST_REJECTED),
message: "Request has been rejected.".into(),
data: None,
}
}
/// Error returned when request is not found in queue.
pub fn request_not_found_error() -> Error {
Error {
code: ErrorCode::ServerError(error_codes::REQUEST_NOT_FOUND),
message: "Request not found.".into(),
data: None,
}
}
fn transaction_error(error: EthcoreError) -> Error {
use ethcore::error::TransactionError::*;
if let EthcoreError::Transaction(e) = error {
let msg = match e {
AlreadyImported => "Transaction with the same hash was already imported.".into(),
Old => "Transaction nonce is too low. Try incrementing the nonce.".into(),
TooCheapToReplace => {
"Transaction fee is too low. There is another transaction with same nonce in the queue. Try increasing the fee or incrementing the nonce.".into()
},
LimitReached => {
"There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into()
},
InsufficientGasPrice { minimal, got } => {
format!("Transaction fee is too low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got)
},
InsufficientBalance { balance, cost } => {
format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
},
GasLimitExceeded { limit, got } => {
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
},
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
};
Error {
code: ErrorCode::ServerError(error_codes::TRANSACTION_ERROR),
message: msg,
data: None,
}
} else {
Error {
code: ErrorCode::ServerError(error_codes::UNKNOWN_ERROR),
message: "Unknown error when sending transaction.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
}

View File

@@ -19,6 +19,7 @@ use std::sync::{Arc, Weak};
use jsonrpc_core::*;
use ethsync::SyncProvider;
use v1::traits::Net;
use v1::helpers::params::expect_no_params;
/// Net rpc implementation.
pub struct NetClient<S: ?Sized> where S: SyncProvider {
@@ -35,15 +36,18 @@ impl<S: ?Sized> NetClient<S> where S: SyncProvider {
}
impl<S: ?Sized> Net for NetClient<S> where S: SyncProvider + 'static {
fn version(&self, _: Params) -> Result<Value, Error> {
fn version(&self, params: Params) -> Result<Value, Error> {
try!(expect_no_params(params));
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, params: Params) -> Result<Value, Error> {
try!(expect_no_params(params));
Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned()))
}
fn is_listening(&self, _: Params) -> Result<Value, Error> {
fn is_listening(&self, params: Params) -> Result<Value, Error> {
try!(expect_no_params(params));
// right now (11 march 2016), we are always listening for incoming connections
Ok(Value::Bool(true))
}

View File

@@ -20,8 +20,9 @@ use std::collections::{BTreeMap};
use jsonrpc_core::*;
use v1::traits::Personal;
use v1::types::{H160 as RpcH160, TransactionRequest};
use v1::impls::unlock_sign_and_dispatch;
use v1::helpers::{TransactionRequest as TRequest};
use v1::helpers::{errors, TransactionRequest as TRequest};
use v1::helpers::params::expect_no_params;
use v1::helpers::dispatch::unlock_sign_and_dispatch;
use ethcore::account_provider::AccountProvider;
use util::Address;
use ethcore::client::MiningBlockChainClient;
@@ -57,8 +58,10 @@ impl<C, M> PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService
impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService {
fn signer_enabled(&self, _: Params) -> Result<Value, Error> {
fn signer_enabled(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
self.signer_port
.map(|v| to_value(&v))
.unwrap_or_else(|| to_value(&false))
@@ -66,14 +69,11 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
fn accounts(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
match params {
Params::None => {
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|_| Error::internal_error()));
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
},
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e)));
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
}
fn new_account(&self, params: Params) -> Result<Value, Error> {
@@ -83,7 +83,7 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
let store = take_weak!(self.accounts);
match store.new_account(&pass) {
Ok(address) => to_value(&RpcH160::from(address)),
Err(_) => Err(Error::internal_error())
Err(e) => Err(errors::account("Could not create account.", e)),
}
}
)
@@ -124,7 +124,7 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
let store = take_weak!(self.accounts);
from_params::<(RpcH160, _)>(params).and_then(|(addr, name)| {
let addr: Address = addr.into();
store.set_account_name(addr, name).map_err(|_| Error::invalid_params()).map(|_| Value::Null)
store.set_account_name(addr, name).map_err(|e| errors::account("Could not set account name.", e)).map(|_| Value::Null)
})
}
@@ -133,14 +133,16 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
let store = take_weak!(self.accounts);
from_params::<(RpcH160, _)>(params).and_then(|(addr, meta)| {
let addr: Address = addr.into();
store.set_account_meta(addr, meta).map_err(|_| Error::invalid_params()).map(|_| Value::Null)
store.set_account_meta(addr, meta).map_err(|e| errors::account("Could not set account meta.", e)).map(|_| Value::Null)
})
}
fn accounts_info(&self, _: Params) -> Result<Value, Error> {
fn accounts_info(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
let store = take_weak!(self.accounts);
Ok(Value::Object(try!(store.accounts_info().map_err(|_| Error::invalid_params())).into_iter().map(|(a, v)| {
let info = try!(store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e)));
Ok(Value::Object(info.into_iter().map(|(a, v)| {
let m = map![
"name".to_owned() => to_value(&v.name).unwrap(),
"meta".to_owned() => to_value(&v.meta).unwrap(),

View File

@@ -23,8 +23,9 @@ use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
use v1::traits::PersonalSigner;
use v1::types::{TransactionModification, ConfirmationRequest, U256};
use v1::impls::{unlock_sign_and_dispatch, signature_with_password};
use v1::helpers::{SigningQueue, ConfirmationsQueue, ConfirmationPayload};
use v1::helpers::{errors, SigningQueue, ConfirmationsQueue, ConfirmationPayload};
use v1::helpers::params::expect_no_params;
use v1::helpers::dispatch::{unlock_sign_and_dispatch, signature_with_password};
/// Transactions confirmation (personal) rpc implementation.
pub struct SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
@@ -55,8 +56,9 @@ impl<C: 'static, M: 'static> SignerClient<C, M> where C: MiningBlockChainClient,
impl<C: 'static, M: 'static> PersonalSigner for SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
fn requests_to_confirm(&self, _params: Params) -> Result<Value, Error> {
fn requests_to_confirm(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
let queue = take_weak!(self.queue);
to_value(&queue.requests().into_iter().map(From::from).collect::<Vec<ConfirmationRequest>>())
}
@@ -91,7 +93,7 @@ impl<C: 'static, M: 'static> PersonalSigner for SignerClient<C, M> where C: Mini
queue.request_confirmed(id, Ok(response.clone()));
}
result
}).unwrap_or_else(|| Err(Error::invalid_params()))
}).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id)))
}
)
}

View File

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

View File

@@ -23,9 +23,9 @@ use ethcore::client::{BlockChainClient, CallAnalytics, TransactionID, TraceId};
use ethcore::miner::MinerService;
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
use v1::traits::Traces;
use v1::helpers::CallRequest as CRequest;
use v1::helpers::{errors, CallRequest as CRequest};
use v1::helpers::params::from_params_default_third;
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
use v1::impls::from_params_default_third;
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
CallAnalytics {
@@ -144,7 +144,7 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
Ok(e) => to_value(&TraceResults::from(e)),
_ => Ok(Value::Null),
},
Err(_) => Err(Error::invalid_params()),
Err(e) => Err(errors::invalid_params("Transaction is not valid RLP", e)),
}
})
}

View File

@@ -19,6 +19,7 @@ use jsonrpc_core::*;
use util::version;
use v1::traits::Web3;
use v1::types::{H256, Bytes};
use v1::helpers::params::expect_no_params;
use util::sha3::Hashable;
/// Web3 rpc implementation.
@@ -31,10 +32,8 @@ impl Web3Client {
impl Web3 for Web3Client {
fn client_version(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => Ok(Value::String(version().to_owned().replace("Parity/", "Parity//"))),
_ => Err(Error::invalid_params())
}
try!(expect_no_params(params));
Ok(Value::String(version().to_owned().replace("Parity/", "Parity//")))
}
fn sha3(&self, params: Params) -> Result<Value, Error> {

View File

@@ -18,8 +18,9 @@
//!
//! Compliant with ethereum rpc.
mod impls;
#[macro_use]
mod helpers;
mod impls;
pub mod traits;
pub mod tests;

View File

@@ -15,13 +15,16 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use util::log::RotatingLogger;
use util::U256;
use ethsync::ManageNetwork;
use ethcore::client::{TestBlockChainClient};
use jsonrpc_core::IoHandler;
use v1::{Ethcore, EthcoreClient};
use v1::tests::helpers::TestMinerService;
use v1::helpers::ConfirmationsQueue;
use ethcore::client::{TestBlockChainClient};
use util::log::RotatingLogger;
use v1::helpers::NetworkSettings;
use v1::helpers::{ConfirmationsQueue, NetworkSettings};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};
use super::manage_network::TestManageNetwork;
fn miner_service() -> Arc<TestMinerService> {
Arc::new(TestMinerService::default())
@@ -31,6 +34,13 @@ fn client_service() -> Arc<TestBlockChainClient> {
Arc::new(TestBlockChainClient::default())
}
fn sync_provider() -> Arc<TestSyncProvider> {
Arc::new(TestSyncProvider::new(Config {
network_id: U256::from(3),
num_peers: 120,
}))
}
fn logger() -> Arc<RotatingLogger> {
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
}
@@ -39,8 +49,6 @@ fn settings() -> Arc<NetworkSettings> {
Arc::new(NetworkSettings {
name: "mynode".to_owned(),
chain: "testchain".to_owned(),
min_peers: 25,
max_peers: 25,
network_port: 30303,
rpc_enabled: true,
rpc_interface: "all".to_owned(),
@@ -48,16 +56,26 @@ fn settings() -> Arc<NetworkSettings> {
})
}
fn ethcore_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>) -> EthcoreClient<TestBlockChainClient, TestMinerService> {
EthcoreClient::new(client, miner, logger(), settings(), None)
fn network_service() -> Arc<ManageNetwork> {
Arc::new(TestManageNetwork)
}
fn ethcore_client(
client: &Arc<TestBlockChainClient>,
miner: &Arc<TestMinerService>,
sync: &Arc<TestSyncProvider>,
net: &Arc<ManageNetwork>) -> EthcoreClient<TestBlockChainClient, TestMinerService, TestSyncProvider> {
EthcoreClient::new(client, miner, sync, net, logger(), settings(), None)
}
#[test]
fn rpc_ethcore_extra_data() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x01020304","id":1}"#;
@@ -72,8 +90,10 @@ fn rpc_ethcore_default_extra_data() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#;
let response = format!(r#"{{"jsonrpc":"2.0","result":"0x{}","id":1}}"#, misc::version_data().to_hex());
@@ -85,8 +105,10 @@ fn rpc_ethcore_default_extra_data() {
fn rpc_ethcore_gas_floor_target() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x3039","id":1}"#;
@@ -98,8 +120,10 @@ fn rpc_ethcore_gas_floor_target() {
fn rpc_ethcore_min_gas_price() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x01312d00","id":1}"#;
@@ -111,10 +135,12 @@ fn rpc_ethcore_min_gas_price() {
fn rpc_ethcore_dev_logs() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let logger = logger();
logger.append("a".to_owned());
logger.append("b".to_owned());
let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings(), None).to_delegate();
let ethcore = EthcoreClient::new(&client, &miner, &sync, &net, logger.clone(), settings(), None).to_delegate();
let io = IoHandler::new();
io.add_delegate(ethcore);
@@ -128,8 +154,10 @@ fn rpc_ethcore_dev_logs() {
fn rpc_ethcore_dev_logs_levels() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"rpc=trace","id":1}"#;
@@ -141,8 +169,10 @@ fn rpc_ethcore_dev_logs_levels() {
fn rpc_ethcore_transactions_limit() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":1024,"id":1}"#;
@@ -154,8 +184,10 @@ fn rpc_ethcore_transactions_limit() {
fn rpc_ethcore_net_chain() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"testchain","id":1}"#;
@@ -164,14 +196,16 @@ fn rpc_ethcore_net_chain() {
}
#[test]
fn rpc_ethcore_net_max_peers() {
fn rpc_ethcore_net_peers() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":25,"id":1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPeers", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50},"id":1}"#;
assert_eq!(io.handle_request(request), Some(response.to_owned()));
}
@@ -180,8 +214,10 @@ fn rpc_ethcore_net_max_peers() {
fn rpc_ethcore_net_port() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":30303,"id":1}"#;
@@ -193,8 +229,10 @@ fn rpc_ethcore_net_port() {
fn rpc_ethcore_rpc_settings() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"enabled":true,"interface":"all","port":8545},"id":1}"#;
@@ -206,8 +244,10 @@ fn rpc_ethcore_rpc_settings() {
fn rpc_ethcore_node_name() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"mynode","id":1}"#;
@@ -219,9 +259,11 @@ fn rpc_ethcore_node_name() {
fn rpc_ethcore_unsigned_transactions_count() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
let queue = Arc::new(ConfirmationsQueue::default());
let ethcore = EthcoreClient::new(&client, &miner, logger(), settings(), Some(queue)).to_delegate();
let ethcore = EthcoreClient::new(&client, &miner, &sync, &net, logger(), settings(), Some(queue)).to_delegate();
io.add_delegate(ethcore);
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
@@ -234,8 +276,10 @@ fn rpc_ethcore_unsigned_transactions_count() {
fn rpc_ethcore_unsigned_transactions_count_when_signer_disabled() {
let miner = miner_service();
let client = client_service();
let sync = sync_provider();
let net = network_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#;

View File

@@ -45,8 +45,8 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
/// Returns chain name
fn net_chain(&self, _: Params) -> Result<Value, Error>;
/// Returns max peers
fn net_max_peers(&self, _: Params) -> Result<Value, Error>;
/// Returns peers details
fn net_peers(&self, _: Params) -> Result<Value, Error>;
/// Returns network port
fn net_port(&self, _: Params) -> Result<Value, Error>;
@@ -79,7 +79,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
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_netMaxPeers", Ethcore::net_max_peers);
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);

View File

@@ -40,7 +40,7 @@ pub use self::filter::Filter;
pub use self::hash::{H64, H160, H256, H520, H2048};
pub use self::index::Index;
pub use self::log::Log;
pub use self::sync::{SyncStatus, SyncInfo};
pub use self::sync::{SyncStatus, SyncInfo, Peers};
pub use self::transaction::Transaction;
pub use self::transaction_request::TransactionRequest;
pub use self::receipt::Receipt;

View File

@@ -31,6 +31,17 @@ pub struct SyncInfo {
pub highest_block: U256,
}
/// Peers info
#[derive(Default, Debug, Serialize, PartialEq)]
pub struct Peers {
/// Number of active peers
pub active: usize,
/// Number of connected peers
pub connected: usize,
/// Max number of peers
pub max: u32,
}
/// Sync status
#[derive(Debug, PartialEq)]
pub enum SyncStatus {
@@ -53,7 +64,7 @@ impl Serialize for SyncStatus {
#[cfg(test)]
mod tests {
use serde_json;
use super::{SyncInfo, SyncStatus};
use super::{SyncInfo, SyncStatus, Peers};
#[test]
fn test_serialize_sync_info() {
@@ -62,6 +73,13 @@ mod tests {
assert_eq!(serialized, r#"{"startingBlock":"0x00","currentBlock":"0x00","highestBlock":"0x00"}"#);
}
#[test]
fn test_serialize_peers() {
let t = Peers::default();
let serialized = serde_json::to_string(&t).unwrap();
assert_eq!(serialized, r#"{"active":0,"connected":0,"max":0}"#);
}
#[test]
fn test_serialize_sync_status() {
let t = SyncStatus::None;

View File

@@ -12,14 +12,14 @@ rustc_version = "0.1"
[dependencies]
rand = "0.3.14"
jsonrpc-core = "2.0"
jsonrpc-core = "2.1"
log = "0.3"
env_logger = "0.3"
ws = { git = "https://github.com/ethcore/ws-rs.git", branch = "stable" }
ws = { git = "https://github.com/ethcore/ws-rs.git", branch = "mio-upstream-stable" }
ethcore-util = { path = "../util" }
ethcore-io = { path = "../util/io" }
ethcore-rpc = { path = "../rpc" }
parity-dapps-signer = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6", optional = true}
parity-dapps-signer = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true}
clippy = { version = "0.0.80", optional = true}

View File

@@ -46,7 +46,7 @@ impl TimeProvider for DefaultTimeProvider {
}
/// No of seconds the hash is valid
const TIME_THRESHOLD: u64 = 2;
const TIME_THRESHOLD: u64 = 7;
const TOKEN_LENGTH: usize = 16;
/// Manages authorization codes for `SignerUIs`
@@ -102,7 +102,7 @@ impl<T: TimeProvider> AuthCodes<T> {
let now = self.now.now();
// check time
if time >= now + TIME_THRESHOLD || time <= now - TIME_THRESHOLD {
warn!(target: "signer", "Received old authentication request.");
warn!(target: "signer", "Received old authentication request. ({} vs {})", now, time);
return false;
}
@@ -169,8 +169,8 @@ mod tests {
fn should_return_false_if_hash_is_valid_but_time_is_invalid() {
// given
let code = "23521352asdfasdfadf";
let time = 105;
let time2 = 95;
let time = 107;
let time2 = 93;
let codes = AuthCodes::new(vec![code.into()], || 100);
// when

View File

@@ -146,7 +146,9 @@ impl ws::Handler for Session {
fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
let req = try!(msg.as_text());
match self.handler.handle_request(req) {
Some(res) => self.out.send(res),
Some(res) => {
self.out.send(res)
},
None => Ok(()),
}
}

View File

@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::ops::*;
use std::sync::Arc;
use network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId,
NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, NetworkError};
@@ -75,7 +74,7 @@ pub struct EthSync {
impl EthSync {
/// Creates and register protocol with the network service
pub fn new(config: SyncConfig, chain: Arc<BlockChainClient>, network_config: NetworkConfiguration) -> Result<Arc<EthSync>, NetworkError> {
let chain_sync = ChainSync::new(config, chain.deref());
let chain_sync = ChainSync::new(config, &*chain);
let service = try!(NetworkService::new(try!(network_config.into_basic())));
let sync = Arc::new(EthSync{
network: service,
@@ -108,20 +107,20 @@ impl NetworkProtocolHandler for SyncProtocolHandler {
}
fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) {
ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, self.chain.deref()), *peer, packet_id, data);
ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, &*self.chain), *peer, packet_id, data);
}
fn connected(&self, io: &NetworkContext, peer: &PeerId) {
self.sync.write().on_peer_connected(&mut NetSyncIo::new(io, self.chain.deref()), *peer);
self.sync.write().on_peer_connected(&mut NetSyncIo::new(io, &*self.chain), *peer);
}
fn disconnected(&self, io: &NetworkContext, peer: &PeerId) {
self.sync.write().on_peer_aborting(&mut NetSyncIo::new(io, self.chain.deref()), *peer);
self.sync.write().on_peer_aborting(&mut NetSyncIo::new(io, &*self.chain), *peer);
}
fn timeout(&self, io: &NetworkContext, _timer: TimerToken) {
self.sync.write().maintain_peers(&mut NetSyncIo::new(io, self.chain.deref()));
self.sync.write().maintain_sync(&mut NetSyncIo::new(io, self.chain.deref()));
self.sync.write().maintain_peers(&mut NetSyncIo::new(io, &*self.chain));
self.sync.write().maintain_sync(&mut NetSyncIo::new(io, &*self.chain));
}
}
@@ -135,7 +134,7 @@ impl ChainNotify for EthSync {
_duration: u64)
{
self.network.with_context(ETH_PROTOCOL, |context| {
let mut sync_io = NetSyncIo::new(context, self.handler.chain.deref());
let mut sync_io = NetSyncIo::new(context, &*self.handler.chain);
self.handler.sync.write().chain_new_blocks(
&mut sync_io,
&imported,
@@ -204,7 +203,7 @@ impl ManageNetwork for EthSync {
fn stop_network(&self) {
self.network.with_context(ETH_PROTOCOL, |context| {
let mut sync_io = NetSyncIo::new(context, self.handler.chain.deref());
let mut sync_io = NetSyncIo::new(context, &*self.handler.chain);
self.handler.sync.write().abort(&mut sync_io);
});
self.stop();

View File

@@ -187,6 +187,15 @@ impl SyncStatus {
pub fn is_major_syncing(&self) -> bool {
self.state != SyncState::Idle && self.state != SyncState::NewBlocks
}
/// Returns max no of peers to display in informants
pub fn current_max_peers(&self, min_peers: u32, max_peers: u32) -> u32 {
if self.num_peers as u32 > min_peers {
max_peers
} else {
min_peers
}
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
@@ -199,6 +208,16 @@ enum PeerAsking {
Heads,
}
#[derive(Clone, Eq, PartialEq)]
enum ForkConfirmation {
/// Fork block confirmation pending.
Unconfirmed,
/// Peers chain is too short to confirm the fork.
TooShort,
/// Fork is confurmed.
Confirmed,
}
#[derive(Clone)]
/// Syncing peer information
struct PeerInfo {
@@ -224,13 +243,17 @@ struct PeerInfo {
ask_time: f64,
/// Pending request is expird and result should be ignored
expired: bool,
/// Peer fork confirmed
confirmed: bool,
/// Peer fork confirmation status
confirmation: ForkConfirmation,
}
impl PeerInfo {
fn is_available(&self) -> bool {
self.confirmed && !self.expired
fn can_sync(&self) -> bool {
self.confirmation == ForkConfirmation::Confirmed && !self.expired
}
fn is_allowed(&self) -> bool {
self.confirmation != ForkConfirmation::Unconfirmed && !self.expired
}
}
@@ -307,8 +330,8 @@ impl ChainSync {
highest_block_number: self.highest_block.map(|n| max(n, self.last_imported_block)),
blocks_received: if self.last_imported_block > self.starting_block { self.last_imported_block - self.starting_block } else { 0 },
blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 },
num_peers: self.peers.values().filter(|p| p.confirmed).count(),
num_active_peers: self.peers.values().filter(|p| p.confirmed && p.asking != PeerAsking::Nothing).count(),
num_peers: self.peers.values().filter(|p| p.is_allowed()).count(),
num_active_peers: self.peers.values().filter(|p| p.is_allowed() && p.asking != PeerAsking::Nothing).count(),
mem_used:
self.blocks.heap_size()
+ self.peers.heap_size_of_children()
@@ -330,7 +353,7 @@ impl ChainSync {
p.asking_blocks.clear();
p.asking_hash = None;
// mark any pending requests as expired
if p.asking != PeerAsking::Nothing && p.confirmed {
if p.asking != PeerAsking::Nothing && p.is_allowed() {
p.expired = true;
}
}
@@ -384,7 +407,7 @@ impl ChainSync {
asking_hash: None,
ask_time: 0f64,
expired: false,
confirmed: self.fork_block.is_none(),
confirmation: if self.fork_block.is_none() { ForkConfirmation::Confirmed } else { ForkConfirmation::Unconfirmed },
};
trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis);
@@ -427,14 +450,19 @@ impl ChainSync {
Some(ref mut peer) if peer.asking == PeerAsking::ForkHeader => {
let item_count = r.item_count();
if item_count == 0 || (item_count == 1 && try!(r.at(0)).as_raw().sha3() == self.fork_block.unwrap().1) {
trace!(target: "sync", "{}: Confirmed peer", peer_id);
peer.asking = PeerAsking::Nothing;
peer.confirmed = true;
if item_count == 0 {
trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id);
peer.confirmation = ForkConfirmation::TooShort;
} else {
trace!(target: "sync", "{}: Confirmed peer", peer_id);
peer.confirmation = ForkConfirmation::Confirmed;
}
true
} else {
trace!(target: "sync", "{}: Fork mismatch", peer_id);
io.disconnect_peer(peer_id);
false
return Ok(());
}
},
_ => false,
@@ -586,7 +614,7 @@ impl ChainSync {
/// Called by peer once it has new block bodies
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
if !self.peers.get(&peer_id).map_or(false, |p| p.confirmed) {
if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) {
trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id);
return Ok(());
}
@@ -654,7 +682,7 @@ impl ChainSync {
/// Handles `NewHashes` packet. Initiates headers download for any unknown hashes.
fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
if !self.peers.get(&peer_id).map_or(false, |p| p.confirmed) {
if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) {
trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id);
return Ok(());
}
@@ -741,7 +769,7 @@ impl ChainSync {
/// Resume downloading
fn continue_sync(&mut self, io: &mut SyncIo) {
let mut peers: Vec<(PeerId, U256)> = self.peers.iter().filter_map(|(k, p)|
if p.is_available() { Some((*k, p.difficulty.unwrap_or_else(U256::zero))) } else { None }).collect();
if p.can_sync() { Some((*k, p.difficulty.unwrap_or_else(U256::zero))) } else { None }).collect();
thread_rng().shuffle(&mut peers); //TODO: sort by rating
trace!(target: "sync", "Syncing with {}/{} peers", self.active_peers.len(), peers.len());
for (p, _) in peers {
@@ -749,7 +777,7 @@ impl ChainSync {
self.sync_peer(io, p, false);
}
}
if self.state != SyncState::Waiting && !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.is_available()) {
if self.state != SyncState::Waiting && !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.can_sync()) {
self.complete_sync();
}
}
@@ -775,7 +803,7 @@ impl ChainSync {
}
let (peer_latest, peer_difficulty) = {
let peer = self.peers.get_mut(&peer_id).unwrap();
if peer.asking != PeerAsking::Nothing || !peer.is_available() {
if peer.asking != PeerAsking::Nothing || !peer.can_sync() {
return;
}
if self.state == SyncState::Waiting {
@@ -1037,7 +1065,7 @@ impl ChainSync {
if !io.is_chain_queue_empty() {
return Ok(());
}
if !self.peers.get(&peer_id).map_or(false, |p| p.confirmed) {
if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) {
trace!(target: "sync", "{} Ignoring transactions from unconfirmed/unknown peer", peer_id);
}
@@ -1357,27 +1385,23 @@ impl ChainSync {
.collect::<Vec<_>>()
}
fn select_lagging_peers(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> Vec<(PeerId, BlockNumber)> {
fn select_random_lagging_peers(&mut self, peers: &[(PeerId, BlockNumber)]) -> Vec<(PeerId, BlockNumber)> {
use rand::Rng;
let mut lagging_peers = self.get_lagging_peers(chain_info, io);
// take sqrt(x) peers
let mut peers = peers.to_vec();
let mut count = (self.peers.len() as f64).powf(0.5).round() as usize;
count = min(count, MAX_PEERS_PROPAGATION);
count = max(count, MIN_PEERS_PROPAGATION);
::rand::thread_rng().shuffle(&mut lagging_peers);
lagging_peers.into_iter().take(count).collect::<Vec<_>>()
::rand::thread_rng().shuffle(&mut peers);
peers.truncate(count);
peers
}
/// propagates latest block to lagging peers
fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, sealed: &[H256]) -> usize {
let lucky_peers: Vec<_> = if sealed.is_empty() {
self.select_lagging_peers(chain_info, io).iter().map(|&(id, _)| id).collect()
} else {
self.peers.keys().cloned().collect()
};
trace!(target: "sync", "Sending NewBlocks to {:?}", lucky_peers);
fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, sealed: &[H256], peers: &[(PeerId, BlockNumber)]) -> usize {
trace!(target: "sync", "Sending NewBlocks to {:?}", peers);
let mut sent = 0;
for peer_id in lucky_peers {
for &(peer_id, _) in peers {
if sealed.is_empty() {
let rlp = ChainSync::create_latest_block_rlp(io.chain());
self.send_packet(io, peer_id, NEW_BLOCK_PACKET, rlp);
@@ -1395,12 +1419,11 @@ impl ChainSync {
}
/// propagates new known hashes to all peers
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize {
let lucky_peers = self.select_lagging_peers(chain_info, io);
trace!(target: "sync", "Sending NewHashes to {:?}", lucky_peers);
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[(PeerId, BlockNumber)]) -> usize {
trace!(target: "sync", "Sending NewHashes to {:?}", peers);
let mut sent = 0;
let last_parent = HeaderView::new(&io.chain().block_header(BlockID::Hash(chain_info.best_block_hash.clone())).unwrap()).parent_hash();
for (peer_id, peer_number) in lucky_peers {
for &(peer_id, peer_number) in peers {
let peer_best = if chain_info.best_block_number - peer_number > MAX_PEER_LAG_PROPAGATION as BlockNumber {
// If we think peer is too far behind just send one latest hash
last_parent.clone()
@@ -1466,11 +1489,19 @@ impl ChainSync {
fn propagate_latest_blocks(&mut self, io: &mut SyncIo, sealed: &[H256]) {
let chain_info = io.chain().chain_info();
if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION {
let hashes = self.propagate_new_hashes(&chain_info, io);
let blocks = self.propagate_blocks(&chain_info, io, sealed);
if blocks != 0 || hashes != 0 {
trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
}
let mut peers = self.get_lagging_peers(&chain_info, io);
if sealed.is_empty() {
let hashes = self.propagate_new_hashes(&chain_info, io, &peers);
peers = self.select_random_lagging_peers(&peers);
let blocks = self.propagate_blocks(&chain_info, io, sealed, &peers);
if blocks != 0 || hashes != 0 {
trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
}
} else {
self.propagate_blocks(&chain_info, io, sealed, &peers);
self.propagate_new_hashes(&chain_info, io, &peers);
trace!(target: "sync", "Sent sealed block to all peers");
};
}
self.propagate_new_transactions(io);
self.last_sent_block_number = chain_info.best_block_number;
@@ -1693,7 +1724,7 @@ mod tests {
asking_hash: None,
ask_time: 0f64,
expired: false,
confirmed: true,
confirmation: super::ForkConfirmation::Confirmed,
});
sync
}
@@ -1738,7 +1769,8 @@ mod tests {
let chain_info = client.chain_info();
let mut io = TestIo::new(&mut client, &mut queue, None);
let peer_count = sync.propagate_new_hashes(&chain_info, &mut io);
let peers = sync.get_lagging_peers(&chain_info, &io);
let peer_count = sync.propagate_new_hashes(&chain_info, &mut io, &peers);
// 1 message should be send
assert_eq!(1, io.queue.len());
@@ -1756,7 +1788,8 @@ mod tests {
let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client);
let chain_info = client.chain_info();
let mut io = TestIo::new(&mut client, &mut queue, None);
let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[]);
let peers = sync.get_lagging_peers(&chain_info, &io);
let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[], &peers);
// 1 message should be send
assert_eq!(1, io.queue.len());
@@ -1775,7 +1808,8 @@ mod tests {
let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client);
let chain_info = client.chain_info();
let mut io = TestIo::new(&mut client, &mut queue, None);
let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[hash.clone()]);
let peers = sync.get_lagging_peers(&chain_info, &io);
let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[hash.clone()], &peers);
// 1 message should be send
assert_eq!(1, io.queue.len());
@@ -1881,7 +1915,8 @@ mod tests {
let chain_info = client.chain_info();
let mut io = TestIo::new(&mut client, &mut queue, None);
sync.propagate_new_hashes(&chain_info, &mut io);
let peers = sync.get_lagging_peers(&chain_info, &io);
sync.propagate_new_hashes(&chain_info, &mut io, &peers);
let data = &io.queue[0].data.clone();
let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(data));
@@ -1899,7 +1934,8 @@ mod tests {
let chain_info = client.chain_info();
let mut io = TestIo::new(&mut client, &mut queue, None);
sync.propagate_blocks(&chain_info, &mut io, &[]);
let peers = sync.get_lagging_peers(&chain_info, &io);
sync.propagate_blocks(&chain_info, &mut io, &[], &peers);
let data = &io.queue[0].data.clone();
let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(data));

View File

@@ -27,7 +27,7 @@ fn two_peers() {
net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle);
net.sync();
assert!(net.peer(0).chain.block(BlockID::Number(1000)).is_some());
assert_eq!(net.peer(0).chain.blocks.read().deref(), net.peer(1).chain.blocks.read().deref());
assert_eq!(*net.peer(0).chain.blocks.read(), *net.peer(1).chain.blocks.read());
}
#[test]
@@ -37,7 +37,7 @@ fn long_chain() {
net.peer_mut(1).chain.add_blocks(50000, EachBlockWith::Nothing);
net.sync();
assert!(net.peer(0).chain.block(BlockID::Number(50000)).is_some());
assert_eq!(net.peer(0).chain.blocks.read().deref(), net.peer(1).chain.blocks.read().deref());
assert_eq!(*net.peer(0).chain.blocks.read(), *net.peer(1).chain.blocks.read());
}
#[test]
@@ -71,7 +71,7 @@ fn empty_blocks() {
}
net.sync();
assert!(net.peer(0).chain.block(BlockID::Number(1000)).is_some());
assert_eq!(net.peer(0).chain.blocks.read().deref(), net.peer(1).chain.blocks.read().deref());
assert_eq!(*net.peer(0).chain.blocks.read(), *net.peer(1).chain.blocks.read());
}
#[test]
@@ -89,10 +89,10 @@ fn forked() {
// peer 1 has the best chain of 601 blocks
let peer1_chain = net.peer(1).chain.numbers.read().clone();
net.sync();
assert_eq!(net.peer(0).chain.difficulty.read().deref(), net.peer(1).chain.difficulty.read().deref());
assert_eq!(net.peer(0).chain.numbers.read().deref(), &peer1_chain);
assert_eq!(net.peer(1).chain.numbers.read().deref(), &peer1_chain);
assert_eq!(net.peer(2).chain.numbers.read().deref(), &peer1_chain);
assert_eq!(*net.peer(0).chain.difficulty.read(), *net.peer(1).chain.difficulty.read());
assert_eq!(&*net.peer(0).chain.numbers.read(), &peer1_chain);
assert_eq!(&*net.peer(1).chain.numbers.read(), &peer1_chain);
assert_eq!(&*net.peer(2).chain.numbers.read(), &peer1_chain);
}
#[test]
@@ -161,11 +161,11 @@ fn propagate_hashes() {
net.trigger_chain_new_blocks(0); //first event just sets the marker
net.trigger_chain_new_blocks(0);
// 5 peers to sync
assert_eq!(5, net.peer(0).queue.len());
// 5 peers with NewHahses, 4 with blocks
assert_eq!(9, net.peer(0).queue.len());
let mut hashes = 0;
let mut blocks = 0;
for i in 0..5 {
for i in 0..net.peer(0).queue.len() {
if net.peer(0).queue[i].packet_id == 0x1 {
hashes += 1;
}
@@ -173,7 +173,8 @@ fn propagate_hashes() {
blocks += 1;
}
}
assert!(blocks + hashes == 5);
assert_eq!(blocks, 4);
assert_eq!(hashes, 5);
}
#[test]
@@ -221,3 +222,4 @@ fn high_td_attach() {
assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5);
}

View File

@@ -1,11 +1,11 @@
#!/bin/sh
# Running Parity Full Test Sute
FEATURES="--features json-tests"
FEATURES="json-tests ipc"
case $1 in
--no-json)
FEATURES=""
FEATURES="ipc"
shift # past argument=value
;;
*)
@@ -14,5 +14,5 @@ case $1 in
esac
. ./scripts/targets.sh
cargo test --release $FEATURES $TARGETS $1 \
cargo test --release --features "$FEATURES" $TARGETS $1 \

View File

@@ -17,7 +17,6 @@
//! Panic utilities
use std::thread;
use std::ops::DerefMut;
use std::sync::Arc;
use std::default::Default;
@@ -91,7 +90,7 @@ impl PanicHandler {
/// You should use `catch_panic` instead of calling this method explicitly.
pub fn notify_all(&self, r: String) {
let mut listeners = self.listeners.lock();
for listener in listeners.deref_mut() {
for mut listener in &mut **listeners {
listener.call(&r);
}
}

View File

@@ -787,7 +787,7 @@ impl Host {
let entry = NodeEntry { id: s.id().unwrap().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } };
self.nodes.write().add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
let mut discovery = self.discovery.lock();
if let Some(ref mut discovery) = *discovery.deref_mut() {
if let Some(ref mut discovery) = *discovery {
discovery.add_node(entry);
}
}

View File

@@ -46,7 +46,7 @@ impl TestProtocol {
}
pub fn got_packet(&self) -> bool {
self.packet.lock().deref()[..] == b"hello"[..]
self.packet.lock()[..] == b"hello"[..]
}
pub fn got_timeout(&self) -> bool {

View File

@@ -577,9 +577,9 @@ impl Hasher for PlainHasher {
}
}
/// Specialized version of HashMap with H256 keys and fast hashing function.
/// Specialized version of `HashMap` with H256 keys and fast hashing function.
pub type H256FastMap<T> = HashMap<H256, T, BuildHasherDefault<PlainHasher>>;
/// Specialized version of HashSet with H256 keys and fast hashing function.
/// Specialized version of `HashSet` with H256 keys and fast hashing function.
pub type H256FastSet = HashSet<H256, BuildHasherDefault<PlainHasher>>;
#[cfg(test)]

View File

@@ -74,7 +74,7 @@ impl HashDB for ArchiveDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = HashMap::new();
for (key, _) in self.backing.iter(self.column) {
let h = H256::from_slice(key.deref());
let h = H256::from_slice(&*key);
ret.insert(h, 1);
}

View File

@@ -263,7 +263,7 @@ impl HashDB for EarlyMergeDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = HashMap::new();
for (key, _) in self.backing.iter(self.column) {
let h = H256::from_slice(key.deref());
let h = H256::from_slice(&*key);
ret.insert(h, 1);
}

View File

@@ -66,7 +66,8 @@ pub struct OverlayRecentDB {
#[derive(PartialEq)]
struct JournalOverlay {
backing_overlay: MemoryDB,
backing_overlay: MemoryDB, // Nodes added in the history period
pending_overlay: H256FastMap<Bytes>, // Nodes being transfered from backing_overlay to backing db
journal: HashMap<u64, Vec<JournalEntry>>,
latest_era: Option<u64>,
}
@@ -173,7 +174,11 @@ impl OverlayRecentDB {
}
}
trace!("Recovered {} overlay entries, {} journal entries", count, journal.len());
JournalOverlay { backing_overlay: overlay, journal: journal, latest_era: latest_era }
JournalOverlay {
backing_overlay: overlay,
pending_overlay: HashMap::default(),
journal: journal,
latest_era: latest_era }
}
}
@@ -194,6 +199,7 @@ impl JournalDB for OverlayRecentDB {
let mut mem = self.transaction_overlay.mem_used();
let overlay = self.journal_overlay.read();
mem += overlay.backing_overlay.mem_used();
mem += overlay.pending_overlay.heap_size_of_children();
mem += overlay.journal.heap_size_of_children();
mem
}
@@ -209,14 +215,19 @@ impl JournalDB for OverlayRecentDB {
fn latest_era(&self) -> Option<u64> { self.journal_overlay.read().latest_era }
fn state(&self, key: &H256) -> Option<Bytes> {
let v = self.journal_overlay.read().backing_overlay.get(&to_short_key(key)).map(|v| v.to_vec());
v.or_else(|| self.backing.get_by_prefix(self.column, &key[0..DB_PREFIX_LEN]).map(|b| b.to_vec()))
let journal_overlay = self.journal_overlay.read();
let key = to_short_key(key);
journal_overlay.backing_overlay.get(&key).map(|v| v.to_vec())
.or_else(|| journal_overlay.pending_overlay.get(&key).map(|v| v.clone()))
.or_else(|| self.backing.get_by_prefix(self.column, &key[0..DB_PREFIX_LEN]).map(|b| b.to_vec()))
}
fn commit(&mut self, batch: &DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result<u32, UtilError> {
// record new commit's details.
trace!("commit: #{} ({}), end era: {:?}", now, id, end);
let mut journal_overlay = self.journal_overlay.write();
// flush previous changes
journal_overlay.pending_overlay.clear();
{
let mut r = RlpStream::new_list(3);
let mut tx = self.transaction_overlay.drain();
@@ -280,7 +291,8 @@ impl JournalDB for OverlayRecentDB {
}
// apply canon inserts first
for (k, v) in canon_insertions {
try!(batch.put_vec(self.column, &k, v));
try!(batch.put(self.column, &k, &v));
journal_overlay.pending_overlay.insert(to_short_key(&k), v);
}
// update the overlay
for k in overlay_deletions {
@@ -298,6 +310,10 @@ impl JournalDB for OverlayRecentDB {
Ok(0)
}
fn flush(&self) {
self.journal_overlay.write().pending_overlay.clear();
}
fn inject(&mut self, batch: &DBTransaction) -> Result<u32, UtilError> {
let mut ops = 0;
for (key, (value, rc)) in self.transaction_overlay.drain() {
@@ -329,7 +345,7 @@ impl HashDB for OverlayRecentDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = HashMap::new();
for (key, _) in self.backing.iter(self.column) {
let h = H256::from_slice(key.deref());
let h = H256::from_slice(&*key);
ret.insert(h, 1);
}
@@ -345,14 +361,19 @@ impl HashDB for OverlayRecentDB {
match k {
Some((d, rc)) if rc > 0 => Some(d),
_ => {
let v = self.journal_overlay.read().backing_overlay.get(&to_short_key(key)).map(|v| v.to_vec());
let v = {
let journal_overlay = self.journal_overlay.read();
let key = to_short_key(key);
journal_overlay.backing_overlay.get(&key).map(|v| v.to_vec())
.or_else(|| journal_overlay.pending_overlay.get(&key).map(|v| v.clone()))
};
match v {
Some(x) => {
Some(&self.transaction_overlay.denote(key, x).0)
Some(self.transaction_overlay.denote(key, x).0)
}
_ => {
if let Some(x) = self.payload(key) {
Some(&self.transaction_overlay.denote(key, x).0)
Some(self.transaction_overlay.denote(key, x).0)
}
else {
None
@@ -920,4 +941,4 @@ mod tests {
assert!(jdb.get(&key).is_none());
}
}
}

View File

@@ -190,7 +190,7 @@ impl JournalDB for RefCountedDB {
for remove in self.removes.drain(..) {
self.forward.remove(&remove);
}
self.forward.commit_to_batch(&batch)
self.forward.commit_to_batch(batch)
}
}

View File

@@ -57,12 +57,18 @@ pub trait JournalDB: HashDB {
/// Get backing database.
fn backing(&self) -> &Arc<Database>;
/// Clear internal strucutres. This should called after changes have been written
/// to the backing strage
fn flush(&self) {}
/// Commit all changes in a single batch
#[cfg(test)]
fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result<u32, UtilError> {
let batch = self.backing().transaction();
let res = try!(self.commit(&batch, now, id, end));
self.backing().write(batch).map(|_| res).map_err(Into::into)
let result = self.backing().write(batch).map(|_| res).map_err(Into::into);
self.flush();
result
}
/// Inject all changes in a single batch.

View File

@@ -105,10 +105,10 @@ impl DBTransaction {
}
}
struct DBColumnOverlay {
insertions: HashMap<ElasticArray32<u8>, Bytes>,
compressed_insertions: HashMap<ElasticArray32<u8>, Bytes>,
deletions: HashSet<ElasticArray32<u8>>,
enum KeyState {
Insert(Bytes),
InsertCompressed(Bytes),
Delete,
}
/// Compaction profile for the database settings
@@ -172,7 +172,7 @@ impl Default for DatabaseConfig {
fn default() -> DatabaseConfig {
DatabaseConfig {
cache_size: None,
max_open_files: 1024,
max_open_files: 512,
compaction: CompactionProfile::default(),
columns: None,
wal: true,
@@ -198,7 +198,7 @@ pub struct Database {
db: DB,
write_opts: WriteOptions,
cfs: Vec<Column>,
overlay: RwLock<Vec<DBColumnOverlay>>,
overlay: RwLock<Vec<HashMap<ElasticArray32<u8>, KeyState>>>,
}
impl Database {
@@ -275,11 +275,7 @@ impl Database {
Ok(Database {
db: db,
write_opts: write_opts,
overlay: RwLock::new((0..(cfs.len() + 1)).map(|_| DBColumnOverlay {
insertions: HashMap::new(),
compressed_insertions: HashMap::new(),
deletions: HashSet::new(),
}).collect()),
overlay: RwLock::new((0..(cfs.len() + 1)).map(|_| HashMap::new()).collect()),
cfs: cfs,
})
}
@@ -302,21 +298,15 @@ impl Database {
match op {
DBOp::Insert { col, key, value } => {
let c = Self::to_overlay_column(col);
overlay[c].deletions.remove(&key);
overlay[c].compressed_insertions.remove(&key);
overlay[c].insertions.insert(key, value);
overlay[c].insert(key, KeyState::Insert(value));
},
DBOp::InsertCompressed { col, key, value } => {
let c = Self::to_overlay_column(col);
overlay[c].deletions.remove(&key);
overlay[c].insertions.remove(&key);
overlay[c].compressed_insertions.insert(key, value);
overlay[c].insert(key, KeyState::InsertCompressed(value));
},
DBOp::Delete { col, key } => {
let c = Self::to_overlay_column(col);
overlay[c].insertions.remove(&key);
overlay[c].compressed_insertions.remove(&key);
overlay[c].deletions.insert(key);
overlay[c].insert(key, KeyState::Delete);
},
}
};
@@ -328,34 +318,34 @@ impl Database {
let batch = WriteBatch::new();
let mut overlay = self.overlay.write();
let mut c = 0;
for column in overlay.iter_mut() {
let insertions = mem::replace(&mut column.insertions, HashMap::new());
let compressed_insertions = mem::replace(&mut column.compressed_insertions, HashMap::new());
let deletions = mem::replace(&mut column.deletions, HashSet::new());
for d in deletions.into_iter() {
if c > 0 {
try!(batch.delete_cf(self.cfs[c - 1], &d));
} else {
try!(batch.delete(&d));
for (c, column) in overlay.iter_mut().enumerate() {
let column_data = mem::replace(column, HashMap::new());
for (key, state) in column_data.into_iter() {
match state {
KeyState::Delete => {
if c > 0 {
try!(batch.delete_cf(self.cfs[c - 1], &key));
} else {
try!(batch.delete(&key));
}
},
KeyState::Insert(value) => {
if c > 0 {
try!(batch.put_cf(self.cfs[c - 1], &key, &value));
} else {
try!(batch.put(&key, &value));
}
},
KeyState::InsertCompressed(value) => {
let compressed = UntrustedRlp::new(&value).compress(RlpType::Blocks);
if c > 0 {
try!(batch.put_cf(self.cfs[c - 1], &key, &compressed));
} else {
try!(batch.put(&key, &value));
}
}
}
}
for (key, value) in insertions.into_iter() {
if c > 0 {
try!(batch.put_cf(self.cfs[c - 1], &key, &value));
} else {
try!(batch.put(&key, &value));
}
}
for (key, value) in compressed_insertions.into_iter() {
let compressed = UntrustedRlp::new(&value).compress(RlpType::Blocks);
if c > 0 {
try!(batch.put_cf(self.cfs[c - 1], &key, &compressed));
} else {
try!(batch.put(&key, &compressed));
}
}
c += 1;
}
self.db.write_opt(batch, &self.write_opts)
}
@@ -385,14 +375,19 @@ impl Database {
/// Get value by key.
pub fn get(&self, col: Option<u32>, key: &[u8]) -> Result<Option<Bytes>, String> {
let overlay = &self.overlay.read()[Self::to_overlay_column(col)];
overlay.insertions.get(key).or_else(|| overlay.compressed_insertions.get(key)).map_or_else(||
col.map_or_else(
|| self.db.get(key).map(|r| r.map(|v| v.to_vec())),
|c| self.db.get_cf(self.cfs[c as usize], key).map(|r| r.map(|v| v.to_vec()))),
|value| Ok(Some(value.clone())))
match overlay.get(key) {
Some(&KeyState::Insert(ref value)) | Some(&KeyState::InsertCompressed(ref value)) => Ok(Some(value.clone())),
Some(&KeyState::Delete) => Ok(None),
None => {
col.map_or_else(
|| self.db.get(key).map(|r| r.map(|v| v.to_vec())),
|c| self.db.get_cf(self.cfs[c as usize], key).map(|r| r.map(|v| v.to_vec())))
},
}
}
/// Get value by partial key. Prefix size should match configured prefix size.
/// Get value by partial key. Prefix size should match configured prefix size. Only searches flushed values.
// TODO: support prefix seek for unflushed ata
pub fn get_by_prefix(&self, col: Option<u32>, prefix: &[u8]) -> Option<Box<[u8]>> {
let mut iter = col.map_or_else(|| self.db.iterator(IteratorMode::From(prefix, Direction::Forward)),
|c| self.db.iterator_cf(self.cfs[c as usize], IteratorMode::From(prefix, Direction::Forward)).unwrap());
@@ -403,13 +398,9 @@ impl Database {
}
}
/// Check if there is anything in the database.
pub fn is_empty(&self, col: Option<u32>) -> bool {
self.iter(col).next().is_none()
}
/// Get database iterator.
/// Get database iterator for flushed data.
pub fn iter(&self, col: Option<u32>) -> DatabaseIterator {
//TODO: iterate over overlay
col.map_or_else(|| DatabaseIterator { iter: self.db.iterator(IteratorMode::Start) },
|c| DatabaseIterator { iter: self.db.iterator_cf(self.cfs[c as usize], IteratorMode::Start).unwrap() })
}
@@ -421,7 +412,6 @@ mod tests {
use super::*;
use devtools::*;
use std::str::FromStr;
use std::ops::Deref;
fn test_db(config: &DatabaseConfig) {
let path = RandomTempPath::create_dir();
@@ -435,13 +425,13 @@ mod tests {
batch.put(None, &key2, b"dog").unwrap();
db.write(batch).unwrap();
assert_eq!(db.get(None, &key1).unwrap().unwrap().deref(), b"cat");
assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"cat");
let contents: Vec<_> = db.iter(None).collect();
assert_eq!(contents.len(), 2);
assert_eq!(&*contents[0].0, key1.deref());
assert_eq!(&*contents[0].0, &*key1);
assert_eq!(&*contents[0].1, b"cat");
assert_eq!(&*contents[1].0, key2.deref());
assert_eq!(&*contents[1].0, &*key2);
assert_eq!(&*contents[1].1, b"dog");
let batch = db.transaction();
@@ -459,17 +449,27 @@ mod tests {
transaction.delete(None, &key1).unwrap();
db.write(transaction).unwrap();
assert!(db.get(None, &key1).unwrap().is_none());
assert_eq!(db.get(None, &key3).unwrap().unwrap().deref(), b"elephant");
assert_eq!(&*db.get(None, &key3).unwrap().unwrap(), b"elephant");
assert_eq!(db.get_by_prefix(None, &key3).unwrap().deref(), b"elephant");
assert_eq!(db.get_by_prefix(None, &key2).unwrap().deref(), b"dog");
assert_eq!(&*db.get_by_prefix(None, &key3).unwrap(), b"elephant");
assert_eq!(&*db.get_by_prefix(None, &key2).unwrap(), b"dog");
let transaction = db.transaction();
transaction.put(None, &key1, b"horse").unwrap();
transaction.delete(None, &key3).unwrap();
db.write_buffered(transaction).unwrap();
assert!(db.get(None, &key3).unwrap().is_none());
assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"horse");
db.flush().unwrap();
assert!(db.get(None, &key3).unwrap().is_none());
assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"horse");
}
#[test]
fn kvdb() {
let path = RandomTempPath::create_dir();
let smoke = Database::open_default(path.as_path().to_str().unwrap()).unwrap();
assert!(smoke.is_empty(None));
let _ = Database::open_default(path.as_path().to_str().unwrap()).unwrap();
test_db(&DatabaseConfig::default());
}
}

View File

@@ -49,7 +49,7 @@ pub fn version() -> String {
let date_dash = if commit_date.is_empty() { "" } else { "-" };
let env = Target::env();
let env_dash = if env.is_empty() { "" } else { "-" };
format!("Parity/v{}-unstable{}{}{}{}/{}-{}{}{}/rustc{}", env!("CARGO_PKG_VERSION"), sha3_dash, sha3, date_dash, commit_date, Target::arch(), Target::os(), env_dash, env, rustc_version())
format!("Parity/v{}-beta{}{}{}{}/{}-{}{}{}/rustc{}", env!("CARGO_PKG_VERSION"), sha3_dash, sha3, date_dash, commit_date, Target::arch(), Target::os(), env_dash, env, rustc_version())
}
/// Get the standard version data for this software.
@@ -64,4 +64,4 @@ pub fn version_data() -> Bytes {
s.append(&rustc_version());
s.append(&&Target::os()[0..2]);
s.out()
}
}

View File

@@ -22,7 +22,6 @@ use bytes::*;
use rlp::*;
use hashdb::*;
use memorydb::*;
use std::ops::*;
use std::sync::*;
use std::collections::HashMap;
use kvdb::{Database, DBTransaction};
@@ -130,7 +129,7 @@ impl HashDB for OverlayDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = HashMap::new();
for (key, _) in self.backing.iter(self.column) {
let h = H256::from_slice(key.deref());
let h = H256::from_slice(&*key);
let r = self.payload(&h).unwrap().1;
ret.insert(h, r as i32);
}
@@ -305,7 +304,7 @@ fn playpen() {
batch.put(None, b"test", b"test2").unwrap();
db.write(batch).unwrap();
match db.get(None, b"test") {
Ok(Some(value)) => println!("Got value {:?}", value.deref()),
Ok(Some(value)) => println!("Got value {:?}", &*value),
Ok(None) => println!("No value for that key"),
Err(..) => println!("Gah"),
}
@@ -314,4 +313,4 @@ fn playpen() {
db.write(batch).unwrap();
}
fs::remove_dir_all("/tmp/test").unwrap();
}
}

View File

@@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::ops::Deref;
use std::default::Default;
use elastic_array::*;
use rlp::bytes::{ToBytes, VecLike};
use rlp::{Stream, Encoder, Encodable};
@@ -293,7 +291,7 @@ impl<'a> Encodable for &'a[u8] {
impl Encodable for Vec<u8> {
fn rlp_append(&self, s: &mut RlpStream) {
s.append_value(&U8Slice(self.deref()))
s.append_value(&U8Slice(self))
}
}
@@ -334,7 +332,7 @@ impl<'a, T> Encodable for &'a[T] where T: Encodable {
impl<T> Encodable for Vec<T> where T: Encodable {
fn rlp_append(&self, s: &mut RlpStream) {
Encodable::rlp_append(&self.deref(), s);
Encodable::rlp_append(&self.as_slice(), s);
}
}

View File

@@ -15,7 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Common RLP traits
use std::ops::Deref;
use rlp::bytes::VecLike;
use rlp::{DecoderError, UntrustedRlp};
use rlp::rlpstream::RlpStream;
@@ -244,7 +243,7 @@ pub trait ByteEncodable {
fn bytes_len(&self) -> usize;
}
/// Structure encodable to RLP. Implement this trait for
/// Structure encodable to RLP. Implement this trait for
pub trait Encodable {
/// Append a value to the stream
fn rlp_append(&self, s: &mut RlpStream);
@@ -257,7 +256,7 @@ pub trait Encodable {
}
/// Get the hash or RLP encoded representation
fn rlp_sha3(&self) -> H256 { self.rlp_bytes().deref().sha3() }
fn rlp_sha3(&self) -> H256 { (&*self.rlp_bytes()).sha3() }
}
/// Encodable wrapper trait required to handle special case of encoding a &[u8] as string and not as list

View File

@@ -192,7 +192,7 @@ impl<'db> TrieDB<'db> {
where 'db: 'key
{
let root_rlp = try!(self.root_data());
self.get_from_node(&root_rlp, key)
self.get_from_node(root_rlp, key)
}
/// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no