Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54bae9a0f2 | ||
|
|
42dd3addea | ||
|
|
c74c8c1ac1 | ||
|
|
4e39c318aa | ||
|
|
03b1e9d8ba | ||
|
|
fdaedc8c00 | ||
|
|
d60fe51553 | ||
|
|
c7621b9bbf | ||
|
|
0ec35d9ac5 | ||
|
|
ef702b77dc | ||
|
|
a8cf4efc91 | ||
|
|
aeb43b6af0 | ||
|
|
dcdde49d91 | ||
|
|
b49c44a198 | ||
|
|
561e843207 | ||
|
|
6ad5d559ca | ||
|
|
91db3535f8 | ||
|
|
baa1223736 | ||
|
|
a2d5edb8f5 | ||
|
|
454b4518f2 | ||
|
|
303036cab0 | ||
|
|
b7e9152cc2 | ||
|
|
b1b5ffff95 | ||
|
|
067cbe78d2 | ||
|
|
1211c1f10c | ||
|
|
148ec3731c | ||
|
|
1b6588cb27 | ||
|
|
0e4a06d078 | ||
|
|
d470773fec | ||
|
|
8f0eb3e192 | ||
|
|
48c7e4ab8c | ||
|
|
8362bc7f2d | ||
|
|
284fc65c70 | ||
|
|
9882902f31 | ||
|
|
789c85561e | ||
|
|
18dff68278 | ||
|
|
d9a92c2bea | ||
|
|
2145388103 | ||
|
|
77d00e3dab | ||
|
|
aa6909ff99 | ||
|
|
0085d6a47b |
106
Cargo.lock
generated
106
Cargo.lock
generated
@@ -1,17 +1,3 @@
|
||||
[root]
|
||||
name = "wasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vm 0.1.0",
|
||||
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.0.2"
|
||||
@@ -374,7 +360,7 @@ dependencies = [
|
||||
"bloomable 0.1.0",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethjson 0.1.0",
|
||||
"hash 0.1.0",
|
||||
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -542,7 +528,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ethabi"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -588,7 +574,7 @@ dependencies = [
|
||||
"ethcore-ipc-nano 1.8.0",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-stratum 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethjson 0.1.0",
|
||||
"ethkey 0.2.0",
|
||||
"ethstore 0.1.0",
|
||||
@@ -682,7 +668,7 @@ version = "1.8.0"
|
||||
dependencies = [
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-devtools 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)",
|
||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -732,7 +718,7 @@ dependencies = [
|
||||
"ethcore-ipc 1.8.0",
|
||||
"ethcore-ipc-codegen 1.8.0",
|
||||
"ethcore-ipc-nano 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)",
|
||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -751,7 +737,7 @@ dependencies = [
|
||||
"ethcore-ipc 1.8.0",
|
||||
"ethcore-ipc-codegen 1.8.0",
|
||||
"ethcore-network 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"evm 0.1.0",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hash 0.1.0",
|
||||
@@ -801,7 +787,7 @@ dependencies = [
|
||||
"ethcore-devtools 1.8.0",
|
||||
"ethcore-io 1.8.0",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethcrypto 0.1.0",
|
||||
"ethkey 0.2.0",
|
||||
"hash 0.1.0",
|
||||
@@ -827,7 +813,7 @@ name = "ethcore-secretstore"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore 1.8.0",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
@@ -836,7 +822,7 @@ dependencies = [
|
||||
"ethcore-ipc-codegen 1.8.0",
|
||||
"ethcore-ipc-nano 1.8.0",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethcrypto 0.1.0",
|
||||
"ethkey 0.2.0",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -871,7 +857,7 @@ dependencies = [
|
||||
"ethcore-ipc-codegen 1.8.0",
|
||||
"ethcore-ipc-nano 1.8.0",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"hash 0.1.0",
|
||||
"jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.8)",
|
||||
"jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.8)",
|
||||
@@ -884,7 +870,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ethcore-util"
|
||||
version = "1.8.0"
|
||||
version = "1.8.5"
|
||||
dependencies = [
|
||||
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1018,7 +1004,7 @@ dependencies = [
|
||||
"ethcore-ipc-nano 1.8.0",
|
||||
"ethcore-light 1.8.0",
|
||||
"ethcore-network 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethkey 0.2.0",
|
||||
"hash 0.1.0",
|
||||
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1044,7 +1030,7 @@ dependencies = [
|
||||
"common-types 0.1.0",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethjson 0.1.0",
|
||||
"evmjit 1.8.0",
|
||||
"hash 0.1.0",
|
||||
@@ -1066,7 +1052,7 @@ dependencies = [
|
||||
"ethcore 1.8.0",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethjson 0.1.0",
|
||||
"evm 0.1.0",
|
||||
"panic_hook 0.1.0",
|
||||
@@ -1364,7 +1350,7 @@ dependencies = [
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-ipc 1.8.0",
|
||||
"ethcore-ipc-codegen 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1809,7 +1795,7 @@ dependencies = [
|
||||
name = "native-contract-generator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heck 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1818,7 +1804,7 @@ name = "native-contracts"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-contract-generator 0.1.0",
|
||||
@@ -1857,7 +1843,7 @@ dependencies = [
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-io 1.8.0",
|
||||
"ethcore-network 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kvdb 0.1.0",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2056,7 +2042,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity"
|
||||
version = "1.8.0"
|
||||
version = "1.8.5"
|
||||
dependencies = [
|
||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2080,7 +2066,7 @@ dependencies = [
|
||||
"ethcore-network 1.8.0",
|
||||
"ethcore-secretstore 1.0.0",
|
||||
"ethcore-stratum 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethkey 0.2.0",
|
||||
"ethsync 1.8.0",
|
||||
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2136,7 +2122,7 @@ dependencies = [
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-devtools 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"fetch 0.1.0",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2195,10 +2181,10 @@ dependencies = [
|
||||
name = "parity-hash-fetch"
|
||||
version = "1.8.0"
|
||||
dependencies = [
|
||||
"ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"fetch 0.1.0",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hash 0.1.0",
|
||||
@@ -2220,7 +2206,7 @@ dependencies = [
|
||||
"ethcore 1.8.0",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.8)",
|
||||
"jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.8)",
|
||||
"multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2234,7 +2220,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ethcore 1.8.0",
|
||||
"ethcore-io 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethkey 0.2.0",
|
||||
"kvdb 0.1.0",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2249,7 +2235,7 @@ name = "parity-machine"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2277,7 +2263,7 @@ dependencies = [
|
||||
"ethcore-light 1.8.0",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-network 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethcrypto 0.1.0",
|
||||
"ethjson 0.1.0",
|
||||
"ethkey 0.2.0",
|
||||
@@ -2358,7 +2344,7 @@ name = "parity-ui"
|
||||
version = "1.8.0"
|
||||
dependencies = [
|
||||
"parity-ui-dev 1.8.0",
|
||||
"parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git)",
|
||||
"parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git?branch=beta)",
|
||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -2372,7 +2358,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "parity-ui-precompiled"
|
||||
version = "1.4.0"
|
||||
source = "git+https://github.com/paritytech/js-precompiled.git#7f18ddb380a06977d1028501d5930023b5cc9a26"
|
||||
source = "git+https://github.com/paritytech/js-precompiled.git?branch=beta#26c6b48bfc83bb26445f6d72646773b6d5838fe4"
|
||||
dependencies = [
|
||||
"parity-dapps-glue 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2381,13 +2367,13 @@ dependencies = [
|
||||
name = "parity-updater"
|
||||
version = "1.8.0"
|
||||
dependencies = [
|
||||
"ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore 1.8.0",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-ipc 1.8.0",
|
||||
"ethcore-ipc-codegen 1.8.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethsync 1.8.0",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-common-types 1.8.0",
|
||||
@@ -2401,7 +2387,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-wasm"
|
||||
version = "0.14.5"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2849,7 +2835,7 @@ name = "rpc-cli"
|
||||
version = "1.4.0"
|
||||
dependencies = [
|
||||
"bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-rpc 1.8.0",
|
||||
"parity-rpc-client 1.4.0",
|
||||
@@ -3565,7 +3551,7 @@ dependencies = [
|
||||
"common-types 0.1.0",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethcore-util 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"ethjson 0.1.0",
|
||||
"evmjit 1.8.0",
|
||||
"hash 0.1.0",
|
||||
@@ -3580,10 +3566,24 @@ name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.1.3",
|
||||
"ethcore-logger 1.8.0",
|
||||
"ethcore-util 1.8.5",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vm 0.1.0",
|
||||
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/paritytech/wasm-utils#6a39db802eb6b67a0c4e5cf50741f965e217335a"
|
||||
source = "git+https://github.com/paritytech/wasm-utils#3d59f7ca0661317bc66894a26b2a5a319fa5d229"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3591,7 +3591,7 @@ dependencies = [
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3721,7 +3721,7 @@ dependencies = [
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5c82c815138e278b8dcdeffc49f27ea6ffb528403e9dea4194f2e3dd40b143"
|
||||
"checksum eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)" = "<none>"
|
||||
"checksum ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3d62319ee0f35abf20afe8859dd2668195912614346447bb2dee9fb8da7c62"
|
||||
"checksum ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6af84a622f9169efc6ead7f70043ca2058ef261c50e5e1e2ac60ccd381e386"
|
||||
"checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa"
|
||||
"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423"
|
||||
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
|
||||
@@ -3814,8 +3814,8 @@ dependencies = [
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum parity-dapps-glue 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddaeb8543c6823e93dae65a25eb8083ebfeee8f0000031119d7a0055b2e8fc63"
|
||||
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
|
||||
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git)" = "<none>"
|
||||
"checksum parity-wasm 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4502e18417d96bd8e72fca9ea4cc18f4d80288ff565582d10aefe86f18b4fc3"
|
||||
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git?branch=beta)" = "<none>"
|
||||
"checksum parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8431a184ad88cfbcd71a792aaca319cc7203a94300c26b8dce2d0df0681ea87d"
|
||||
"checksum parity-wordlist 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81451bfab101d186f8fc4a0aa13cb5539b31b02c4ed96425a0842e2a413daba6"
|
||||
"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
|
||||
"checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
description = "Parity Ethereum client"
|
||||
name = "parity"
|
||||
version = "1.8.0"
|
||||
version = "1.8.5"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
@@ -193,7 +193,7 @@ const UPDATE_TIMEOUT_ERR_SECS: u64 = 60;
|
||||
const UPDATE_TIMEOUT_INCOMPLETE_SECS: u64 = 10;
|
||||
|
||||
/// Maximal valid time drift.
|
||||
pub const MAX_DRIFT: i64 = 500;
|
||||
pub const MAX_DRIFT: i64 = 10_000;
|
||||
|
||||
type BoxFuture<A, B> = Box<Future<Item = A, Error = B> + Send>;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ rustc_version = "0.1"
|
||||
[dependencies]
|
||||
parity-ui-dev = { path = "../../js", optional = true }
|
||||
# This is managed by the js/scripts/release.sh script on CI - keep it in a single line
|
||||
parity-ui-precompiled = { git = "https://github.com/paritytech/js-precompiled.git", optional = true, branch = "master" }
|
||||
parity-ui-precompiled = { git = "https://github.com/paritytech/js-precompiled.git", optional = true, branch = "beta" }
|
||||
|
||||
[features]
|
||||
no-precompiled-js = ["parity-ui-dev"]
|
||||
|
||||
@@ -322,20 +322,24 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let init_off = stack.pop_back();
|
||||
let init_size = stack.pop_back();
|
||||
|
||||
let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };
|
||||
let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed");
|
||||
|
||||
let contract_code = self.mem.read_slice(init_off, init_size);
|
||||
let can_create = ext.balance(¶ms.address)? >= endowment && ext.depth() < ext.schedule().max_depth;
|
||||
if ext.is_static() {
|
||||
return Err(vm::Error::MutableCallInStaticContext);
|
||||
}
|
||||
|
||||
// clear return data buffer before creating new call frame.
|
||||
self.return_data = ReturnData::empty();
|
||||
|
||||
let can_create = ext.balance(¶ms.address)? >= endowment && ext.depth() < ext.schedule().max_depth;
|
||||
if !can_create {
|
||||
stack.push(U256::zero());
|
||||
return Ok(InstructionResult::UnusedGas(create_gas));
|
||||
}
|
||||
|
||||
let contract_code = self.mem.read_slice(init_off, init_size);
|
||||
let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };
|
||||
|
||||
let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme);
|
||||
return match create_result {
|
||||
ContractCreateResult::Created(address, gas_left) => {
|
||||
@@ -351,9 +355,6 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
stack.push(U256::zero());
|
||||
Ok(InstructionResult::Ok)
|
||||
},
|
||||
ContractCreateResult::FailedInStaticCall => {
|
||||
Err(vm::Error::MutableCallInStaticContext)
|
||||
},
|
||||
};
|
||||
},
|
||||
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {
|
||||
|
||||
@@ -724,7 +724,6 @@ fn test_jumps(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(54_117));
|
||||
}
|
||||
|
||||
|
||||
evm_test!{test_calls: test_calls_jit, test_calls_int}
|
||||
fn test_calls(factory: super::Factory) {
|
||||
let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap();
|
||||
@@ -769,6 +768,27 @@ fn test_calls(factory: super::Factory) {
|
||||
assert_eq!(ext.calls.len(), 2);
|
||||
}
|
||||
|
||||
evm_test!{test_create_in_staticcall: test_create_in_staticcall_jit, test_create_in_staticcall_int}
|
||||
fn test_create_in_staticcall(factory: super::Factory) {
|
||||
let code = "600060006064f000".from_hex().unwrap();
|
||||
|
||||
let address = Address::from(0x155);
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.address = address.clone();
|
||||
let mut ext = FakeExt::new_byzantium();
|
||||
ext.is_static = true;
|
||||
|
||||
let err = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap_err()
|
||||
};
|
||||
|
||||
assert_eq!(err, vm::Error::MutableCallInStaticContext);
|
||||
assert_eq!(ext.calls.len(), 0);
|
||||
}
|
||||
|
||||
fn assert_set_contains<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, val: &T) {
|
||||
let contains = set.contains(val);
|
||||
if !contains {
|
||||
|
||||
@@ -173,24 +173,36 @@
|
||||
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://efe4f2493f4aff2d641b1db8366b96ddacfe13e7a6e9c8f8f8cf49f9cdba0fdf3258d8c8f8d0c5db529f8123c8f1d95f36d54d590ca1bb366a5818b9a4ba521c@163.172.187.252:30303",
|
||||
"enode://6a868ced2dec399c53f730261173638a93a40214cf299ccf4d42a76e3fa54701db410669e8006347a4b3a74fa090bb35af0320e4bc8d04cf5b7f582b1db285f5@163.172.131.191:30303",
|
||||
"enode://66a483383882a518fcc59db6c017f9cd13c71261f13c8d7e67ed43adbbc82a932d88d2291f59be577e9425181fc08828dc916fdd053af935a9491edf9d6006ba@212.47.247.103:30303",
|
||||
"enode://cd6611461840543d5b9c56fbf088736154c699c43973b3a1a32390cf27106f87e58a818a606ccb05f3866de95a4fe860786fea71bf891ea95f234480d3022aa3@163.172.157.114:30303",
|
||||
"enode://5a62f19d35c0da8b576c9414568c728d4744e6e9d436c0f9db27456400011414f515871f13a6b8e0468534b5116cfe765d7630f680f1707a38467940a9f62511@45.55.33.62:30303",
|
||||
"enode://605e04a43b1156966b3a3b66b980c87b7f18522f7f712035f84576016be909a2798a438b2b17b1a8c58db314d88539a77419ca4be36148c086900fba487c9d39@188.166.255.12:30303",
|
||||
"enode://dc72806c3aa8fda207c8c018aba8d6cf143728b3628b6ded8d5e8cdeb8aa05cbd53f710ecd014c9a8f0d1e98f2874bff8afb15a229202f510a9c0258d1f6d109@159.203.210.80:30303",
|
||||
"enode://aafde2e81e035f417019a80f5342d1cd0e5bce97f83230fc57e1abbb3a9a5d6fb751446040c67261ed422324ffb69214567e181bb4ac0cc6e817451be0eaad1e@52.178.74.216:30303",
|
||||
"enode://460e54d7e9a361d326a9e503b3879c6a1075e1bfb7ea919b512ea1fe841e65f82c5f87af028f14a7825be1c1260825d5326b93b43a5bc72e3214a99e0c4c7bd4@52.230.6.166:30303",
|
||||
"enode://28faaf6b2e86694d8978b8e6986e7813951d7bd25201116fa77de893aabedd2a4a8d5832776905b4c3e616320506516d08239d82aeef4355f6878c3a701a6059@40.71.19.172:30303",
|
||||
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
||||
"enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303",
|
||||
"enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303",
|
||||
"enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303",
|
||||
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
||||
"enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303",
|
||||
"enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30305",
|
||||
"enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308",
|
||||
"enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309",
|
||||
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
||||
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
||||
"enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303",
|
||||
"enode://01f76fa0561eca2b9a7e224378dd854278735f1449793c46ad0c4e79e8775d080c21dcc455be391e90a98153c3b05dcc8935c8440de7b56fe6d67251e33f4e3c@51.15.42.252:30303",
|
||||
"enode://2c9059f05c352b29d559192fe6bca272d965c9f2290632a2cfda7f83da7d2634f3ec45ae3a72c54dd4204926fb8082dcf9686e0d7504257541c86fc8569bcf4b@163.172.171.38:30303",
|
||||
"enode://efe4f2493f4aff2d641b1db8366b96ddacfe13e7a6e9c8f8f8cf49f9cdba0fdf3258d8c8f8d0c5db529f8123c8f1d95f36d54d590ca1bb366a5818b9a4ba521c@163.172.187.252:30303",
|
||||
"enode://bcc7240543fe2cf86f5e9093d05753dd83343f8fda7bf0e833f65985c73afccf8f981301e13ef49c4804491eab043647374df1c4adf85766af88a624ecc3330e@136.243.154.244:30303",
|
||||
"enode://ed4227681ca8c70beb2277b9e870353a9693f12e7c548c35df6bca6a956934d6f659999c2decb31f75ce217822eefca149ace914f1cbe461ed5a2ebaf9501455@88.212.206.70:30303",
|
||||
"enode://cadc6e573b6bc2a9128f2f635ac0db3353e360b56deef239e9be7e7fce039502e0ec670b595f6288c0d2116812516ad6b6ff8d5728ff45eba176989e40dead1e@37.128.191.230:30303",
|
||||
"enode://595a9a06f8b9bc9835c8723b6a82105aea5d55c66b029b6d44f229d6d135ac3ecdd3e9309360a961ea39d7bee7bac5d03564077a4e08823acc723370aace65ec@46.20.235.22:30303",
|
||||
"enode://029178d6d6f9f8026fc0bc17d5d1401aac76ec9d86633bba2320b5eed7b312980c0a210b74b20c4f9a8b0b2bf884b111fa9ea5c5f916bb9bbc0e0c8640a0f56c@216.158.85.185:30303",
|
||||
"enode://fdd1b9bb613cfbc200bba17ce199a9490edc752a833f88d4134bf52bb0d858aa5524cb3ec9366c7a4ef4637754b8b15b5dc913e4ed9fdb6022f7512d7b63f181@212.47.247.103:30303",
|
||||
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
||||
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
||||
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
||||
"enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303",
|
||||
|
||||
"enode://89d5dc2a81e574c19d0465f497c1af96732d1b61a41de89c2a37f35707689ac416529fae1038809852b235c2d30fd325abdc57c122feeefbeaaf802cc7e9580d@45.55.33.62:30303",
|
||||
"enode://605e04a43b1156966b3a3b66b980c87b7f18522f7f712035f84576016be909a2798a438b2b17b1a8c58db314d88539a77419ca4be36148c086900fba487c9d39@188.166.255.12:30303",
|
||||
"enode://016b20125f447a3b203a3cae953b2ede8ffe51290c071e7599294be84317635730c397b8ff74404d6be412d539ee5bb5c3c700618723d3b53958c92bd33eaa82@159.203.210.80:30303",
|
||||
"enode://01f76fa0561eca2b9a7e224378dd854278735f1449793c46ad0c4e79e8775d080c21dcc455be391e90a98153c3b05dcc8935c8440de7b56fe6d67251e33f4e3c@51.15.42.252:30303",
|
||||
"enode://8d91c8137890d29110b9463882f17ae4e279cd2c90cf56573187ed1c8546fca5f590a9f05e9f108eb1bd91767ed01ede4daad9e001b61727885eaa246ddb39c2@163.172.171.38:30303"
|
||||
"enode://fdd1b9bb613cfbc200bba17ce199a9490edc752a833f88d4134bf52bb0d858aa5524cb3ec9366c7a4ef4637754b8b15b5dc913e4ed9fdb6022f7512d7b63f181@212.47.247.103:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
|
||||
@@ -12,29 +12,35 @@
|
||||
"0x00427feae2419c15b89d1c21af10d1b6650a4d3d",
|
||||
"0x4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c",
|
||||
"0x0020ee4Be0e2027d76603cB751eE069519bA81A1",
|
||||
|
||||
"0x0010f94b296a852aaac52ea6c5ac72e03afd032d",
|
||||
|
||||
"0x007733a1FE69CF3f2CF989F81C7b4cAc1693387A",
|
||||
"0x00E6d2b931F55a3f1701c7389d592a7778897879",
|
||||
"0x00e4a10650e5a6D6001C38ff8E64F97016a1645c",
|
||||
|
||||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||
]
|
||||
},
|
||||
"validateScoreTransition": 1000000,
|
||||
"validateStepTransition": 1500000
|
||||
"validateStepTransition": 1500000,
|
||||
"maximumUncleCountTransition": 5067000,
|
||||
"maximumUncleCount": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x2A",
|
||||
"forkBlock": 4297256,
|
||||
"forkCanonHash": "0x0a66d93c2f727dca618fabaf70c39b37018c73d78b939d8b11efbbd09034778f",
|
||||
"validateReceiptsTransition" : 1000000,
|
||||
"eip155Transition": 1000000
|
||||
"eip155Transition": 1000000,
|
||||
"validateChainIdTransition": 1000000,
|
||||
"eip140Transition": 5067000,
|
||||
"eip211Transition": 5067000,
|
||||
"eip214Transition": 5067000,
|
||||
"eip658Transition": 5067000
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@@ -51,13 +57,17 @@
|
||||
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0x0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 5067000, "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0x0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 5067000, "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0x0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 5067000, "pricing": { "linear": { "base": 40000, "word": 0 } } } },
|
||||
"0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 5067000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
|
||||
"0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
||||
},
|
||||
"nodes": [
|
||||
"enode://0518a3d35d4a7b3e8c433e7ffd2355d84a1304ceb5ef349787b556197f0c87fad09daed760635b97d52179d645d3e6d16a37d2cc0a9945c2ddf585684beb39ac@40.68.248.100:30303",
|
||||
"enode://dcf984764db421fa0cd8dc7fc02ae378545723abb94d179f55325514cc30185eaea3dcefde6e358b7cdbe970c50b7c49e841618713a9a72d6f3f59ad9949ec6b@52.165.239.18:30303",
|
||||
"enode://56abaf065581a5985b8c5f4f88bd202526482761ba10be9bfdcd14846dd01f652ec33fde0f8c0fd1db19b59a4c04465681fcef50e11380ca88d25996191c52de@40.71.221.215:30303",
|
||||
"enode://d07827483dc47b368eaf88454fb04b41b7452cf454e194e2bd4c14f98a3278fed5d819dbecd0d010407fc7688d941ee1e58d4f9c6354d3da3be92f55c17d7ce3@52.166.117.77:30303",
|
||||
"enode://8fa162563a8e5a05eef3e1cd5abc5828c71344f7277bb788a395cce4a0e30baf2b34b92fe0b2dbbba2313ee40236bae2aab3c9811941b9f5a7e8e90aaa27ecba@52.165.239.18:30303",
|
||||
"enode://7e2e7f00784f516939f94e22bdc6cf96153603ca2b5df1c7cc0f90a38e7a2f218ffb1c05b156835e8b49086d11fdd1b3e2965be16baa55204167aa9bf536a4d9@52.243.47.56:30303",
|
||||
"enode://d51b3e98bf35addf2f1d0ea1ffc90483e24d7c60b0fb3be1701e818f3d6778c06e53fdec737a534fe222956296f9d6e909baa025916a94601897e5c7136a7d95@40.71.221.215:30303",
|
||||
"enode://419d42e300e8fd379ff6d045d93d7e66a091441e7b3c9f1d3d10088d8634ad37721e6bf86148f78c3f1b9f1360dc566ca8ee830b2d2079bc9f7171ea6152bb64@52.166.117.77:30303"
|
||||
"enode://0518a3d35d4a7b3e8c433e7ffd2355d84a1304ceb5ef349787b556197f0c87fad09daed760635b97d52179d645d3e6d16a37d2cc0a9945c2ddf585684beb39ac@40.68.248.100:30303"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"eip160Transition": 1915000,
|
||||
"ecip1010PauseTransition": 1915000,
|
||||
"ecip1010ContinueTransition": 3415000,
|
||||
"ecip1017EraRounds": 2000000,
|
||||
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
@@ -49,11 +50,13 @@
|
||||
"gasLimit": "0x2fefd8"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303",
|
||||
"enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303",
|
||||
"enode://fb28713820e718066a2f5df6250ae9d07cff22f672dbf26be6c75d088f821a9ad230138ba492c533a80407d054b1436ef18e951bb65e6901553516c8dffe8ff0@104.155.176.151:30304",
|
||||
"enode://afdc6076b9bf3e7d3d01442d6841071e84c76c73a7016cb4f35c0437df219db38565766234448f1592a07ba5295a867f0ce87b359bf50311ed0b830a2361392d@104.154.136.117:30403",
|
||||
"enode://21101a9597b79e933e17bc94ef3506fe99a137808907aa8fefa67eea4b789792ad11fb391f38b00087f8800a2d3dff011572b62a31232133dd1591ac2d1502c8@104.198.71.200:30403"
|
||||
"enode://21101a9597b79e933e17bc94ef3506fe99a137808907aa8fefa67eea4b789792ad11fb391f38b00087f8800a2d3dff011572b62a31232133dd1591ac2d1502c8@104.198.71.200:30403",
|
||||
"enode://fd008499e9c4662f384b3cff23438879d31ced24e2d19504c6389bc6da6c882f9c2f8dbed972f7058d7650337f54e4ba17bb49c7d11882dd1731d26a6e62e3cb@35.187.57.94:30304",
|
||||
"enode://30a1fd71f28aa6f66fe662af9ecc75f0a6980f06b71598f2b19d3dda04223fc0e53b47e40c9171d5014e9f5b59d9954de125782da592f5d95ea39066e2591d5d@104.237.131.102:30304",
|
||||
"enode://7909d51011d8a153351169f21d3a7bbedb3be1e17d38c1f2fad06504dd5aa07a00f00845835d535fe702bf379c4d7209a51f4d1b723e0ca8b8732bd21fba3b30@139.162.133.42:30303",
|
||||
"enode://a088dfb2f5305be9232e8071c5535f13718a4017e247a0b35074b807d43d99e022880c27302cdb5b1e98ad34c083dbbb483f2b17bdc66149bad037154d6ace96@139.162.127.72:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
|
||||
Submodule ethcore/res/wasm-tests updated: c8129ce2f3...d6185ea16e
@@ -269,7 +269,7 @@ impl AccountProvider {
|
||||
|
||||
/// Checks whether an account with a given address is present.
|
||||
pub fn has_account(&self, address: Address) -> Result<bool, Error> {
|
||||
Ok(self.accounts()?.iter().any(|&a| a == address))
|
||||
Ok(self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address))
|
||||
}
|
||||
|
||||
/// Returns addresses of all accounts.
|
||||
|
||||
@@ -380,8 +380,13 @@ impl<'x> OpenBlock<'x> {
|
||||
/// NOTE Will check chain constraints and the uncle number but will NOT check
|
||||
/// that the header itself is actually valid.
|
||||
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
|
||||
if self.block.uncles.len() + 1 > self.engine.maximum_uncle_count() {
|
||||
return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.uncles.len() + 1}));
|
||||
let max_uncles = self.engine.maximum_uncle_count(self.block.header().number());
|
||||
if self.block.uncles.len() + 1 > max_uncles {
|
||||
return Err(BlockError::TooManyUncles(OutOfBounds{
|
||||
min: None,
|
||||
max: Some(max_uncles),
|
||||
found: self.block.uncles.len() + 1,
|
||||
}));
|
||||
}
|
||||
// TODO: check number
|
||||
// TODO: check not a direct ancestor (use last_hashes for that)
|
||||
|
||||
@@ -123,7 +123,11 @@ impl Pricer for ModexpPricer {
|
||||
|
||||
let adjusted_exp_len = Self::adjusted_exp_len(exp_len, exp_low);
|
||||
|
||||
(Self::mult_complexity(m) * max(adjusted_exp_len, 1) / self.divisor as u64).into()
|
||||
let (gas, overflow) = Self::mult_complexity(m).overflowing_mul(max(adjusted_exp_len, 1));
|
||||
if overflow {
|
||||
return U256::max_value();
|
||||
}
|
||||
(gas / self.divisor as u64).into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,6 +710,14 @@ mod tests {
|
||||
activate_at: 0,
|
||||
};
|
||||
|
||||
// test for potential gas cost multiplication overflow
|
||||
{
|
||||
let input = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b27bafd00000000000000000000000000000000000000000000000000000000503c8ac3").unwrap();
|
||||
let expected_cost = U256::max_value();
|
||||
assert_eq!(f.cost(&input[..]), expected_cost.into());
|
||||
}
|
||||
|
||||
|
||||
// test for potential exp len overflow
|
||||
{
|
||||
let input = FromHex::from_hex("\
|
||||
|
||||
@@ -1230,18 +1230,18 @@ impl BlockChainClient for Client {
|
||||
}
|
||||
|
||||
fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError> {
|
||||
const UPPER_CEILING: u64 = 1_000_000_000_000u64;
|
||||
let (mut upper, env_info) = {
|
||||
let (mut upper, max_upper, env_info) = {
|
||||
let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?;
|
||||
let initial_upper = env_info.gas_limit;
|
||||
env_info.gas_limit = UPPER_CEILING.into();
|
||||
(initial_upper, env_info)
|
||||
let init = env_info.gas_limit;
|
||||
let max = init * U256::from(10);
|
||||
env_info.gas_limit = max;
|
||||
(init, max, env_info)
|
||||
};
|
||||
|
||||
// that's just a copy of the state.
|
||||
let original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
||||
let sender = t.sender();
|
||||
let options = || TransactOptions::with_tracing();
|
||||
let options = || TransactOptions::with_tracing().dont_check_nonce();
|
||||
|
||||
let cond = |gas| {
|
||||
let mut tx = t.as_unsigned().clone();
|
||||
@@ -1256,9 +1256,7 @@ impl BlockChainClient for Client {
|
||||
};
|
||||
|
||||
if !cond(upper)? {
|
||||
// impossible at block gas limit - try `UPPER_CEILING` instead.
|
||||
// TODO: consider raising limit by powers of two.
|
||||
upper = UPPER_CEILING.into();
|
||||
upper = max_upper;
|
||||
if !cond(upper)? {
|
||||
trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
|
||||
let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", upper));
|
||||
@@ -1871,7 +1869,7 @@ impl MiningBlockChainClient for Client {
|
||||
.find_uncle_headers(&h, engine.maximum_uncle_age())
|
||||
.unwrap_or_else(Vec::new)
|
||||
.into_iter()
|
||||
.take(engine.maximum_uncle_count())
|
||||
.take(engine.maximum_uncle_count(open_block.header().number()))
|
||||
.foreach(|h| {
|
||||
open_block.push_uncle(h).expect("pushing maximum_uncle_count;
|
||||
open_block was just created;
|
||||
@@ -1886,7 +1884,7 @@ impl MiningBlockChainClient for Client {
|
||||
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
||||
let engine = &*self.engine;
|
||||
let mut block = block.reopen(engine);
|
||||
let max_uncles = engine.maximum_uncle_count();
|
||||
let max_uncles = engine.maximum_uncle_count(block.header().number());
|
||||
if block.uncles().len() < max_uncles {
|
||||
let chain = self.chain.read();
|
||||
let h = chain.best_block_hash();
|
||||
|
||||
@@ -65,6 +65,10 @@ pub struct AuthorityRoundParams {
|
||||
pub immediate_transitions: bool,
|
||||
/// Block reward in base units.
|
||||
pub block_reward: U256,
|
||||
/// Number of accepted uncles transition block.
|
||||
pub maximum_uncle_count_transition: u64,
|
||||
/// Number of accepted uncles.
|
||||
pub maximum_uncle_count: usize,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||
@@ -77,6 +81,8 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||
validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
|
||||
immediate_transitions: p.immediate_transitions.unwrap_or(false),
|
||||
block_reward: p.block_reward.map_or_else(Default::default, Into::into),
|
||||
maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into),
|
||||
maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +126,11 @@ impl Step {
|
||||
}
|
||||
}
|
||||
|
||||
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
|
||||
fn calculate_score(parent_step: U256, current_step: U256) -> U256 {
|
||||
U256::from(U128::max_value()) + parent_step - current_step
|
||||
}
|
||||
|
||||
struct EpochManager {
|
||||
epoch_transition_hash: H256,
|
||||
epoch_transition_number: BlockNumber,
|
||||
@@ -218,6 +229,8 @@ pub struct AuthorityRound {
|
||||
epoch_manager: Mutex<EpochManager>,
|
||||
immediate_transitions: bool,
|
||||
block_reward: U256,
|
||||
maximum_uncle_count_transition: u64,
|
||||
maximum_uncle_count: usize,
|
||||
machine: EthereumMachine,
|
||||
}
|
||||
|
||||
@@ -365,6 +378,8 @@ impl AuthorityRound {
|
||||
epoch_manager: Mutex::new(EpochManager::blank()),
|
||||
immediate_transitions: our_params.immediate_transitions,
|
||||
block_reward: our_params.block_reward,
|
||||
maximum_uncle_count_transition: our_params.maximum_uncle_count_transition,
|
||||
maximum_uncle_count: our_params.maximum_uncle_count,
|
||||
machine: machine,
|
||||
});
|
||||
|
||||
@@ -436,13 +451,23 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
]
|
||||
}
|
||||
|
||||
fn maximum_uncle_count(&self, block: BlockNumber) -> usize {
|
||||
if block >= self.maximum_uncle_count_transition {
|
||||
self.maximum_uncle_count
|
||||
} else {
|
||||
// fallback to default value
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
||||
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
|
||||
let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load().into();
|
||||
header.set_difficulty(new_difficulty);
|
||||
let parent_step = header_step(parent).expect("Header has been verified; qed");
|
||||
let score = calculate_score(parent_step.into(), self.step.load().into());
|
||||
header.set_difficulty(score);
|
||||
}
|
||||
|
||||
fn seals_internally(&self) -> Option<bool> {
|
||||
// TODO: accept a `&Call` here so we can query the validator set.
|
||||
Some(self.signer.read().is_some())
|
||||
}
|
||||
|
||||
@@ -450,14 +475,23 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
///
|
||||
/// This operation is synchronous and may (quite reasonably) not be available, in which case
|
||||
/// `Seal::None` will be returned.
|
||||
fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
|
||||
fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal {
|
||||
// first check to avoid generating signature most of the time
|
||||
// (but there's still a race to the `compare_and_swap`)
|
||||
if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; }
|
||||
|
||||
let header = block.header();
|
||||
let parent_step: U256 = header_step(parent)
|
||||
.expect("Header has been verified; qed").into();
|
||||
|
||||
let step = self.step.load();
|
||||
|
||||
let expected_diff = calculate_score(parent_step, step.into());
|
||||
|
||||
if header.difficulty() != &expected_diff {
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
// fetch correct validator set for current epoch, taking into account
|
||||
// finality of previous transitions.
|
||||
let active_set;
|
||||
@@ -484,6 +518,13 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
};
|
||||
|
||||
if is_step_proposer(validators, header.parent_hash(), step, header.author()) {
|
||||
// this is guarded against by `can_propose` unless the block was signed
|
||||
// on the same step (implies same key) and on a different node.
|
||||
if parent_step == step.into() {
|
||||
warn!("Attempted to seal block on the same step as parent. Is this authority sealing with more than one node?");
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
if let Ok(signature) = self.sign(header.bare_hash()) {
|
||||
trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step);
|
||||
|
||||
@@ -498,6 +539,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
trace!(target: "engine", "generate_seal: {} not a proposer for step {}.",
|
||||
header.author(), step);
|
||||
}
|
||||
|
||||
Seal::None
|
||||
}
|
||||
|
||||
@@ -539,7 +581,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
}
|
||||
|
||||
/// Check the number of seal fields.
|
||||
fn verify_block_basic(&self, header: &Header,) -> Result<(), Error> {
|
||||
fn verify_block_basic(&self, header: &Header) -> Result<(), Error> {
|
||||
if header.number() >= self.validate_score_transition && *header.difficulty() >= U256::from(U128::max_value()) {
|
||||
Err(From::from(BlockError::DifficultyOutOfBounds(
|
||||
OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() }
|
||||
@@ -850,17 +892,51 @@ mod tests {
|
||||
let b2 = b2.close_and_lock();
|
||||
|
||||
engine.set_signer(tap.clone(), addr1, "1".into());
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b1.block()) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b1.block(), &genesis_header) {
|
||||
assert!(b1.clone().try_seal(engine, seal).is_ok());
|
||||
// Second proposal is forbidden.
|
||||
assert!(engine.generate_seal(b1.block()) == Seal::None);
|
||||
assert!(engine.generate_seal(b1.block(), &genesis_header) == Seal::None);
|
||||
}
|
||||
|
||||
engine.set_signer(tap, addr2, "2".into());
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b2.block()) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b2.block(), &genesis_header) {
|
||||
assert!(b2.clone().try_seal(engine, seal).is_ok());
|
||||
// Second proposal is forbidden.
|
||||
assert!(engine.generate_seal(b2.block()) == Seal::None);
|
||||
assert!(engine.generate_seal(b2.block(), &genesis_header) == Seal::None);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checks_difficulty_in_generate_seal() {
|
||||
let tap = Arc::new(AccountProvider::transient_provider());
|
||||
let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap();
|
||||
let addr2 = tap.insert_account(keccak("0").into(), "0").unwrap();
|
||||
|
||||
let spec = Spec::new_test_round();
|
||||
let engine = &*spec.engine;
|
||||
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
||||
let b1 = b1.close_and_lock();
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
||||
let b2 = b2.close_and_lock();
|
||||
|
||||
engine.set_signer(tap.clone(), addr1, "1".into());
|
||||
match engine.generate_seal(b1.block(), &genesis_header) {
|
||||
Seal::None | Seal::Proposal(_) => panic!("wrong seal"),
|
||||
Seal::Regular(_) => {
|
||||
engine.step();
|
||||
|
||||
engine.set_signer(tap.clone(), addr2, "0".into());
|
||||
match engine.generate_seal(b2.block(), &genesis_header) {
|
||||
Seal::Regular(_) | Seal::Proposal(_) => panic!("sealed despite wrong difficulty"),
|
||||
Seal::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -949,6 +1025,8 @@ mod tests {
|
||||
validate_score_transition: 0,
|
||||
validate_step_transition: 0,
|
||||
immediate_transitions: true,
|
||||
maximum_uncle_count_transition: 0,
|
||||
maximum_uncle_count: 0,
|
||||
block_reward: Default::default(),
|
||||
};
|
||||
|
||||
@@ -976,4 +1054,31 @@ mod tests {
|
||||
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uncles_transition() {
|
||||
let last_benign = Arc::new(AtomicUsize::new(0));
|
||||
let params = AuthorityRoundParams {
|
||||
step_duration: Default::default(),
|
||||
start_step: Some(1),
|
||||
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
|
||||
validate_score_transition: 0,
|
||||
validate_step_transition: 0,
|
||||
immediate_transitions: true,
|
||||
maximum_uncle_count_transition: 1,
|
||||
maximum_uncle_count: 0,
|
||||
block_reward: Default::default(),
|
||||
};
|
||||
|
||||
let aura = {
|
||||
let mut c_params = ::spec::CommonParams::default();
|
||||
c_params.gas_limit_bound_divisor = 5.into();
|
||||
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
|
||||
AuthorityRound::new(params, machine).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(aura.maximum_uncle_count(0), 2);
|
||||
assert_eq!(aura.maximum_uncle_count(1), 0);
|
||||
assert_eq!(aura.maximum_uncle_count(100), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ impl Engine<EthereumMachine> for BasicAuthority {
|
||||
}
|
||||
|
||||
/// Attempt to seal the block internally.
|
||||
fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
|
||||
fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal {
|
||||
let header = block.header();
|
||||
let author = header.author();
|
||||
if self.validators.contains(header.parent_hash(), author) {
|
||||
@@ -251,7 +251,7 @@ mod tests {
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
||||
let b = b.close_and_lock();
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b.block()) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) {
|
||||
assert!(b.try_seal(engine, seal).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ impl<M: Machine> Engine<M> for InstantSeal<M>
|
||||
|
||||
fn seals_internally(&self) -> Option<bool> { Some(true) }
|
||||
|
||||
fn generate_seal(&self, block: &M::LiveBlock) -> Seal {
|
||||
fn generate_seal(&self, block: &M::LiveBlock, _parent: &M::Header) -> Seal {
|
||||
if block.transactions().is_empty() { Seal::None } else { Seal::Regular(Vec::new()) }
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ mod tests {
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
||||
let b = b.close_and_lock();
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b.block()) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) {
|
||||
assert!(b.try_seal(engine, seal).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,8 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
||||
|
||||
/// Maximum number of uncles a block is allowed to declare.
|
||||
fn maximum_uncle_count(&self) -> usize { 2 }
|
||||
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 }
|
||||
|
||||
/// The number of generations back that uncles can be.
|
||||
fn maximum_uncle_age(&self) -> usize { 6 }
|
||||
|
||||
@@ -225,7 +226,7 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
///
|
||||
/// It is fine to require access to state or a full client for this function, since
|
||||
/// light clients do not generate seals.
|
||||
fn generate_seal(&self, _block: &M::LiveBlock) -> Seal { Seal::None }
|
||||
fn generate_seal(&self, _block: &M::LiveBlock, _parent: &M::Header) -> Seal { Seal::None }
|
||||
|
||||
/// Verify a locally-generated seal of a header.
|
||||
///
|
||||
@@ -363,7 +364,7 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
||||
}
|
||||
|
||||
/// The nonce with which accounts begin at given block.
|
||||
fn account_start_nonce(&self, block: u64) -> U256 {
|
||||
fn account_start_nonce(&self, block: BlockNumber) -> U256 {
|
||||
self.machine().account_start_nonce(block)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
use bigint::prelude::U256;
|
||||
use engines::Engine;
|
||||
use header::BlockNumber;
|
||||
use parity_machine::{Header, LiveBlock, WithBalances};
|
||||
|
||||
/// Params for a null engine.
|
||||
@@ -95,6 +96,8 @@ impl<M: WithBalances> Engine<M> for NullEngine<M> {
|
||||
self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards)
|
||||
}
|
||||
|
||||
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 }
|
||||
|
||||
fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ impl Engine<EthereumMachine> for Tendermint {
|
||||
|
||||
fn machine(&self) -> &EthereumMachine { &self.machine }
|
||||
|
||||
fn maximum_uncle_count(&self) -> usize { 0 }
|
||||
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 }
|
||||
|
||||
fn maximum_uncle_age(&self) -> usize { 0 }
|
||||
|
||||
@@ -483,7 +483,7 @@ impl Engine<EthereumMachine> for Tendermint {
|
||||
///
|
||||
/// This operation is synchronous and may (quite reasonably) not be available, in which case
|
||||
/// `Seal::None` will be returned.
|
||||
fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
|
||||
fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal {
|
||||
let header = block.header();
|
||||
let author = header.author();
|
||||
// Only proposer can generate seal if None was generated.
|
||||
@@ -805,7 +805,7 @@ mod tests {
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
||||
let b = b.close();
|
||||
if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block()) {
|
||||
if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block(), &genesis_header) {
|
||||
(b, seal)
|
||||
} else {
|
||||
panic!()
|
||||
|
||||
@@ -26,7 +26,7 @@ use util::Address;
|
||||
use unexpected::{OutOfBounds, Mismatch};
|
||||
use block::*;
|
||||
use error::{BlockError, Error};
|
||||
use header::Header;
|
||||
use header::{Header, BlockNumber};
|
||||
use engines::{self, Engine};
|
||||
use ethjson;
|
||||
use rlp::{self, UntrustedRlp};
|
||||
@@ -181,6 +181,8 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
||||
}
|
||||
}
|
||||
|
||||
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 }
|
||||
|
||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
||||
let difficulty = self.calculate_difficulty(header, parent);
|
||||
header.set_difficulty(difficulty);
|
||||
@@ -447,9 +449,12 @@ fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u6
|
||||
} else {
|
||||
block_number / era_rounds
|
||||
};
|
||||
let mut divi = U256::from(1);
|
||||
for _ in 0..eras {
|
||||
reward = reward / U256::from(5) * U256::from(4);
|
||||
reward = reward * U256::from(4);
|
||||
divi = divi * U256::from(5);
|
||||
}
|
||||
reward = reward / divi;
|
||||
(eras, reward)
|
||||
}
|
||||
|
||||
@@ -515,6 +520,11 @@ mod tests {
|
||||
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number);
|
||||
assert_eq!(15, eras);
|
||||
assert_eq!(U256::from_str("271000000000000").unwrap(), reward);
|
||||
|
||||
let block_number = 250000000;
|
||||
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number);
|
||||
assert_eq!(49, eras);
|
||||
assert_eq!(U256::from_str("51212FFBAF0A").unwrap(), reward);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -31,7 +31,7 @@ use machine::EthereumMachine;
|
||||
use super::spec::*;
|
||||
|
||||
/// Most recent fork block that we support on Mainnet.
|
||||
pub const FORK_SUPPORTED_FOUNDATION: u64 = 2675000;
|
||||
pub const FORK_SUPPORTED_FOUNDATION: u64 = 4370000;
|
||||
|
||||
/// Most recent fork block that we support on Ropsten.
|
||||
pub const FORK_SUPPORTED_ROPSTEN: u64 = 10;
|
||||
|
||||
@@ -309,6 +309,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
code: Some(Arc::new(t.data.clone())),
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
params_type: vm::ParamsType::Embedded,
|
||||
};
|
||||
let mut out = if output_from_create { Some(vec![]) } else { None };
|
||||
(self.create(params, &mut substate, &mut out, &mut tracer, &mut vm_tracer), out.unwrap_or_else(Vec::new))
|
||||
@@ -326,6 +327,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
code_hash: Some(self.state.code_hash(address)?),
|
||||
data: Some(t.data.clone()),
|
||||
call_type: CallType::Call,
|
||||
params_type: vm::ParamsType::Separate,
|
||||
};
|
||||
let mut out = vec![];
|
||||
(self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer, &mut vm_tracer), out)
|
||||
|
||||
@@ -171,6 +171,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
code_hash: Some(code_hash),
|
||||
data: Some(H256::from(number).to_vec()),
|
||||
call_type: CallType::Call,
|
||||
params_type: vm::ParamsType::Separate,
|
||||
};
|
||||
|
||||
let mut output = H256::new();
|
||||
@@ -219,6 +220,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
code_hash: code_hash,
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
params_type: vm::ParamsType::Embedded,
|
||||
};
|
||||
|
||||
if !self.static_flag {
|
||||
@@ -240,7 +242,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
Ok(FinalizationResult{ gas_left, apply_state: false, return_data }) => {
|
||||
ContractCreateResult::Reverted(gas_left, return_data)
|
||||
},
|
||||
Err(vm::Error::MutableCallInStaticContext) => ContractCreateResult::FailedInStaticCall,
|
||||
_ => ContractCreateResult::Failed,
|
||||
}
|
||||
}
|
||||
@@ -277,6 +278,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
code_hash: Some(code_hash),
|
||||
data: Some(data.to_vec()),
|
||||
call_type: call_type,
|
||||
params_type: vm::ParamsType::Separate,
|
||||
};
|
||||
|
||||
if let Some(value) = value {
|
||||
|
||||
@@ -162,6 +162,12 @@ impl Header {
|
||||
pub fn difficulty(&self) -> &U256 { &self.difficulty }
|
||||
/// Get the seal field of the header.
|
||||
pub fn seal(&self) -> &[Bytes] { &self.seal }
|
||||
/// Get the seal field with RLP-decoded values as bytes.
|
||||
pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(&'a self) -> Result<T, DecoderError> {
|
||||
self.seal.iter().map(|rlp| {
|
||||
UntrustedRlp::new(rlp).data()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
// TODO: seal_at, set_seal_at &c.
|
||||
|
||||
@@ -340,13 +346,20 @@ mod tests {
|
||||
// that's rlp of block header created with ethash engine.
|
||||
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||
let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap();
|
||||
let mix_hash_decoded = "a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap();
|
||||
let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||
let nonce_decoded = "ab4e252a7e8c2a23".from_hex().unwrap();
|
||||
|
||||
let header: Header = rlp::decode(&header_rlp);
|
||||
let seal_fields = header.seal;
|
||||
let seal_fields = header.seal.clone();
|
||||
assert_eq!(seal_fields.len(), 2);
|
||||
assert_eq!(seal_fields[0], mix_hash);
|
||||
assert_eq!(seal_fields[1], nonce);
|
||||
|
||||
let decoded_seal = header.decode_seal::<Vec<_>>().unwrap();
|
||||
assert_eq!(decoded_seal.len(), 2);
|
||||
assert_eq!(decoded_seal[0], &*mix_hash_decoded);
|
||||
assert_eq!(decoded_seal[1], &*nonce_decoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -35,7 +35,7 @@ use tx_filter::TransactionFilter;
|
||||
use bigint::prelude::U256;
|
||||
use bytes::BytesRef;
|
||||
use util::Address;
|
||||
use vm::{CallType, ActionParams, ActionValue};
|
||||
use vm::{CallType, ActionParams, ActionValue, ParamsType};
|
||||
use vm::{EnvInfo, Schedule, CreateContractAddress};
|
||||
|
||||
/// Parity tries to round block.gas_limit to multiple of this constant
|
||||
@@ -149,6 +149,7 @@ impl EthereumMachine {
|
||||
code_hash: Some(state.code_hash(&contract_address)?),
|
||||
data: data,
|
||||
call_type: CallType::Call,
|
||||
params_type: ParamsType::Separate,
|
||||
};
|
||||
let mut ex = Executive::new(&mut state, &env_info, self);
|
||||
let mut substate = Substate::new();
|
||||
@@ -351,7 +352,9 @@ impl EthereumMachine {
|
||||
None => true,
|
||||
};
|
||||
|
||||
let chain_id = if header.number() >= self.params().eip155_transition {
|
||||
let chain_id = if header.number() < self.params().validate_chain_id_transition {
|
||||
t.chain_id()
|
||||
} else if header.number() >= self.params().eip155_transition {
|
||||
Some(self.params().chain_id)
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -525,7 +525,13 @@ impl Miner {
|
||||
fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool {
|
||||
if !block.transactions().is_empty() || self.forced_sealing() || Instant::now() > *self.next_mandatory_reseal.read() {
|
||||
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
|
||||
match self.engine.generate_seal(block.block()) {
|
||||
|
||||
let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) {
|
||||
Some(hdr) => hdr.decode(),
|
||||
None => return false,
|
||||
};
|
||||
|
||||
match self.engine.generate_seal(block.block(), &parent_header) {
|
||||
// Save proposal for later seal submission and broadcast it.
|
||||
Seal::Proposal(seal) => {
|
||||
trace!(target: "miner", "Received a Proposal seal.");
|
||||
@@ -647,10 +653,6 @@ impl Miner {
|
||||
condition: Option<TransactionCondition>,
|
||||
transaction_queue: &mut BanningTransactionQueue,
|
||||
) -> Vec<Result<TransactionImportResult, Error>> {
|
||||
let accounts = self.accounts.as_ref()
|
||||
.and_then(|provider| provider.accounts().ok())
|
||||
.map(|accounts| accounts.into_iter().collect::<HashSet<_>>());
|
||||
|
||||
let best_block_header = client.best_block_header().decode();
|
||||
let insertion_time = client.chain_info().best_block_number;
|
||||
|
||||
@@ -669,8 +671,8 @@ impl Miner {
|
||||
Err(e)
|
||||
},
|
||||
Ok(transaction) => {
|
||||
let origin = accounts.as_ref().and_then(|accounts| {
|
||||
match accounts.contains(&transaction.sender()) {
|
||||
let origin = self.accounts.as_ref().and_then(|accounts| {
|
||||
match accounts.has_account(transaction.sender()).unwrap_or(false) {
|
||||
true => Some(TransactionOrigin::Local),
|
||||
false => None,
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use parking_lot::RwLock;
|
||||
use rlp::{Rlp, RlpStream};
|
||||
use rustc_hex::FromHex;
|
||||
use util::*;
|
||||
use vm::{EnvInfo, CallType, ActionValue, ActionParams};
|
||||
use vm::{EnvInfo, CallType, ActionValue, ActionParams, ParamsType};
|
||||
|
||||
use super::genesis::Genesis;
|
||||
use super::seal::Generic as GenericSeal;
|
||||
@@ -85,6 +85,8 @@ pub struct CommonParams {
|
||||
pub eip155_transition: BlockNumber,
|
||||
/// Validate block receipts root.
|
||||
pub validate_receipts_transition: BlockNumber,
|
||||
/// Validate transaction chain id.
|
||||
pub validate_chain_id_transition: BlockNumber,
|
||||
/// Number of first block where EIP-86 (Metropolis) rules begin.
|
||||
pub eip86_transition: BlockNumber,
|
||||
/// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin.
|
||||
@@ -153,7 +155,7 @@ impl CommonParams {
|
||||
self.validate_receipts_transition != 0 && self.eip86_transition != 0 &&
|
||||
self.eip140_transition != 0 && self.eip210_transition != 0 &&
|
||||
self.eip211_transition != 0 && self.eip214_transition != 0 &&
|
||||
self.dust_protection_transition != 0
|
||||
self.validate_chain_id_transition != 0 && self.dust_protection_transition != 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +180,7 @@ impl From<ethjson::spec::Params> for CommonParams {
|
||||
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
||||
eip155_transition: p.eip155_transition.map_or(0, Into::into),
|
||||
validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into),
|
||||
validate_chain_id_transition: p.validate_chain_id_transition.map_or(0, Into::into),
|
||||
eip86_transition: p.eip86_transition.map_or(
|
||||
BlockNumber::max_value(),
|
||||
Into::into,
|
||||
@@ -501,6 +504,7 @@ impl Spec {
|
||||
code: Some(Arc::new(constructor.clone())),
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
params_type: ParamsType::Embedded,
|
||||
};
|
||||
|
||||
let mut substate = Substate::new();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use hash::keccak;
|
||||
use vm::{EnvInfo, ActionParams, ActionValue, CallType};
|
||||
use vm::{EnvInfo, ActionParams, ActionValue, CallType, ParamsType};
|
||||
use evm::{Factory, VMType};
|
||||
use executive::Executive;
|
||||
use state::Substate;
|
||||
@@ -45,6 +45,7 @@ fn test_blockhash_eip210(factory: Factory) {
|
||||
code_hash: Some(blockhash_contract_code_hash),
|
||||
data: Some(H256::from(i - 1).to_vec()),
|
||||
call_type: CallType::Call,
|
||||
params_type: ParamsType::Separate,
|
||||
};
|
||||
let mut ex = Executive::new(&mut state, &env_info, &machine);
|
||||
let mut substate = Substate::new();
|
||||
@@ -67,6 +68,7 @@ fn test_blockhash_eip210(factory: Factory) {
|
||||
code_hash: Some(get_prev_hash_code_hash),
|
||||
data: None,
|
||||
call_type: CallType::Call,
|
||||
params_type: ParamsType::Separate,
|
||||
};
|
||||
let mut ex = Executive::new(&mut state, &env_info, &machine);
|
||||
let mut substate = Substate::new();
|
||||
|
||||
@@ -469,6 +469,11 @@ impl SignedTransaction {
|
||||
pub fn is_unsigned(&self) -> bool {
|
||||
self.transaction.is_unsigned()
|
||||
}
|
||||
|
||||
/// Deconstructs this transaction back into `UnverifiedTransaction`
|
||||
pub fn deconstruct(self) -> (UnverifiedTransaction, Address, Option<Public>) {
|
||||
(self.transaction, self.sender, self.public)
|
||||
}
|
||||
}
|
||||
|
||||
/// Signed Transaction that is a part of canon blockchain.
|
||||
|
||||
@@ -137,9 +137,14 @@ pub fn verify_block_family(header: &Header, parent: &Header, engine: &EthEngine,
|
||||
|
||||
fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> {
|
||||
let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?;
|
||||
let max_uncles = engine.maximum_uncle_count(header.number());
|
||||
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 })));
|
||||
if num_uncles > max_uncles {
|
||||
return Err(From::from(BlockError::TooManyUncles(OutOfBounds {
|
||||
min: None,
|
||||
max: Some(max_uncles),
|
||||
found: num_uncles,
|
||||
})));
|
||||
}
|
||||
|
||||
let mut excluded = HashSet::new();
|
||||
@@ -268,7 +273,7 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool)
|
||||
}
|
||||
|
||||
if is_full {
|
||||
let max_time = get_time().sec as u64 + 30;
|
||||
let max_time = get_time().sec as u64 + 15;
|
||||
if header.timestamp() > max_time {
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() })))
|
||||
}
|
||||
@@ -641,9 +646,15 @@ mod tests {
|
||||
check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
|
||||
|
||||
header = good.clone();
|
||||
header.set_timestamp(get_time().sec as u64 + 40);
|
||||
header.set_timestamp(get_time().sec as u64 + 20);
|
||||
check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
|
||||
|
||||
header = good.clone();
|
||||
header.set_timestamp(get_time().sec as u64 + 10);
|
||||
header.set_uncles_hash(good_uncles_hash.clone());
|
||||
header.set_transactions_root(good_transactions_root.clone());
|
||||
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
|
||||
|
||||
header = good.clone();
|
||||
header.set_number(9);
|
||||
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
|
||||
@@ -653,7 +664,7 @@ mod tests {
|
||||
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, &bc),
|
||||
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
|
||||
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count(header.number())), min: None, found: bad_uncles.len() }));
|
||||
|
||||
header = good.clone();
|
||||
bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ];
|
||||
|
||||
@@ -21,7 +21,7 @@ use bigint::prelude::U256;
|
||||
use bigint::hash::{H256, H2048};
|
||||
use util::Address;
|
||||
use bytes::Bytes;
|
||||
use rlp::Rlp;
|
||||
use rlp::{self, Rlp};
|
||||
use header::BlockNumber;
|
||||
|
||||
/// View onto block header rlp.
|
||||
@@ -99,6 +99,14 @@ impl<'a> HeaderView<'a> {
|
||||
}
|
||||
seal
|
||||
}
|
||||
|
||||
/// Returns a vector of seal fields (RLP-decoded).
|
||||
pub fn decode_seal(&self) -> Result<Vec<Bytes>, rlp::DecoderError> {
|
||||
let seal = self.seal();
|
||||
seal.into_iter()
|
||||
.map(|s| rlp::UntrustedRlp::new(&s).data().map(|x| x.to_vec()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -35,6 +35,15 @@ pub enum ActionValue {
|
||||
Apparent(U256)
|
||||
}
|
||||
|
||||
/// Type of the way parameters encoded
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ParamsType {
|
||||
/// Parameters are included in code
|
||||
Embedded,
|
||||
/// Parameters are passed in data section
|
||||
Separate,
|
||||
}
|
||||
|
||||
impl ActionValue {
|
||||
/// Returns action value as U256.
|
||||
pub fn value(&self) -> U256 {
|
||||
@@ -81,7 +90,8 @@ pub struct ActionParams {
|
||||
pub data: Option<Bytes>,
|
||||
/// Type of call
|
||||
pub call_type: CallType,
|
||||
|
||||
/// Param types encoding
|
||||
pub params_type: ParamsType,
|
||||
}
|
||||
|
||||
impl Default for ActionParams {
|
||||
@@ -99,6 +109,7 @@ impl Default for ActionParams {
|
||||
code: None,
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
params_type: ParamsType::Separate,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,6 +129,7 @@ impl From<ethjson::vm::Transaction> for ActionParams {
|
||||
gas_price: t.gas_price.into(),
|
||||
value: ActionValue::Transfer(t.value.into()),
|
||||
call_type: match address.is_zero() { true => CallType::None, false => CallType::Call }, // TODO @debris is this correct?
|
||||
params_type: ParamsType::Separate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,6 @@ pub enum ContractCreateResult {
|
||||
/// Returned when contract creation failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
Failed,
|
||||
/// Returned when contract creation failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
FailedInStaticCall,
|
||||
/// Reverted with REVERT.
|
||||
Reverted(U256, ReturnData),
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ mod error;
|
||||
|
||||
pub mod tests;
|
||||
|
||||
pub use action_params::{ActionParams, ActionValue};
|
||||
pub use action_params::{ActionParams, ActionValue, ParamsType};
|
||||
pub use call_type::CallType;
|
||||
pub use env_info::{EnvInfo, LastHashes};
|
||||
pub use schedule::{Schedule, CleanDustMode};
|
||||
|
||||
@@ -127,12 +127,14 @@ pub struct WasmCosts {
|
||||
pub mul: u32,
|
||||
/// Memory (load/store) operations multiplier.
|
||||
pub mem: u32,
|
||||
/// Memory copy operation.
|
||||
/// Memory copy operation, per byte.
|
||||
pub mem_copy: u32,
|
||||
/// Memory move operation, per byte.
|
||||
pub mem_move: u32,
|
||||
/// Memory set operation, per byte.
|
||||
pub mem_set: u32,
|
||||
/// Static region charge, per byte.
|
||||
pub static_region: u32,
|
||||
/// General static query of u64 value from env-info
|
||||
pub static_u64: u32,
|
||||
/// General static query of U256 value from env-info
|
||||
pub static_u256: u32,
|
||||
/// General static query of Address value from env-info
|
||||
@@ -147,11 +149,9 @@ impl Default for WasmCosts {
|
||||
mul: 4,
|
||||
mem: 2,
|
||||
mem_copy: 1,
|
||||
mem_move: 1,
|
||||
mem_set: 1,
|
||||
static_region: 1,
|
||||
|
||||
// due to runtime issues, this can be slow
|
||||
static_u64: 32,
|
||||
|
||||
static_u256: 64,
|
||||
static_address: 40,
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ pub struct FakeExt {
|
||||
pub schedule: Schedule,
|
||||
pub balances: HashMap<Address, U256>,
|
||||
pub tracing: bool,
|
||||
pub is_static: bool,
|
||||
}
|
||||
|
||||
// similar to the normal `finalize` function, but ignoring NeedsReturn.
|
||||
@@ -192,7 +193,7 @@ impl Ext for FakeExt {
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
false
|
||||
self.is_static
|
||||
}
|
||||
|
||||
fn inc_sstore_clears(&mut self) {
|
||||
|
||||
@@ -8,7 +8,7 @@ byteorder = "1.0"
|
||||
ethcore-util = { path = "../../util" }
|
||||
ethcore-bigint = { path = "../../util/bigint" }
|
||||
log = "0.3"
|
||||
parity-wasm = "0.14"
|
||||
parity-wasm = "0.15"
|
||||
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
||||
vm = { path = "../vm" }
|
||||
ethcore-logger = { path = "../../logger" }
|
||||
|
||||
@@ -25,12 +25,12 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
Static(
|
||||
"_storage_read",
|
||||
&[I32; 2],
|
||||
Some(I32),
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_storage_write",
|
||||
&[I32; 2],
|
||||
Some(I32),
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_balance",
|
||||
@@ -38,12 +38,12 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_malloc",
|
||||
"_ext_malloc",
|
||||
&[I32],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_free",
|
||||
"_ext_free",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
@@ -92,6 +92,21 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ext_memcpy",
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ext_memset",
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ext_memmove",
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_panic",
|
||||
&[I32; 2],
|
||||
@@ -99,8 +114,8 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
),
|
||||
Static(
|
||||
"_blockhash",
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
&[I64, I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_coinbase",
|
||||
@@ -130,12 +145,12 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
Static(
|
||||
"_timestamp",
|
||||
&[],
|
||||
Some(I32),
|
||||
Some(I64),
|
||||
),
|
||||
Static(
|
||||
"_blocknumber",
|
||||
&[],
|
||||
Some(I32),
|
||||
Some(I64),
|
||||
),
|
||||
Static(
|
||||
"_difficulty",
|
||||
@@ -147,6 +162,11 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_elog",
|
||||
&[I32; 4],
|
||||
None,
|
||||
),
|
||||
|
||||
// TODO: Get rid of it also somehow?
|
||||
Static(
|
||||
@@ -157,8 +177,8 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
|
||||
Static(
|
||||
"_llvm_bswap_i64",
|
||||
&[I32; 2],
|
||||
Some(I32)
|
||||
&[I64],
|
||||
Some(I64)
|
||||
),
|
||||
];
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ mod result;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod env;
|
||||
mod panic_payload;
|
||||
|
||||
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
||||
|
||||
@@ -115,7 +116,18 @@ impl vm::Vm for WasmInterpreter {
|
||||
&self.program,
|
||||
);
|
||||
|
||||
let mut cursor = ::std::io::Cursor::new(&*code);
|
||||
let (mut cursor, data_position) = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
let module_size = parity_wasm::peek_size(&*code);
|
||||
(
|
||||
::std::io::Cursor::new(&code[..module_size]),
|
||||
module_size
|
||||
)
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
(::std::io::Cursor::new(&code[..]), 0)
|
||||
},
|
||||
};
|
||||
|
||||
let contract_module = wasm_utils::inject_gas_counter(
|
||||
elements::Module::deserialize(
|
||||
@@ -134,8 +146,19 @@ impl vm::Vm for WasmInterpreter {
|
||||
let static_segment_cost = data_section_length * runtime.ext().schedule().wasm.static_region as u64;
|
||||
runtime.charge(|_| static_segment_cost).map_err(Error)?;
|
||||
|
||||
let d_ptr = runtime.write_descriptor(¶ms.data.unwrap_or_default())
|
||||
.map_err(Error)?;
|
||||
let d_ptr = {
|
||||
match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
runtime.write_descriptor(
|
||||
if data_position < code.len() { &code[data_position..] } else { &[] }
|
||||
).map_err(Error)?
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
runtime.write_descriptor(¶ms.data.unwrap_or_default())
|
||||
.map_err(Error)?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
let execution_params = runtime.execution_params()
|
||||
|
||||
168
ethcore/wasm/src/panic_payload.rs
Normal file
168
ethcore/wasm/src/panic_payload.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright 2015-2017 Parity Technologies (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 byteorder::{LittleEndian, ReadBytesExt};
|
||||
use std::io::{self, Read};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct PanicPayload {
|
||||
pub msg: Option<String>,
|
||||
pub file: Option<String>,
|
||||
pub line: Option<u32>,
|
||||
pub col: Option<u32>,
|
||||
}
|
||||
|
||||
fn read_string(rdr: &mut io::Cursor<&[u8]>) -> io::Result<Option<String>> {
|
||||
let string_len = rdr.read_u32::<LittleEndian>()?;
|
||||
let string = if string_len == 0 {
|
||||
None
|
||||
} else {
|
||||
let mut content = vec![0; string_len as usize];
|
||||
rdr.read_exact(&mut content)?;
|
||||
Some(String::from_utf8_lossy(&content).into_owned())
|
||||
};
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
pub fn decode(raw: &[u8]) -> PanicPayload {
|
||||
let mut rdr = io::Cursor::new(raw);
|
||||
let msg = read_string(&mut rdr).ok().and_then(|x| x);
|
||||
let file = read_string(&mut rdr).ok().and_then(|x| x);
|
||||
let line = rdr.read_u32::<LittleEndian>().ok();
|
||||
let col = rdr.read_u32::<LittleEndian>().ok();
|
||||
PanicPayload {
|
||||
msg: msg,
|
||||
file: file,
|
||||
line: line,
|
||||
col: col,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use byteorder::WriteBytesExt;
|
||||
|
||||
fn write_u32(payload: &mut Vec<u8>, val: u32) {
|
||||
payload.write_u32::<LittleEndian>(val).unwrap();
|
||||
}
|
||||
|
||||
fn write_bytes(payload: &mut Vec<u8>, bytes: &[u8]) {
|
||||
write_u32(payload, bytes.len() as u32);
|
||||
payload.extend(bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_msg() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: None,
|
||||
line: None,
|
||||
col: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_utf8() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"\xF0\x90\x80msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("<EFBFBD>msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_data() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
write_u32(&mut raw, 0xdeadbeef);
|
||||
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_str_is_none() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"");
|
||||
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: None,
|
||||
line: None,
|
||||
col: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ use std::sync::Arc;
|
||||
use byteorder::{LittleEndian, ByteOrder};
|
||||
|
||||
use vm;
|
||||
use panic_payload;
|
||||
use parity_wasm::interpreter;
|
||||
use wasm_utils::rules;
|
||||
use bigint::prelude::U256;
|
||||
@@ -55,6 +56,8 @@ pub enum UserTrap {
|
||||
Unknown,
|
||||
/// Passed string had invalid utf-8 encoding
|
||||
BadUtf8,
|
||||
/// Log event error
|
||||
Log,
|
||||
/// Other error in native code
|
||||
Other,
|
||||
/// Panic with message
|
||||
@@ -75,6 +78,7 @@ impl ::std::fmt::Display for UserTrap {
|
||||
UserTrap::AllocationFailed => write!(f, "Memory allocation failed (OOM)"),
|
||||
UserTrap::BadUtf8 => write!(f, "String encoding is bad utf-8 sequence"),
|
||||
UserTrap::GasLimit => write!(f, "Invocation resulted in gas limit violated"),
|
||||
UserTrap::Log => write!(f, "Error occured while logging an event"),
|
||||
UserTrap::Other => write!(f, "Other unspecified error"),
|
||||
UserTrap::Panic(ref msg) => write!(f, "Panic: {}", msg),
|
||||
}
|
||||
@@ -164,7 +168,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
|
||||
self.ext.set_storage(key, val).map_err(|_| UserTrap::StorageUpdateError)?;
|
||||
|
||||
Ok(Some(0i32.into()))
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Read from the storage to wasm memory
|
||||
@@ -180,7 +184,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
|
||||
self.memory.set(val_ptr as u32, &*val)?;
|
||||
|
||||
Ok(Some(0.into()))
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Fetches balance for address
|
||||
@@ -221,8 +225,8 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
}
|
||||
|
||||
/// Charge gas according to closure
|
||||
pub fn charge<F>(&mut self, f: F) -> Result<(), InterpreterError>
|
||||
where F: FnOnce(&vm::Schedule) -> u64
|
||||
pub fn charge<F>(&mut self, f: F) -> Result<(), InterpreterError>
|
||||
where F: FnOnce(&vm::Schedule) -> u64
|
||||
{
|
||||
let amount = f(self.ext.schedule());
|
||||
if !self.charge_gas(amount as u64) {
|
||||
@@ -232,6 +236,21 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overflow_charge<F>(&mut self, f: F) -> Result<(), InterpreterError>
|
||||
where F: FnOnce(&vm::Schedule) -> Option<u64>
|
||||
{
|
||||
let amount = match f(self.ext.schedule()) {
|
||||
Some(amount) => amount,
|
||||
None => { return Err(UserTrap::GasLimit.into()); }
|
||||
};
|
||||
|
||||
if !self.charge_gas(amount as u64) {
|
||||
Err(UserTrap::GasLimit.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Invoke create in the state runtime
|
||||
pub fn create(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
@@ -277,10 +296,6 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
self.gas_counter = self.gas_limit - gas_left.low_u64();
|
||||
Ok(Some((-1i32).into()))
|
||||
},
|
||||
vm::ContractCreateResult::FailedInStaticCall => {
|
||||
trace!(target: "wasm", "runtime: create contract called in static context");
|
||||
Err(interpreter::Error::Trap("CREATE in static context".to_owned()))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,43 +561,92 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
fn mem_copy(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
//
|
||||
// method signature:
|
||||
// fn memcpy(dest: *const u8, src: *const u8, len: u32) -> *mut u8;
|
||||
//
|
||||
|
||||
let len = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let dst = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let src = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let dst = context.value_stack.pop_as::<i32>()? as u32;
|
||||
|
||||
self.charge(|schedule| schedule.wasm.mem_copy as u64 * len as u64)?;
|
||||
|
||||
let mem = self.memory().get(src, len as usize)?;
|
||||
self.memory().set(dst, &mem)?;
|
||||
self.memory().copy_nonoverlapping(src as usize, dst as usize, len as usize)?;
|
||||
|
||||
Ok(Some(0i32.into()))
|
||||
Ok(Some(Into::into(dst as i32)))
|
||||
}
|
||||
|
||||
fn bswap_32(x: u32) -> u32 {
|
||||
x >> 24 | x >> 8 & 0xff00 | x << 8 & 0xff0000 | x << 24
|
||||
fn mem_move(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
//
|
||||
// method signature:
|
||||
// fn memmove(dest: *const u8, src: *const u8, len: u32) -> *mut u8;
|
||||
//
|
||||
|
||||
let len = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let src = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let dst = context.value_stack.pop_as::<i32>()? as u32;
|
||||
|
||||
self.charge(|schedule| schedule.wasm.mem_move as u64 * len as u64)?;
|
||||
|
||||
self.memory().copy(src as usize, dst as usize, len as usize)?;
|
||||
|
||||
Ok(Some(Into::into(dst as i32)))
|
||||
}
|
||||
|
||||
fn mem_set(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
//
|
||||
// method signature:
|
||||
// fn memset(dest: *const u8, c: u32, len: u32) -> *mut u8;
|
||||
//
|
||||
|
||||
let len = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let c = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let dst = context.value_stack.pop_as::<i32>()? as u32;
|
||||
|
||||
self.charge(|schedule| schedule.wasm.mem_set as u64 * len as u64)?;
|
||||
|
||||
self.memory().clear(dst as usize, c as u8, len as usize)?;
|
||||
|
||||
Ok(Some(Into::into(dst as i32)))
|
||||
}
|
||||
|
||||
fn bitswap_i64(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
let x1 = context.value_stack.pop_as::<i32>()?;
|
||||
let x2 = context.value_stack.pop_as::<i32>()?;
|
||||
let x = context.value_stack.pop_as::<i64>()?;
|
||||
let result = x.swap_bytes();
|
||||
|
||||
let result = ((Runtime::bswap_32(x2 as u32) as u64) << 32
|
||||
| Runtime::bswap_32(x1 as u32) as u64) as i64;
|
||||
|
||||
self.return_i64(result)
|
||||
Ok(Some(result.into()))
|
||||
}
|
||||
|
||||
fn user_panic(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
let msg_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let msg_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||
|
||||
let msg = String::from_utf8(self.memory.get(msg_ptr, msg_len as usize)?)
|
||||
.map_err(|_| UserTrap::BadUtf8)?;
|
||||
let payload_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let payload_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||
|
||||
let raw_payload = self.memory.get(payload_ptr, payload_len as usize)?;
|
||||
let payload = panic_payload::decode(&raw_payload);
|
||||
let msg = format!(
|
||||
"{msg}, {file}:{line}:{col}",
|
||||
msg = payload
|
||||
.msg
|
||||
.as_ref()
|
||||
.map(String::as_ref)
|
||||
.unwrap_or("<msg was stripped>"),
|
||||
file = payload
|
||||
.file
|
||||
.as_ref()
|
||||
.map(String::as_ref)
|
||||
.unwrap_or("<unknown>"),
|
||||
line = payload.line.unwrap_or(0),
|
||||
col = payload.col.unwrap_or(0)
|
||||
);
|
||||
trace!(target: "wasm", "Contract custom panic message: {}", msg);
|
||||
|
||||
Err(UserTrap::Panic(msg).into())
|
||||
@@ -592,19 +656,16 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let block_hi = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let block_lo = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let block_num = context.value_stack.pop_as::<i64>()? as u64;
|
||||
|
||||
self.charge(|schedule| schedule.blockhash_gas as u64)?;
|
||||
|
||||
let block_num = (block_hi as u64) << 32 | block_lo as u64;
|
||||
|
||||
trace!("Requesting block hash for block #{}", block_num);
|
||||
let hash = self.ext.blockhash(&U256::from(block_num));
|
||||
|
||||
self.memory.set(return_ptr, &*hash)?;
|
||||
|
||||
Ok(Some(0i32.into()))
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn return_address_ptr(&mut self, ptr: u32, val: Address) -> Result<(), InterpreterError>
|
||||
@@ -615,11 +676,11 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
}
|
||||
|
||||
fn return_u256_ptr(&mut self, ptr: u32, val: U256) -> Result<(), InterpreterError> {
|
||||
let value: H256 = val.into();
|
||||
let value: H256 = val.into();
|
||||
self.charge(|schedule| schedule.wasm.static_u256 as u64)?;
|
||||
self.memory.set(ptr, &*value)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn coinbase(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
@@ -640,7 +701,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
context.value_stack.pop_as::<i32>()? as u32,
|
||||
sender,
|
||||
)?;
|
||||
Ok(None)
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn address(&mut self, context: InterpreterCallerContext)
|
||||
@@ -651,7 +712,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
context.value_stack.pop_as::<i32>()? as u32,
|
||||
addr,
|
||||
)?;
|
||||
Ok(None)
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn origin(&mut self, context: InterpreterCallerContext)
|
||||
@@ -662,7 +723,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
context.value_stack.pop_as::<i32>()? as u32,
|
||||
origin,
|
||||
)?;
|
||||
Ok(None)
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn value(&mut self, context: InterpreterCallerContext)
|
||||
@@ -680,14 +741,14 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
let timestamp = self.ext.env_info().timestamp as i64;
|
||||
self.return_i64(timestamp)
|
||||
Ok(Some(timestamp.into()))
|
||||
}
|
||||
|
||||
fn block_number(&mut self, _context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
let block_number: u64 = self.ext.env_info().number.into();
|
||||
self.return_i64(block_number as i64)
|
||||
let block_number = self.ext.env_info().number as i64;
|
||||
Ok(Some(block_number.into()))
|
||||
}
|
||||
|
||||
fn difficulty(&mut self, context: InterpreterCallerContext)
|
||||
@@ -709,26 +770,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
context.value_stack.pop_as::<i32>()? as u32,
|
||||
gas_limit,
|
||||
)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn return_i64(&mut self, val: i64) -> Result<Option<interpreter::RuntimeValue>, InterpreterError> {
|
||||
self.charge(|schedule| schedule.wasm.static_u64 as u64)?;
|
||||
|
||||
let uval = val as u64;
|
||||
let hi = (uval >> 32) as i32;
|
||||
let lo = (uval << 32 >> 32) as i32;
|
||||
|
||||
let target = self.instance.module("contract").ok_or(UserTrap::Other)?;
|
||||
target.execute_export(
|
||||
"setTempRet0",
|
||||
self.execution_params().add_argument(
|
||||
interpreter::RuntimeValue::I32(hi).into()
|
||||
),
|
||||
)?;
|
||||
Ok(Some(
|
||||
(lo).into()
|
||||
))
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn execution_params(&mut self) -> interpreter::ExecutionParams<UserTrap> {
|
||||
@@ -753,6 +795,44 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
||||
pub fn ext(&mut self) -> &mut vm::Ext {
|
||||
self.ext
|
||||
}
|
||||
|
||||
pub fn log(&mut self, context: InterpreterCallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
// signature is:
|
||||
// pub fn elog(topic_ptr: *const u8, topic_count: u32, data_ptr: *const u8, data_len: u32);
|
||||
let data_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let data_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let topic_count = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let topic_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||
|
||||
if topic_count > 4 {
|
||||
return Err(UserTrap::Log.into());
|
||||
}
|
||||
|
||||
self.overflow_charge(|schedule|
|
||||
{
|
||||
let topics_gas = schedule.log_gas as u64 + schedule.log_topic_gas as u64 * topic_count as u64;
|
||||
(schedule.log_data_gas as u64)
|
||||
.checked_mul(schedule.log_data_gas as u64)
|
||||
.and_then(|data_gas| data_gas.checked_add(topics_gas))
|
||||
}
|
||||
)?;
|
||||
|
||||
let mut topics: Vec<H256> = Vec::with_capacity(topic_count as usize);
|
||||
topics.resize(topic_count as usize, H256::zero());
|
||||
for i in 0..topic_count {
|
||||
let offset = i.checked_mul(32).ok_or(UserTrap::MemoryAccessViolation)?
|
||||
.checked_add(topic_ptr).ok_or(UserTrap::MemoryAccessViolation)?;
|
||||
|
||||
*topics.get_mut(i as usize)
|
||||
.expect("topics is resized to `topic_count`, i is in 0..topic count iterator, get_mut uses i as an indexer, get_mut cannot fail; qed")
|
||||
= H256::from(&self.memory.get(offset, 32)?[..]);
|
||||
}
|
||||
self.ext.log(topics, &self.memory.get(data_ptr, data_len as usize)?).map_err(|_| UserTrap::Log)?;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
|
||||
@@ -760,10 +840,10 @@ impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
|
||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
match name {
|
||||
"_malloc" => {
|
||||
"_ext_malloc" => {
|
||||
self.malloc(context)
|
||||
},
|
||||
"_free" => {
|
||||
"_ext_free" => {
|
||||
// Since it is arena allocator, free does nothing
|
||||
// todo: update if changed
|
||||
self.user_noop(context)
|
||||
@@ -801,6 +881,15 @@ impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
|
||||
"_emscripten_memcpy_big" => {
|
||||
self.mem_copy(context)
|
||||
},
|
||||
"_ext_memcpy" => {
|
||||
self.mem_copy(context)
|
||||
},
|
||||
"_ext_memmove" => {
|
||||
self.mem_move(context)
|
||||
},
|
||||
"_ext_memset" => {
|
||||
self.mem_set(context)
|
||||
},
|
||||
"_llvm_bswap_i64" => {
|
||||
self.bitswap_i64(context)
|
||||
},
|
||||
@@ -837,6 +926,9 @@ impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
|
||||
"_value" => {
|
||||
self.value(context)
|
||||
},
|
||||
"_elog" => {
|
||||
self.log(context)
|
||||
},
|
||||
_ => {
|
||||
trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name);
|
||||
Ok(self.unknown_trap(context)?)
|
||||
|
||||
@@ -60,7 +60,7 @@ fn empty() {
|
||||
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(99_976));
|
||||
assert_eq!(gas_left, U256::from(99_982));
|
||||
}
|
||||
|
||||
// This test checks if the contract deserializes payload header properly.
|
||||
@@ -89,7 +89,6 @@ fn logger() {
|
||||
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(15_177));
|
||||
let address_val: H256 = address.into();
|
||||
assert_eq!(
|
||||
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
||||
@@ -113,6 +112,7 @@ fn logger() {
|
||||
U256::from(1_000_000_000),
|
||||
"Logger sets 0x04 key to the trasferred value"
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(19_147));
|
||||
}
|
||||
|
||||
// This test checks if the contract can allocate memory and pass pointer to the result stream properly.
|
||||
@@ -142,13 +142,12 @@ fn identity() {
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(99_695));
|
||||
|
||||
assert_eq!(
|
||||
Address::from_slice(&result),
|
||||
sender,
|
||||
"Idenity test contract does not return the sender passed"
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(99_844));
|
||||
}
|
||||
|
||||
// Dispersion test sends byte array and expect the contract to 'disperse' the original elements with
|
||||
@@ -176,12 +175,12 @@ fn dispersion() {
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(96_543));
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(96_393));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -205,12 +204,11 @@ fn suicide_not() {
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(96_822));
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
vec![0u8]
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(96_725));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -241,8 +239,8 @@ fn suicide() {
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(96_580));
|
||||
assert!(ext.suicides.contains(&refund));
|
||||
assert_eq!(gas_left, U256::from(96_687));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -272,7 +270,7 @@ fn create() {
|
||||
assert!(ext.calls.contains(
|
||||
&FakeCall {
|
||||
call_type: FakeCallType::Create,
|
||||
gas: U256::from(62_324),
|
||||
gas: U256::from(65_899),
|
||||
sender_address: None,
|
||||
receive_address: None,
|
||||
value: Some(1_000_000_000.into()),
|
||||
@@ -280,7 +278,7 @@ fn create() {
|
||||
code_address: None,
|
||||
}
|
||||
));
|
||||
assert_eq!(gas_left, U256::from(62_289));
|
||||
assert_eq!(gas_left, U256::from(65_892));
|
||||
}
|
||||
|
||||
|
||||
@@ -314,7 +312,7 @@ fn call_code() {
|
||||
assert!(ext.calls.contains(
|
||||
&FakeCall {
|
||||
call_type: FakeCallType::Call,
|
||||
gas: U256::from(95_585),
|
||||
gas: U256::from(98_713),
|
||||
sender_address: Some(sender),
|
||||
receive_address: Some(receiver),
|
||||
value: None,
|
||||
@@ -322,11 +320,11 @@ fn call_code() {
|
||||
code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()),
|
||||
}
|
||||
));
|
||||
assert_eq!(gas_left, U256::from(90_665));
|
||||
|
||||
// siphash result
|
||||
let res = LittleEndian::read_u32(&result[..]);
|
||||
assert_eq!(res, 4198595614);
|
||||
assert_eq!(gas_left, U256::from(93_855));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -359,7 +357,7 @@ fn call_static() {
|
||||
assert!(ext.calls.contains(
|
||||
&FakeCall {
|
||||
call_type: FakeCallType::Call,
|
||||
gas: U256::from(95_585),
|
||||
gas: U256::from(98_713),
|
||||
sender_address: Some(sender),
|
||||
receive_address: Some(receiver),
|
||||
value: None,
|
||||
@@ -367,11 +365,12 @@ fn call_static() {
|
||||
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
|
||||
}
|
||||
));
|
||||
assert_eq!(gas_left, U256::from(90_665));
|
||||
|
||||
// siphash result
|
||||
let res = LittleEndian::read_u32(&result[..]);
|
||||
assert_eq!(res, 317632590);
|
||||
|
||||
assert_eq!(gas_left, U256::from(93_855));
|
||||
}
|
||||
|
||||
// Realloc test
|
||||
@@ -393,8 +392,8 @@ fn realloc() {
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
assert_eq!(gas_left, U256::from(96_811));
|
||||
assert_eq!(result, vec![0u8; 2]);
|
||||
assert_eq!(gas_left, U256::from(96_723));
|
||||
}
|
||||
|
||||
// Tests that contract's ability to read from a storage
|
||||
@@ -419,8 +418,8 @@ fn storage_read() {
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(96_645));
|
||||
assert_eq!(Address::from(&result[12..32]), address);
|
||||
assert_eq!(gas_left, U256::from(99_767));
|
||||
}
|
||||
|
||||
// Tests keccak calculation
|
||||
@@ -446,9 +445,97 @@ fn keccak() {
|
||||
};
|
||||
|
||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||
assert_eq!(gas_left, U256::from(80_452));
|
||||
assert_eq!(gas_left, U256::from(81_446));
|
||||
}
|
||||
|
||||
// memcpy test.
|
||||
#[test]
|
||||
fn memcpy() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("mem.wasm");
|
||||
|
||||
let mut test_payload = Vec::with_capacity(8192);
|
||||
for i in 0..8192 {
|
||||
test_payload.push((i % 255) as u8);
|
||||
}
|
||||
let mut data = vec![0u8];
|
||||
data.extend(&test_payload);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(data);
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("mem should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(result, test_payload);
|
||||
assert_eq!(gas_left, U256::from(72_216));
|
||||
}
|
||||
|
||||
// memmove test.
|
||||
#[test]
|
||||
fn memmove() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("mem.wasm");
|
||||
|
||||
let mut test_payload = Vec::with_capacity(8192);
|
||||
for i in 0..8192 {
|
||||
test_payload.push((i % 255) as u8);
|
||||
}
|
||||
let mut data = vec![1u8];
|
||||
data.extend(&test_payload);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(data);
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("mem should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(result, test_payload);
|
||||
assert_eq!(gas_left, U256::from(72_216));
|
||||
}
|
||||
|
||||
// memset test
|
||||
#[test]
|
||||
fn memset() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("mem.wasm");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(vec![2u8, 228u8]);
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("mem should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(result, vec![228u8; 8192]);
|
||||
assert_eq!(gas_left, U256::from(72_196));
|
||||
}
|
||||
|
||||
macro_rules! reqrep_test {
|
||||
($name: expr, $input: expr) => {
|
||||
@@ -500,11 +587,11 @@ fn math_add() {
|
||||
}
|
||||
).expect("Interpreter to execute without any errors");
|
||||
|
||||
assert_eq!(gas_left, U256::from(94_666));
|
||||
assert_eq!(
|
||||
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(95_524));
|
||||
}
|
||||
|
||||
// multiplication
|
||||
@@ -522,11 +609,11 @@ fn math_mul() {
|
||||
}
|
||||
).expect("Interpreter to execute without any errors");
|
||||
|
||||
assert_eq!(gas_left, U256::from(93_719));
|
||||
assert_eq!(
|
||||
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(94_674));
|
||||
}
|
||||
|
||||
// subtraction
|
||||
@@ -544,11 +631,11 @@ fn math_sub() {
|
||||
}
|
||||
).expect("Interpreter to execute without any errors");
|
||||
|
||||
assert_eq!(gas_left, U256::from(94_718));
|
||||
assert_eq!(
|
||||
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(95_516));
|
||||
}
|
||||
|
||||
// subtraction with overflow
|
||||
@@ -566,7 +653,10 @@ fn math_sub_with_overflow() {
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(result, Err(vm::Error::Wasm("Wasm runtime error: User(Panic(\"arithmetic operation overflow\"))".into())));
|
||||
match result {
|
||||
Err(vm::Error::Wasm(_)) => {},
|
||||
_ => panic!("Unexpected result {:?}", result),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -583,11 +673,11 @@ fn math_div() {
|
||||
}
|
||||
).expect("Interpreter to execute without any errors");
|
||||
|
||||
assert_eq!(gas_left, U256::from(86_996));
|
||||
assert_eq!(
|
||||
U256::from_dec_str("1125000").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(88_514));
|
||||
}
|
||||
|
||||
// This test checks the ability of wasm contract to invoke
|
||||
@@ -675,5 +765,66 @@ fn externs() {
|
||||
"Gas limit requested and returned does not match"
|
||||
);
|
||||
|
||||
assert_eq!(gas_left, U256::from(91_857));
|
||||
assert_eq!(gas_left, U256::from(94_858));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn embedded_keccak() {
|
||||
::ethcore_logger::init_log();
|
||||
let mut code = load_sample!("keccak.wasm");
|
||||
code.extend_from_slice(b"something");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.params_type = vm::ParamsType::Embedded;
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("keccak should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||
assert_eq!(gas_left, U256::from(81_446));
|
||||
}
|
||||
|
||||
/// This test checks the correctness of log extern
|
||||
/// Target test puts one event with two topic [keccak(input), reverse(keccak(input))]
|
||||
/// and reversed input as a data
|
||||
#[test]
|
||||
fn events() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("events.wasm");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(b"something".to_vec());
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("events should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(ext.logs.len(), 1);
|
||||
let log_entry = &ext.logs[0];
|
||||
assert_eq!(log_entry.topics.len(), 2);
|
||||
assert_eq!(&log_entry.topics[0], &H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||
assert_eq!(&log_entry.topics[1], &H256::from("871d5ea37430753faab7dff7a7187783517d83bd822c02e28a164c887e1d3768"));
|
||||
assert_eq!(&log_entry.data, b"gnihtemos");
|
||||
|
||||
assert_eq!(&result, b"gnihtemos");
|
||||
assert_eq!(gas_left, U256::from(79_637));
|
||||
}
|
||||
|
||||
@@ -122,6 +122,13 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
|
||||
Ok(hasher.finish())
|
||||
}
|
||||
|
||||
fn last_modification_date(&self) -> Result<u64, Error> {
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
let duration = fs::metadata(&self.path)?.modified()?.duration_since(UNIX_EPOCH).unwrap_or(Duration::default());
|
||||
let timestamp = duration.as_secs() ^ (duration.subsec_nanos() as u64);
|
||||
Ok(timestamp)
|
||||
}
|
||||
|
||||
/// all accounts found in keys directory
|
||||
fn files_content(&self) -> Result<HashMap<PathBuf, SafeAccount>, Error> {
|
||||
// it's not done using one iterator cause
|
||||
@@ -226,7 +233,7 @@ impl<T> KeyDirectory for DiskDirectory<T> where T: KeyFileManager {
|
||||
}
|
||||
|
||||
fn unique_repr(&self) -> Result<u64, Error> {
|
||||
self.files_hash()
|
||||
self.last_modification_date()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ use std::collections::{BTreeMap, HashMap};
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use std::time::{Instant, Duration};
|
||||
|
||||
use crypto::KEY_ITERATIONS;
|
||||
use random::Random;
|
||||
@@ -28,6 +29,8 @@ use presale::PresaleWallet;
|
||||
use json::{self, Uuid, OpaqueKeyFile};
|
||||
use {import, Error, SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation, OpaqueSecret};
|
||||
|
||||
const REFRESH_TIME_SEC: u64 = 5;
|
||||
|
||||
/// Accounts store.
|
||||
pub struct EthStore {
|
||||
store: EthMultiStore,
|
||||
@@ -245,7 +248,12 @@ pub struct EthMultiStore {
|
||||
// order lock: cache, then vaults
|
||||
cache: RwLock<BTreeMap<StoreAccountRef, Vec<SafeAccount>>>,
|
||||
vaults: Mutex<HashMap<String, Box<VaultKeyDirectory>>>,
|
||||
dir_hash: Mutex<Option<u64>>,
|
||||
timestamp: Mutex<Timestamp>,
|
||||
}
|
||||
|
||||
struct Timestamp {
|
||||
dir_hash: Option<u64>,
|
||||
last_checked: Instant,
|
||||
}
|
||||
|
||||
impl EthMultiStore {
|
||||
@@ -261,20 +269,27 @@ impl EthMultiStore {
|
||||
vaults: Mutex::new(HashMap::new()),
|
||||
iterations: iterations,
|
||||
cache: Default::default(),
|
||||
dir_hash: Default::default(),
|
||||
timestamp: Mutex::new(Timestamp {
|
||||
dir_hash: None,
|
||||
last_checked: Instant::now(),
|
||||
}),
|
||||
};
|
||||
store.reload_accounts()?;
|
||||
Ok(store)
|
||||
}
|
||||
|
||||
fn reload_if_changed(&self) -> Result<(), Error> {
|
||||
let mut last_dir_hash = self.dir_hash.lock();
|
||||
let dir_hash = Some(self.dir.unique_repr()?);
|
||||
if *last_dir_hash == dir_hash {
|
||||
return Ok(())
|
||||
let mut last_timestamp = self.timestamp.lock();
|
||||
let now = Instant::now();
|
||||
if (now - last_timestamp.last_checked) > Duration::from_secs(REFRESH_TIME_SEC) {
|
||||
let dir_hash = Some(self.dir.unique_repr()?);
|
||||
last_timestamp.last_checked = now;
|
||||
if last_timestamp.dir_hash == dir_hash {
|
||||
return Ok(())
|
||||
}
|
||||
self.reload_accounts()?;
|
||||
last_timestamp.dir_hash = dir_hash;
|
||||
}
|
||||
self.reload_accounts()?;
|
||||
*last_dir_hash = dir_hash;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -455,11 +470,11 @@ impl SimpleSecretStore for EthMultiStore {
|
||||
}
|
||||
|
||||
fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error> {
|
||||
use std::collections::Bound;
|
||||
self.reload_if_changed()?;
|
||||
self.cache.read().keys()
|
||||
.find(|r| &r.address == address)
|
||||
.cloned()
|
||||
.ok_or(Error::InvalidAccount)
|
||||
let cache = self.cache.read();
|
||||
let mut r = cache.range((Bound::Included(*address), Bound::Included(*address)));
|
||||
r.next().ok_or(Error::InvalidAccount).map(|(k, _)| k.clone())
|
||||
}
|
||||
|
||||
fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error> {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::path::PathBuf;
|
||||
use std::cmp::Ordering;
|
||||
use ethkey::{Address, Message, Signature, Secret, Public};
|
||||
use Error;
|
||||
use json::{Uuid, OpaqueKeyFile};
|
||||
@@ -32,12 +33,24 @@ pub enum SecretVaultRef {
|
||||
}
|
||||
|
||||
/// Stored account reference
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Ord)]
|
||||
pub struct StoreAccountRef {
|
||||
/// Vault reference
|
||||
pub vault: SecretVaultRef,
|
||||
/// Account address
|
||||
pub address: Address,
|
||||
/// Vault reference
|
||||
pub vault: SecretVaultRef,
|
||||
}
|
||||
|
||||
impl PartialOrd for StoreAccountRef {
|
||||
fn partial_cmp(&self, other: &StoreAccountRef) -> Option<Ordering> {
|
||||
Some(self.address.cmp(&other.address).then_with(|| self.vault.cmp(&other.vault)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::borrow::Borrow<Address> for StoreAccountRef {
|
||||
fn borrow(&self) -> &Address {
|
||||
&self.address
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple Secret Store API
|
||||
|
||||
@@ -37,8 +37,8 @@ use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumT
|
||||
|
||||
const TREZOR_VID: u16 = 0x534c;
|
||||
const TREZOR_PIDS: [u16; 1] = [0x0001]; // Trezor v1, keeping this as an array to leave room for Trezor v2 which is in progress
|
||||
const ETH_DERIVATION_PATH: [u32; 4] = [0x8000002C, 0x8000003C, 0x80000000, 0]; // m/44'/60'/0'/0
|
||||
const ETC_DERIVATION_PATH: [u32; 4] = [0x8000002C, 0x8000003D, 0x80000000, 0]; // m/44'/61'/0'/0
|
||||
const ETH_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003C, 0x80000000, 0, 0]; // m/44'/60'/0'/0/0
|
||||
const ETC_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003D, 0x80000000, 0, 0]; // m/44'/61'/0'/0/0
|
||||
|
||||
|
||||
/// Hardware wallet error.
|
||||
|
||||
@@ -17,35 +17,35 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { walletSourceURL } from '~/contracts/code/wallet';
|
||||
// import { walletSourceURL } from '~/contracts/code/wallet';
|
||||
import { RadioButtons } from '~/ui';
|
||||
|
||||
const TYPES = [
|
||||
{
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id='createWallet.type.multisig.label'
|
||||
defaultMessage='Multi-Sig wallet'
|
||||
/>
|
||||
),
|
||||
key: 'MULTISIG',
|
||||
description: (
|
||||
<FormattedMessage
|
||||
id='createWallet.type.multisig.description'
|
||||
defaultMessage='Create/Deploy a {link} Wallet'
|
||||
values={ {
|
||||
link: (
|
||||
<a href={ walletSourceURL } target='_blank'>
|
||||
<FormattedMessage
|
||||
id='createWallet.type.multisig.link'
|
||||
defaultMessage='standard multi-signature'
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
} }
|
||||
/>
|
||||
)
|
||||
},
|
||||
// {
|
||||
// label: (
|
||||
// <FormattedMessage
|
||||
// id='createWallet.type.multisig.label'
|
||||
// defaultMessage='Multi-Sig wallet'
|
||||
// />
|
||||
// ),
|
||||
// key: 'MULTISIG',
|
||||
// description: (
|
||||
// <FormattedMessage
|
||||
// id='createWallet.type.multisig.description'
|
||||
// defaultMessage='Create/Deploy a {link} Wallet'
|
||||
// values={ {
|
||||
// link: (
|
||||
// <a href={ walletSourceURL } target='_blank'>
|
||||
// <FormattedMessage
|
||||
// id='createWallet.type.multisig.link'
|
||||
// defaultMessage='standard multi-signature'
|
||||
// />
|
||||
// </a>
|
||||
// )
|
||||
// } }
|
||||
// />
|
||||
// )
|
||||
// },
|
||||
{
|
||||
label: (
|
||||
<FormattedMessage
|
||||
|
||||
@@ -59,7 +59,7 @@ const STEPS = {
|
||||
export default class CreateWalletStore {
|
||||
@observable step = null;
|
||||
@observable txhash = null;
|
||||
@observable walletType = 'MULTISIG';
|
||||
@observable walletType = 'WATCH'; // 'MULTISIG';
|
||||
|
||||
@observable wallet = {
|
||||
account: '',
|
||||
|
||||
@@ -206,7 +206,7 @@ export default class CertifiersMonitor {
|
||||
// Fetch the address, name and owner in one batch
|
||||
return querier(this.api, { address: instance.address, from, limit }, instance.badge)
|
||||
.then((results) => {
|
||||
this.certifiers = results
|
||||
const certifiers = results
|
||||
.map(([ address, name, owner ], index) => ({
|
||||
address, owner,
|
||||
id: index + from,
|
||||
@@ -225,7 +225,7 @@ export default class CertifiersMonitor {
|
||||
}, {});
|
||||
|
||||
// Fetch the meta-data in serie
|
||||
return Object.values(this.certifiers).reduce((promise, certifier) => {
|
||||
return Object.values(certifiers).reduce((promise, certifier) => {
|
||||
return promise.then(() => badgeReg.fetchMeta(certifier.id))
|
||||
.then((meta) => {
|
||||
this.certifiers[certifier.id] = { ...certifier, ...meta };
|
||||
@@ -274,8 +274,6 @@ export default class CertifiersMonitor {
|
||||
.then((certified) => {
|
||||
const { id, title, icon, name } = certifier;
|
||||
|
||||
this.fetchedAccounts[address] = true;
|
||||
|
||||
if (!certified) {
|
||||
return this.store.dispatch(removeCertification(address, id));
|
||||
}
|
||||
@@ -283,7 +281,10 @@ export default class CertifiersMonitor {
|
||||
log.debug('seen as certified', { address, id, name, icon });
|
||||
this.store.dispatch(addCertification(address, id, name, title, icon));
|
||||
});
|
||||
}, Promise.resolve());
|
||||
}, Promise.resolve())
|
||||
.then(() => {
|
||||
this.fetchedAccounts[address] = true;
|
||||
});
|
||||
}
|
||||
|
||||
setCertifiersFilter () {
|
||||
|
||||
@@ -71,7 +71,6 @@ function loadCachedTokens (tokenRegContract) {
|
||||
// Check if we have data from the right contract
|
||||
if (cached.tokenreg === tokenRegContract.address && cached.tokens) {
|
||||
log.debug('found cached tokens', cached.tokens);
|
||||
dispatch(_setTokens(cached.tokens));
|
||||
|
||||
// Fetch all the tokens images on load
|
||||
// (it's the only thing that might have changed)
|
||||
@@ -105,22 +104,13 @@ export function loadTokens (options = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
export function loadTokensBasics (_tokenIndexes, options) {
|
||||
export function loadTokensBasics (tokenIndexes, options) {
|
||||
const limit = 64;
|
||||
|
||||
return (dispatch, getState) => {
|
||||
const { api, tokens } = getState();
|
||||
const { api } = getState();
|
||||
const { tokenReg } = Contracts.get();
|
||||
const nextTokens = {};
|
||||
const prevTokensIndexes = Object.values(tokens).map((t) => t.index);
|
||||
|
||||
// Only fetch tokens we don't have yet
|
||||
const tokenIndexes = _tokenIndexes
|
||||
.filter((tokenIndex) => {
|
||||
return !prevTokensIndexes.includes(tokenIndex);
|
||||
})
|
||||
.sort();
|
||||
|
||||
const count = tokenIndexes.length;
|
||||
|
||||
log.debug('loading basic tokens', tokenIndexes);
|
||||
@@ -240,6 +230,7 @@ function fetchTokensData (tokenRegContract, tokenIndexes) {
|
||||
log.debug('fetched', { fullResults, partialResults });
|
||||
|
||||
return [].concat(fullResults, partialResults)
|
||||
.filter(({ address }) => !/0x0*$/.test(address))
|
||||
.reduce((tokens, token) => {
|
||||
const { id, image, address } = token;
|
||||
|
||||
|
||||
@@ -32,14 +32,19 @@ class TokenImage extends Component {
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
state = {
|
||||
error: false
|
||||
};
|
||||
|
||||
render () {
|
||||
const { error } = this.state;
|
||||
const { api } = this.context;
|
||||
const { image, token } = this.props;
|
||||
|
||||
const imageurl = token.image || image;
|
||||
let imagesrc = unknownImage;
|
||||
|
||||
if (imageurl) {
|
||||
if (imageurl && !error) {
|
||||
const host = /^(\/)?api/.test(imageurl)
|
||||
? api.dappsUrl
|
||||
: '';
|
||||
@@ -49,11 +54,16 @@ class TokenImage extends Component {
|
||||
|
||||
return (
|
||||
<img
|
||||
src={ imagesrc }
|
||||
alt={ token.name }
|
||||
onError={ this.handleError }
|
||||
src={ imagesrc }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
handleError = () => {
|
||||
this.setState({ error: true });
|
||||
};
|
||||
}
|
||||
|
||||
function mapStateToProps (iniState) {
|
||||
|
||||
@@ -55,9 +55,14 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
|
||||
return api.eth
|
||||
.call({ data: tokenAddressesBytcode + tokenAddressesCallData })
|
||||
.then((result) => {
|
||||
const tokenAddresses = decodeArray(api, 'address[]', result);
|
||||
|
||||
return decodeArray(api, 'address[]', result);
|
||||
})
|
||||
.then((tokenAddresses) => {
|
||||
return tokenAddresses.map((tokenAddress, index) => {
|
||||
if (/^0x0*$/.test(tokenAddress)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tokenIndex = start + index;
|
||||
|
||||
return {
|
||||
@@ -68,6 +73,17 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
|
||||
fetched: false
|
||||
};
|
||||
});
|
||||
})
|
||||
.then((tokens) => tokens.filter((token) => token))
|
||||
.then((tokens) => {
|
||||
const randomAddress = sha3(`${Date.now()}`).substr(0, 42);
|
||||
|
||||
return fetchTokensBalances(api, tokens, [randomAddress])
|
||||
.then((_balances) => {
|
||||
const balances = _balances[randomAddress];
|
||||
|
||||
return tokens.filter(({ id }) => balances[id].eq(0));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,12 @@ pub struct AuthorityRoundParams {
|
||||
/// Reward per block in wei.
|
||||
#[serde(rename="blockReward")]
|
||||
pub block_reward: Option<Uint>,
|
||||
/// Block at which maximum uncle count should be considered.
|
||||
#[serde(rename="maximumUncleCountTransition")]
|
||||
pub maximum_uncle_count_transition: Option<Uint>,
|
||||
/// Maximum number of accepted uncles.
|
||||
#[serde(rename="maximumUncleCount")]
|
||||
pub maximum_uncle_count: Option<Uint>,
|
||||
}
|
||||
|
||||
/// Authority engine deserialization.
|
||||
@@ -71,7 +77,9 @@ mod tests {
|
||||
},
|
||||
"startStep" : 24,
|
||||
"validateStepTransition": 150,
|
||||
"blockReward": 5000000
|
||||
"blockReward": 5000000,
|
||||
"maximumUncleCountTransition": 10000000,
|
||||
"maximumUncleCount": 5
|
||||
}
|
||||
}"#;
|
||||
|
||||
@@ -80,6 +88,8 @@ mod tests {
|
||||
assert_eq!(deserialized.params.validators, ValidatorSet::List(vec![Address(H160::from("0xc6d9d2cd449a754c494264e1809c50e34d64562b"))]));
|
||||
assert_eq!(deserialized.params.start_step, Some(Uint(U256::from(24))));
|
||||
assert_eq!(deserialized.params.immediate_transitions, None);
|
||||
assert_eq!(deserialized.params.maximum_uncle_count_transition, Some(Uint(10_000_000.into())));
|
||||
assert_eq!(deserialized.params.maximum_uncle_count, Some(Uint(5.into())));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ pub struct Params {
|
||||
#[serde(rename="eip155Transition")]
|
||||
pub eip155_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="validateChainIdTransition")]
|
||||
pub validate_chain_id_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="validateReceiptsTransition")]
|
||||
pub validate_receipts_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
|
||||
@@ -462,7 +462,7 @@
|
||||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>1.8.0</string>
|
||||
<string>1.8.5</string>
|
||||
</dict>
|
||||
<key>UUID</key>
|
||||
<string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string>
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
|
||||
!define VERSIONMAJOR 1
|
||||
!define VERSIONMINOR 8
|
||||
!define VERSIONBUILD 0
|
||||
!define ARGS "--warp"
|
||||
!define FIRST_START_ARGS "ui --warp --mode=passive"
|
||||
!define VERSIONBUILD 5
|
||||
!define ARGS ""
|
||||
!define FIRST_START_ARGS "--mode=passive ui"
|
||||
|
||||
!addplugindir .\
|
||||
|
||||
|
||||
BIN
nsis/logo.ico
BIN
nsis/logo.ico
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 114 KiB |
@@ -24,6 +24,7 @@ usage! {
|
||||
// Subcommands must start with cmd_ and have '_' in place of '-'
|
||||
// Sub-subcommands must start with the name of the subcommand
|
||||
// Arguments must start with arg_
|
||||
// Flags must start with flag_
|
||||
|
||||
CMD cmd_ui {
|
||||
"Manage ui",
|
||||
@@ -53,10 +54,6 @@ usage! {
|
||||
|
||||
CMD cmd_account_new {
|
||||
"Create a new acount",
|
||||
|
||||
ARG arg_account_new_password: (Option<String>) = None,
|
||||
"--password=[FILE]",
|
||||
"Path to the password file",
|
||||
}
|
||||
|
||||
CMD cmd_account_list {
|
||||
@@ -81,10 +78,6 @@ usage! {
|
||||
{
|
||||
"Import wallet",
|
||||
|
||||
ARG arg_wallet_import_password: (Option<String>) = None,
|
||||
"--password=[FILE]",
|
||||
"Path to the password file",
|
||||
|
||||
ARG arg_wallet_import_path: (Option<String>) = None,
|
||||
"<PATH>",
|
||||
"Path to the wallet",
|
||||
@@ -179,10 +172,6 @@ usage! {
|
||||
{
|
||||
"Sign",
|
||||
|
||||
ARG arg_signer_sign_password: (Option<String>) = None,
|
||||
"--password=[FILE]",
|
||||
"Path to the password file",
|
||||
|
||||
ARG arg_signer_sign_id: (Option<usize>) = None,
|
||||
"[ID]",
|
||||
"ID",
|
||||
@@ -244,7 +233,7 @@ usage! {
|
||||
}
|
||||
}
|
||||
{
|
||||
// Flags and arguments
|
||||
// Global flags and arguments
|
||||
["Operating Options"]
|
||||
FLAG flag_public_node: (bool) = false, or |c: &Config| otry!(c.parity).public_node.clone(),
|
||||
"--public-node",
|
||||
@@ -353,7 +342,6 @@ usage! {
|
||||
ARG arg_password: (Vec<String>) = Vec::new(), or |c: &Config| otry!(c.account).password.clone(),
|
||||
"--password=[FILE]...",
|
||||
"Provide a file containing a password for unlocking an account. Leading and trailing whitespace is trimmed.",
|
||||
|
||||
["UI options"]
|
||||
FLAG flag_force_ui: (bool) = false, or |c: &Config| otry!(c.ui).force.clone(),
|
||||
"--force-ui",
|
||||
@@ -836,6 +824,10 @@ usage! {
|
||||
"Target size of the whisper message pool in megabytes.",
|
||||
|
||||
["Legacy options"]
|
||||
FLAG flag_warp: (bool) = false, or |_| None,
|
||||
"--warp",
|
||||
"Does nothing; warp sync is enabled by default.",
|
||||
|
||||
FLAG flag_dapps_apis_all: (bool) = false, or |_| None,
|
||||
"--dapps-apis-all",
|
||||
"Dapps server is merged with RPC server. Use --jsonrpc-apis.",
|
||||
@@ -1203,6 +1195,39 @@ mod tests {
|
||||
use toml;
|
||||
use clap::{ErrorKind as ClapErrorKind};
|
||||
|
||||
#[test]
|
||||
fn should_accept_any_argument_order() {
|
||||
let args = Args::parse(&["parity", "--no-warp", "account", "list"]).unwrap();
|
||||
assert_eq!(args.flag_no_warp, true);
|
||||
|
||||
let args = Args::parse(&["parity", "account", "list", "--no-warp"]).unwrap();
|
||||
assert_eq!(args.flag_no_warp, true);
|
||||
|
||||
let args = Args::parse(&["parity", "--chain=dev", "account", "list"]).unwrap();
|
||||
assert_eq!(args.arg_chain, "dev");
|
||||
|
||||
let args = Args::parse(&["parity", "account", "list", "--chain=dev"]).unwrap();
|
||||
assert_eq!(args.arg_chain, "dev");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_crash_on_warp() {
|
||||
let args = Args::parse(&["parity", "--warp"]);
|
||||
assert!(args.is_ok());
|
||||
|
||||
let args = Args::parse(&["parity", "account", "list", "--warp"]);
|
||||
assert!(args.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_reject_invalid_values() {
|
||||
let args = Args::parse(&["parity", "--cache=20"]);
|
||||
assert!(args.is_ok());
|
||||
|
||||
let args = Args::parse(&["parity", "--cache=asd"]);
|
||||
assert!(args.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_args_and_flags() {
|
||||
let args = Args::parse(&["parity", "--no-warp"]).unwrap();
|
||||
@@ -1365,9 +1390,6 @@ mod tests {
|
||||
arg_restore_file: None,
|
||||
arg_tools_hash_file: None,
|
||||
|
||||
arg_account_new_password: None,
|
||||
arg_signer_sign_password: None,
|
||||
arg_wallet_import_password: None,
|
||||
arg_signer_sign_id: None,
|
||||
arg_signer_reject_id: None,
|
||||
arg_dapp_path: None,
|
||||
@@ -1549,6 +1571,7 @@ mod tests {
|
||||
arg_whisper_pool_size: 20,
|
||||
|
||||
// -- Legacy Options
|
||||
flag_warp: false,
|
||||
flag_geth: false,
|
||||
flag_testnet: false,
|
||||
flag_import_geth_keys: false,
|
||||
|
||||
@@ -32,6 +32,20 @@ macro_rules! otry {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! return_if_parse_error {
|
||||
($e:expr) => (
|
||||
match $e {
|
||||
Err(clap_error @ ClapError { kind: ClapErrorKind::ValueValidation, .. }) => {
|
||||
return Err(clap_error);
|
||||
},
|
||||
|
||||
// Otherwise, if $e is ClapErrorKind::ArgumentNotFound or Ok(),
|
||||
// then convert to Option
|
||||
_ => $e.ok()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! if_option {
|
||||
(Option<$type:ty>, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
|
||||
$($then)*
|
||||
@@ -139,7 +153,7 @@ macro_rules! usage {
|
||||
use std::{fs, io, process};
|
||||
use std::io::{Read, Write};
|
||||
use util::version;
|
||||
use clap::{Arg, App, SubCommand, AppSettings, Error as ClapError};
|
||||
use clap::{Arg, App, SubCommand, AppSettings, ArgMatches as ClapArgMatches, Error as ClapError, ErrorKind as ClapErrorKind};
|
||||
use helpers::replace_home;
|
||||
use std::ffi::OsStr;
|
||||
use std::collections::HashMap;
|
||||
@@ -489,6 +503,36 @@ macro_rules! usage {
|
||||
args
|
||||
}
|
||||
|
||||
pub fn hydrate_with_globals(self: &mut Self, matches: &ClapArgMatches) -> Result<(), ClapError> {
|
||||
$(
|
||||
$(
|
||||
self.$flag = self.$flag || matches.is_present(stringify!($flag));
|
||||
)*
|
||||
$(
|
||||
if let some @ Some(_) = return_if_parse_error!(if_option!(
|
||||
$($arg_type_tt)+,
|
||||
THEN {
|
||||
if_option_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_option_vec_type!($($arg_type_tt)+)) }
|
||||
ELSE { value_t!(matches, stringify!($arg), inner_option_type!($($arg_type_tt)+)) }
|
||||
)
|
||||
}
|
||||
ELSE {
|
||||
if_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_vec_type!($($arg_type_tt)+)) }
|
||||
ELSE { value_t!(matches, stringify!($arg), $($arg_type_tt)+) }
|
||||
)
|
||||
}
|
||||
)) {
|
||||
self.$arg = some;
|
||||
}
|
||||
)*
|
||||
)*
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // the submatches of arg-less subcommands aren't used
|
||||
pub fn parse<S: AsRef<str>>(command: &[S]) -> Result<Self, ClapError> {
|
||||
|
||||
@@ -545,12 +589,14 @@ macro_rules! usage {
|
||||
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc)[4..]))
|
||||
.about($subc_help)
|
||||
.args(&subc_usages.get(stringify!($subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
|
||||
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>()) // accept global arguments at this position
|
||||
$(
|
||||
.setting(AppSettings::SubcommandRequired) // prevent from running `parity account`
|
||||
.subcommand(
|
||||
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]))
|
||||
.about($subc_subc_help)
|
||||
.args(&subc_usages.get(stringify!($subc_subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
|
||||
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>()) // accept global arguments at this position
|
||||
)
|
||||
)*
|
||||
)
|
||||
@@ -558,89 +604,70 @@ macro_rules! usage {
|
||||
.get_matches_from_safe(command.iter().map(|x| OsStr::new(x.as_ref())))?;
|
||||
|
||||
let mut raw_args : RawArgs = Default::default();
|
||||
$(
|
||||
$(
|
||||
raw_args.$flag = matches.is_present(stringify!($flag));
|
||||
)*
|
||||
$(
|
||||
raw_args.$arg = if_option!(
|
||||
$($arg_type_tt)+,
|
||||
THEN {
|
||||
if_option_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_option_vec_type!($($arg_type_tt)+)).ok() }
|
||||
ELSE { value_t!(matches, stringify!($arg), inner_option_type!($($arg_type_tt)+)).ok() }
|
||||
)
|
||||
}
|
||||
ELSE {
|
||||
if_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_vec_type!($($arg_type_tt)+)).ok() }
|
||||
ELSE { value_t!(matches, stringify!($arg), $($arg_type_tt)+).ok() }
|
||||
)
|
||||
}
|
||||
);
|
||||
)*
|
||||
)*
|
||||
|
||||
raw_args.hydrate_with_globals(&matches)?;
|
||||
|
||||
// Subcommands
|
||||
$(
|
||||
if let Some(submatches) = matches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc)[4..])) {
|
||||
raw_args.$subc = true;
|
||||
|
||||
// Globals
|
||||
raw_args.hydrate_with_globals(&submatches)?;
|
||||
// Subcommand flags
|
||||
$(
|
||||
raw_args.$subc_flag = submatches.is_present(&stringify!($subc_flag));
|
||||
)*
|
||||
// Subcommand arguments
|
||||
$(
|
||||
raw_args.$subc_arg = if_option!(
|
||||
raw_args.$subc_arg = return_if_parse_error!(if_option!(
|
||||
$($subc_arg_type_tt)+,
|
||||
THEN {
|
||||
if_option_vec!(
|
||||
$($subc_arg_type_tt)+,
|
||||
THEN { values_t!(submatches, stringify!($subc_arg), inner_option_vec_type!($($subc_arg_type_tt)+)).ok() }
|
||||
ELSE { value_t!(submatches, stringify!($subc_arg), inner_option_type!($($subc_arg_type_tt)+)).ok() }
|
||||
THEN { values_t!(submatches, stringify!($subc_arg), inner_option_vec_type!($($subc_arg_type_tt)+)) }
|
||||
ELSE { value_t!(submatches, stringify!($subc_arg), inner_option_type!($($subc_arg_type_tt)+)) }
|
||||
)
|
||||
}
|
||||
ELSE {
|
||||
if_vec!(
|
||||
$($subc_arg_type_tt)+,
|
||||
THEN { values_t!(submatches, stringify!($subc_arg), inner_vec_type!($($subc_arg_type_tt)+)).ok() }
|
||||
ELSE { value_t!(submatches, stringify!($subc_arg), $($subc_arg_type_tt)+).ok() }
|
||||
THEN { values_t!(submatches, stringify!($subc_arg), inner_vec_type!($($subc_arg_type_tt)+)) }
|
||||
ELSE { value_t!(submatches, stringify!($subc_arg), $($subc_arg_type_tt)+) }
|
||||
)
|
||||
}
|
||||
);
|
||||
));
|
||||
)*
|
||||
|
||||
// Sub-subcommands
|
||||
$(
|
||||
if let Some(subsubmatches) = submatches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])) {
|
||||
raw_args.$subc_subc = true;
|
||||
|
||||
// Globals
|
||||
raw_args.hydrate_with_globals(&subsubmatches)?;
|
||||
// Sub-subcommand flags
|
||||
$(
|
||||
raw_args.$subc_subc_flag = subsubmatches.is_present(&stringify!($subc_subc_flag));
|
||||
)*
|
||||
// Sub-subcommand arguments
|
||||
$(
|
||||
raw_args.$subc_subc_arg = if_option!(
|
||||
raw_args.$subc_subc_arg = return_if_parse_error!(if_option!(
|
||||
$($subc_subc_arg_type_tt)+,
|
||||
THEN {
|
||||
if_option_vec!(
|
||||
$($subc_subc_arg_type_tt)+,
|
||||
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_vec_type!($($subc_subc_arg_type_tt)+)).ok() }
|
||||
ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_type!($($subc_subc_arg_type_tt)+)).ok() }
|
||||
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_vec_type!($($subc_subc_arg_type_tt)+)) }
|
||||
ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_type!($($subc_subc_arg_type_tt)+)) }
|
||||
)
|
||||
}
|
||||
ELSE {
|
||||
if_vec!(
|
||||
$($subc_subc_arg_type_tt)+,
|
||||
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_vec_type!($($subc_subc_arg_type_tt)+)).ok() }
|
||||
ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), $($subc_subc_arg_type_tt)+).ok() }
|
||||
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_vec_type!($($subc_subc_arg_type_tt)+)) }
|
||||
ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), $($subc_subc_arg_type_tt)+) }
|
||||
)
|
||||
}
|
||||
);
|
||||
));
|
||||
)*
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -40,7 +40,7 @@ use parity_rpc::NetworkSettings;
|
||||
use cache::CacheConfig;
|
||||
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home, replace_home_and_local,
|
||||
geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy};
|
||||
use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras};
|
||||
use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType};
|
||||
use ethcore_logger::Config as LogConfig;
|
||||
use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path};
|
||||
use dapps::Configuration as DappsConfiguration;
|
||||
@@ -109,7 +109,7 @@ impl Configuration {
|
||||
let pruning = self.args.arg_pruning.parse()?;
|
||||
let pruning_history = self.args.arg_pruning_history;
|
||||
let vm_type = self.vm_type()?;
|
||||
let spec = self.chain().parse()?;
|
||||
let spec = self.chain()?;
|
||||
let mode = match self.args.arg_mode.as_ref() {
|
||||
"last" => None,
|
||||
mode => Some(to_mode(&mode, self.args.arg_mode_timeout, self.args.arg_mode_alarm)?),
|
||||
@@ -143,7 +143,7 @@ impl Configuration {
|
||||
if self.args.cmd_signer_new_token {
|
||||
Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone())
|
||||
} else if self.args.cmd_signer_sign {
|
||||
let pwfile = self.args.arg_signer_sign_password.map(|pwfile| {
|
||||
let pwfile = self.args.arg_password.first().map(|pwfile| {
|
||||
PathBuf::from(pwfile)
|
||||
});
|
||||
Cmd::SignerSign {
|
||||
@@ -180,7 +180,7 @@ impl Configuration {
|
||||
iterations: self.args.arg_keys_iterations,
|
||||
path: dirs.keys,
|
||||
spec: spec,
|
||||
password_file: self.args.arg_account_new_password.clone(),
|
||||
password_file: self.args.arg_password.first().map(|x| x.to_owned()),
|
||||
};
|
||||
AccountCmd::New(new_acc)
|
||||
} else if self.args.cmd_account_list {
|
||||
@@ -215,7 +215,7 @@ impl Configuration {
|
||||
path: dirs.keys,
|
||||
spec: spec,
|
||||
wallet_path: self.args.arg_wallet_import_path.unwrap().clone(),
|
||||
password_file: self.args.arg_wallet_import_password,
|
||||
password_file: self.args.arg_password.first().map(|x| x.to_owned()),
|
||||
};
|
||||
Cmd::ImportPresaleWallet(presale_cmd)
|
||||
} else if self.args.cmd_import {
|
||||
@@ -336,7 +336,7 @@ impl Configuration {
|
||||
pruning_memory: self.args.arg_pruning_memory,
|
||||
daemon: daemon,
|
||||
logger_config: logger_config.clone(),
|
||||
miner_options: self.miner_options(self.args.arg_reseal_min_period)?,
|
||||
miner_options: self.miner_options()?,
|
||||
ntp_servers: self.ntp_servers(),
|
||||
ws_conf: ws_conf,
|
||||
http_conf: http_conf,
|
||||
@@ -441,15 +441,16 @@ impl Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
fn chain(&self) -> String {
|
||||
if let Some(ref s) = self.spec_name_override {
|
||||
fn chain(&self) -> Result<SpecType, String> {
|
||||
let name = if let Some(ref s) = self.spec_name_override {
|
||||
s.clone()
|
||||
}
|
||||
else if self.args.flag_testnet {
|
||||
} else if self.args.flag_testnet {
|
||||
"testnet".to_owned()
|
||||
} else {
|
||||
self.args.arg_chain.clone()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(name.parse()?)
|
||||
}
|
||||
|
||||
fn max_peers(&self) -> u32 {
|
||||
@@ -504,8 +505,9 @@ impl Configuration {
|
||||
} else { Ok(None) }
|
||||
}
|
||||
|
||||
fn miner_options(&self, reseal_min_period: u64) -> Result<MinerOptions, String> {
|
||||
if self.args.flag_force_sealing && reseal_min_period == 0 {
|
||||
fn miner_options(&self) -> Result<MinerOptions, String> {
|
||||
let is_dev_chain = self.chain()? == SpecType::Dev;
|
||||
if is_dev_chain && self.args.flag_force_sealing && self.args.arg_reseal_min_period == 0 {
|
||||
return Err("Force sealing can't be used with reseal_min_period = 0".into());
|
||||
}
|
||||
|
||||
@@ -528,7 +530,7 @@ impl Configuration {
|
||||
tx_queue_gas_limit: to_gas_limit(&self.args.arg_tx_queue_gas)?,
|
||||
tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?,
|
||||
pending_set: to_pending_set(&self.args.arg_relay_set)?,
|
||||
reseal_min_period: Duration::from_millis(reseal_min_period),
|
||||
reseal_min_period: Duration::from_millis(self.args.arg_reseal_min_period),
|
||||
reseal_max_period: Duration::from_millis(self.args.arg_reseal_max_period),
|
||||
work_queue_size: self.args.arg_work_queue_size,
|
||||
enable_resubmission: !self.args.flag_remove_solved,
|
||||
@@ -762,7 +764,8 @@ impl Configuration {
|
||||
}
|
||||
|
||||
fn cors(cors: Option<&String>) -> Option<Vec<String>> {
|
||||
cors.map(|ref c| c.split(',').map(Into::into).collect())
|
||||
// Never return `None` here (enables CORS for all hosts).
|
||||
Some(cors.map(|ref c| c.split(',').map(Into::into).collect()).unwrap_or_default())
|
||||
}
|
||||
|
||||
fn rpc_cors(&self) -> Option<Vec<String>> {
|
||||
@@ -883,7 +886,7 @@ impl Configuration {
|
||||
let net_addresses = self.net_addresses()?;
|
||||
Ok(NetworkSettings {
|
||||
name: self.args.arg_identity.clone(),
|
||||
chain: self.chain(),
|
||||
chain: format!("{}", self.chain()?),
|
||||
network_port: net_addresses.0.port(),
|
||||
rpc_enabled: http_conf.enabled,
|
||||
rpc_interface: http_conf.interface,
|
||||
@@ -914,8 +917,6 @@ impl Configuration {
|
||||
}
|
||||
|
||||
fn directories(&self) -> Directories {
|
||||
use path;
|
||||
|
||||
let local_path = default_local_path();
|
||||
let base_path = self.args.arg_base_path.as_ref().or_else(|| self.args.arg_datadir.as_ref()).map_or_else(|| default_data_path(), |s| s.clone());
|
||||
let data_path = replace_home("", &base_path);
|
||||
@@ -935,21 +936,6 @@ impl Configuration {
|
||||
let secretstore_path = replace_home(&data_path, &self.args.arg_secretstore_path);
|
||||
let ui_path = replace_home(&data_path, &self.args.arg_ui_path);
|
||||
|
||||
if self.args.flag_geth && !cfg!(windows) {
|
||||
let geth_root = if self.chain() == "testnet".to_owned() { path::ethereum::test() } else { path::ethereum::default() };
|
||||
::std::fs::create_dir_all(geth_root.as_path()).unwrap_or_else(
|
||||
|e| warn!("Failed to create '{}' for geth mode: {}", &geth_root.to_str().unwrap(), e));
|
||||
}
|
||||
|
||||
if cfg!(feature = "ipc") && !cfg!(feature = "windows") {
|
||||
let mut path_buf = PathBuf::from(data_path.clone());
|
||||
path_buf.push("ipc");
|
||||
let ipc_path = path_buf.to_str().unwrap();
|
||||
::std::fs::create_dir_all(ipc_path).unwrap_or_else(
|
||||
|e| warn!("Failed to directory '{}' for ipc sockets: {}", ipc_path, e)
|
||||
);
|
||||
}
|
||||
|
||||
Directories {
|
||||
keys: keys_path,
|
||||
base: data_path,
|
||||
@@ -1401,21 +1387,20 @@ mod tests {
|
||||
let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]);
|
||||
|
||||
// then
|
||||
let min_period = conf0.args.arg_reseal_min_period;
|
||||
assert_eq!(conf0.miner_options(min_period).unwrap(), mining_options);
|
||||
assert_eq!(conf0.miner_options().unwrap(), mining_options);
|
||||
mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice;
|
||||
assert_eq!(conf1.miner_options(min_period).unwrap(), mining_options);
|
||||
assert_eq!(conf1.miner_options().unwrap(), mining_options);
|
||||
mining_options.tx_queue_strategy = PrioritizationStrategy::GasPriceOnly;
|
||||
assert_eq!(conf2.miner_options(min_period).unwrap(), mining_options);
|
||||
assert_eq!(conf2.miner_options().unwrap(), mining_options);
|
||||
mining_options.tx_queue_strategy = PrioritizationStrategy::GasAndGasPrice;
|
||||
assert_eq!(conf3.miner_options(min_period).unwrap(), mining_options);
|
||||
assert_eq!(conf3.miner_options().unwrap(), mining_options);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_fail_on_force_reseal_and_reseal_min_period() {
|
||||
let conf = parse(&["parity", "--chain", "dev", "--force-sealing"]);
|
||||
let conf = parse(&["parity", "--chain", "dev", "--force-sealing", "--reseal-min-period", "0"]);
|
||||
|
||||
assert!(conf.miner_options(0).is_err());
|
||||
assert!(conf.miner_options().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1443,7 +1428,7 @@ mod tests {
|
||||
// then
|
||||
assert_eq!(conf.network_settings(), Ok(NetworkSettings {
|
||||
name: "testname".to_owned(),
|
||||
chain: "testnet".to_owned(),
|
||||
chain: "kovan".to_owned(),
|
||||
network_port: 30303,
|
||||
rpc_enabled: true,
|
||||
rpc_interface: "127.0.0.1".to_owned(),
|
||||
@@ -1526,7 +1511,7 @@ mod tests {
|
||||
let conf2 = parse(&["parity", "--ipfs-api-cors", "http://parity.io,http://something.io"]);
|
||||
|
||||
// then
|
||||
assert_eq!(conf0.ipfs_cors(), None);
|
||||
assert_eq!(conf0.ipfs_cors(), Some(vec![]));
|
||||
assert_eq!(conf1.ipfs_cors(), Some(vec!["*".into()]));
|
||||
assert_eq!(conf2.ipfs_cors(), Some(vec!["http://parity.io".into(),"http://something.io".into()]));
|
||||
}
|
||||
|
||||
@@ -195,9 +195,7 @@ mod server {
|
||||
|
||||
pub struct Middleware;
|
||||
impl RequestMiddleware for Middleware {
|
||||
fn on_request(
|
||||
&self, _req: &hyper::server::Request<hyper::net::HttpStream>, _control: &hyper::Control
|
||||
) -> RequestMiddlewareAction {
|
||||
fn on_request(&self, _req: hyper::Request) -> RequestMiddlewareAction {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ impl fmt::Display for Deprecated {
|
||||
pub fn find_deprecated(args: &Args) -> Vec<Deprecated> {
|
||||
let mut result = vec![];
|
||||
|
||||
if args.flag_warp {
|
||||
result.push(Deprecated::DoesNothing("--warp"));
|
||||
}
|
||||
|
||||
if args.flag_jsonrpc {
|
||||
result.push(Deprecated::DoesNothing("--jsonrpc"));
|
||||
}
|
||||
@@ -117,6 +121,7 @@ mod tests {
|
||||
assert_eq!(find_deprecated(&Args::default()), vec![]);
|
||||
assert_eq!(find_deprecated(&{
|
||||
let mut args = Args::default();
|
||||
args.flag_warp = true;
|
||||
args.flag_jsonrpc = true;
|
||||
args.flag_rpc = true;
|
||||
args.flag_jsonrpc_off = true;
|
||||
@@ -135,6 +140,7 @@ mod tests {
|
||||
args.flag_dapps_apis_all = true;
|
||||
args
|
||||
}), vec![
|
||||
Deprecated::DoesNothing("--warp"),
|
||||
Deprecated::DoesNothing("--jsonrpc"),
|
||||
Deprecated::DoesNothing("--rpc"),
|
||||
Deprecated::Replaced("--jsonrpc-off", "--no-jsonrpc"),
|
||||
|
||||
@@ -34,8 +34,8 @@ impl Default for Configuration {
|
||||
enabled: false,
|
||||
port: 5001,
|
||||
interface: "127.0.0.1".into(),
|
||||
cors: None,
|
||||
hosts: Some(Vec::new()),
|
||||
cors: Some(vec![]),
|
||||
hosts: Some(vec![]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ impl Default for HttpConfiguration {
|
||||
interface: "127.0.0.1".into(),
|
||||
port: 8545,
|
||||
apis: ApiSet::UnsafeContext,
|
||||
cors: None,
|
||||
hosts: Some(Vec::new()),
|
||||
cors: Some(vec![]),
|
||||
hosts: Some(vec![]),
|
||||
server_threads: 1,
|
||||
processing_threads: 0,
|
||||
}
|
||||
@@ -98,7 +98,7 @@ impl From<UiConfiguration> for HttpConfiguration {
|
||||
interface: conf.interface,
|
||||
port: conf.port,
|
||||
apis: rpc_apis::ApiSet::UnsafeContext,
|
||||
cors: None,
|
||||
cors: Some(vec![]),
|
||||
hosts: conf.hosts,
|
||||
server_threads: 1,
|
||||
processing_threads: 0,
|
||||
@@ -301,6 +301,16 @@ pub fn new_ipc<D: rpc_apis::Dependencies>(
|
||||
|
||||
let handler = setup_apis(conf.apis, dependencies);
|
||||
let remote = dependencies.remote.clone();
|
||||
let path = PathBuf::from(&conf.socket_addr);
|
||||
// Make sure socket file can be created on unix-like OS.
|
||||
// Windows pipe paths are not on the FS.
|
||||
if !cfg!(windows) {
|
||||
if let Some(dir) = path.parent() {
|
||||
::std::fs::create_dir_all(&dir)
|
||||
.map_err(|err| format!("Unable to create IPC directory at {}: {}", dir.display(), err))?;
|
||||
}
|
||||
}
|
||||
|
||||
match rpc::start_ipc(&conf.socket_addr, handler, remote, rpc::RpcExtractor) {
|
||||
Ok(server) => Ok(Some(server)),
|
||||
Err(io_error) => Err(format!("IPC error: {}", io_error)),
|
||||
|
||||
@@ -71,6 +71,9 @@ pub trait Dispatcher: Send + Sync + Clone {
|
||||
fn sign(&self, accounts: Arc<AccountProvider>, filled: FilledTransactionRequest, password: SignWith)
|
||||
-> BoxFuture<WithToken<SignedTransaction>, Error>;
|
||||
|
||||
/// Converts a `SignedTransaction` into `RichRawTransaction`
|
||||
fn enrich(&self, SignedTransaction) -> RpcRichRawTransaction;
|
||||
|
||||
/// "Dispatch" a local transaction.
|
||||
fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error>;
|
||||
}
|
||||
@@ -163,6 +166,11 @@ impl<C: MiningBlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C
|
||||
}))
|
||||
}
|
||||
|
||||
fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction {
|
||||
let block_number = self.client.best_block_header().number();
|
||||
RpcRichRawTransaction::from_signed(signed_transaction, block_number, self.client.eip86_transition())
|
||||
}
|
||||
|
||||
fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error> {
|
||||
let hash = signed_transaction.transaction.hash();
|
||||
|
||||
@@ -261,11 +269,11 @@ impl LightDispatcher {
|
||||
transaction_queue: Arc<RwLock<LightTransactionQueue>>,
|
||||
) -> Self {
|
||||
LightDispatcher {
|
||||
sync: sync,
|
||||
client: client,
|
||||
on_demand: on_demand,
|
||||
cache: cache,
|
||||
transaction_queue: transaction_queue,
|
||||
sync,
|
||||
client,
|
||||
on_demand,
|
||||
cache,
|
||||
transaction_queue,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,6 +407,11 @@ impl Dispatcher for LightDispatcher {
|
||||
.and_then(move |nonce| with_nonce(filled, nonce)))
|
||||
}
|
||||
|
||||
fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction {
|
||||
let block_number = self.client.best_block_header().number();
|
||||
RpcRichRawTransaction::from_signed(signed_transaction, block_number, self.client.eip86_transition())
|
||||
}
|
||||
|
||||
fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error> {
|
||||
let hash = signed_transaction.transaction.hash();
|
||||
|
||||
@@ -510,8 +523,8 @@ pub fn execute<D: Dispatcher + 'static>(
|
||||
},
|
||||
ConfirmationPayload::SignTransaction(request) => {
|
||||
Box::new(dispatcher.sign(accounts, request, pass)
|
||||
.map(|result| result
|
||||
.map(RpcRichRawTransaction::from)
|
||||
.map(move |result| result
|
||||
.map(move |tx| dispatcher.enrich(tx))
|
||||
.map(ConfirmationResponse::SignTransaction)
|
||||
))
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@ use ethcore::encoded;
|
||||
use ethcore::executed::{Executed, ExecutionError};
|
||||
use ethcore::ids::BlockId;
|
||||
use ethcore::filter::Filter as EthcoreFilter;
|
||||
use ethcore::transaction::{Action, Transaction as EthTransaction, SignedTransaction};
|
||||
use ethcore::transaction::{Action, Transaction as EthTransaction, SignedTransaction, LocalizedTransaction};
|
||||
use ethcore::receipt::Receipt;
|
||||
|
||||
use jsonrpc_core::{BoxFuture, Error};
|
||||
@@ -65,13 +65,24 @@ pub struct LightFetch {
|
||||
/// Extract a transaction at given index.
|
||||
pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_transition: u64) -> Option<Transaction> {
|
||||
block.transactions().into_iter().nth(index)
|
||||
// Verify if transaction signature is correct.
|
||||
.and_then(|tx| SignedTransaction::new(tx).ok())
|
||||
.map(|tx| Transaction::from_signed(tx, block.number(), eip86_transition))
|
||||
.map(|mut tx| {
|
||||
tx.block_hash = Some(block.hash().into());
|
||||
tx.transaction_index = Some(index.into());
|
||||
tx
|
||||
.map(|signed_tx| {
|
||||
let (signed, sender, _) = signed_tx.deconstruct();
|
||||
let block_hash = block.hash();
|
||||
let block_number = block.number();
|
||||
let transaction_index = index;
|
||||
let cached_sender = Some(sender);
|
||||
|
||||
LocalizedTransaction {
|
||||
signed,
|
||||
block_number,
|
||||
block_hash,
|
||||
transaction_index,
|
||||
cached_sender,
|
||||
}
|
||||
})
|
||||
.map(|tx| Transaction::from_localized(tx, eip86_transition))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,8 +73,8 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
||||
SignerClient {
|
||||
signer: signer.clone(),
|
||||
accounts: store.clone(),
|
||||
dispatcher: dispatcher,
|
||||
subscribers: subscribers,
|
||||
dispatcher,
|
||||
subscribers,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,8 @@ impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
|
||||
},
|
||||
ConfirmationPayload::SignTransaction(request) => {
|
||||
Self::verify_transaction(bytes, request, |pending_transaction| {
|
||||
Ok(ConfirmationResponse::SignTransaction(pending_transaction.transaction.into()))
|
||||
let rich = self.dispatcher.enrich(pending_transaction.transaction);
|
||||
Ok(ConfirmationResponse::SignTransaction(rich))
|
||||
})
|
||||
},
|
||||
ConfirmationPayload::EthSignMessage(address, data) => {
|
||||
|
||||
@@ -547,7 +547,7 @@ fn rpc_eth_pending_transaction_by_hash() {
|
||||
tester.miner.pending_transactions.lock().insert(H256::zero(), tx);
|
||||
}
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":"0x0","chainId":null,"condition":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","standardV":"0x0","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":"0x1b","value":"0xa"},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","standardV":"0x0","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":"0x1b","value":"0xa"},"id":1}"#;
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getTransactionByHash",
|
||||
@@ -863,7 +863,7 @@ fn rpc_eth_sign_transaction() {
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||
r#""tx":{"# +
|
||||
r#""blockHash":null,"blockNumber":"0x0","# +
|
||||
r#""blockHash":null,"blockNumber":null,"# +
|
||||
&format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""condition":null,"creates":null,"# +
|
||||
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||
|
||||
@@ -234,7 +234,7 @@ fn rpc_parity_remove_transaction() {
|
||||
let hash = signed.hash();
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "parity_removeTransaction", "params":[""#.to_owned() + &format!("0x{:?}", hash) + r#""], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":"0x0","chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#;
|
||||
|
||||
miner.pending_transactions.lock().insert(hash, signed);
|
||||
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));
|
||||
|
||||
@@ -456,7 +456,7 @@ fn should_confirm_sign_transaction_with_rlp() {
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||
r#""tx":{"# +
|
||||
r#""blockHash":null,"blockNumber":"0x0","# +
|
||||
r#""blockHash":null,"blockNumber":null,"# +
|
||||
&format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""condition":null,"creates":null,"# +
|
||||
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||
|
||||
@@ -25,7 +25,7 @@ use v1::impls::SigningQueueClient;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::{EthSigning, ParitySigning, Parity};
|
||||
use v1::helpers::{SignerService, SigningQueue, FullDispatcher};
|
||||
use v1::types::ConfirmationResponse;
|
||||
use v1::types::{ConfirmationResponse, RichRawTransaction};
|
||||
use v1::tests::helpers::TestMinerService;
|
||||
use v1::tests::mocked::parity;
|
||||
|
||||
@@ -299,7 +299,7 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||
r#""tx":{"# +
|
||||
r#""blockHash":null,"blockNumber":"0x0","# +
|
||||
r#""blockHash":null,"blockNumber":null,"# +
|
||||
&format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""condition":null,"creates":null,"# +
|
||||
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||
@@ -326,7 +326,9 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
::std::thread::spawn(move || loop {
|
||||
if signer.requests().len() == 1 {
|
||||
// respond
|
||||
signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction(t.into())));
|
||||
signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction(
|
||||
RichRawTransaction::from_signed(t.into(), 0x0, u64::max_value())
|
||||
)));
|
||||
break
|
||||
}
|
||||
::std::thread::sleep(Duration::from_millis(100))
|
||||
|
||||
@@ -173,8 +173,10 @@ impl<'a> From<&'a EthHeader> for Header {
|
||||
logs_bloom: h.log_bloom().into(),
|
||||
timestamp: h.timestamp().into(),
|
||||
difficulty: h.difficulty().into(),
|
||||
seal_fields: h.seal().into_iter().map(Into::into).collect(),
|
||||
extra_data: h.extra_data().into(),
|
||||
seal_fields: h.view().decode_seal()
|
||||
.expect("Client/Miner returns only valid headers. We only serialize headers from Client/Miner; qed")
|
||||
.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use v1::types::{Log, H160, H256, H2048, U256};
|
||||
use v1::types::{Log, H160, H256, H2048, U256, U64};
|
||||
use ethcore::receipt::{Receipt as EthReceipt, RichReceipt, LocalizedReceipt, TransactionOutcome};
|
||||
|
||||
/// Receipt
|
||||
@@ -51,7 +51,7 @@ pub struct Receipt {
|
||||
pub logs_bloom: H2048,
|
||||
/// Status code
|
||||
#[serde(rename="status")]
|
||||
pub status_code: Option<u8>,
|
||||
pub status_code: Option<U64>,
|
||||
}
|
||||
|
||||
impl Receipt {
|
||||
@@ -62,10 +62,10 @@ impl Receipt {
|
||||
}
|
||||
}
|
||||
|
||||
fn outcome_to_status_code(outcome: &TransactionOutcome) -> Option<u8> {
|
||||
fn outcome_to_status_code(outcome: &TransactionOutcome) -> Option<U64> {
|
||||
match *outcome {
|
||||
TransactionOutcome::Unknown | TransactionOutcome::StateRoot(_) => None,
|
||||
TransactionOutcome::StatusCode(ref code) => Some(*code),
|
||||
TransactionOutcome::StatusCode(ref code) => Some((*code as u64).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn receipt_serialization() {
|
||||
let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":null,"type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","status":null}"#;
|
||||
let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":null,"type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","status":"0x1"}"#;
|
||||
|
||||
let receipt = Receipt {
|
||||
transaction_hash: Some(0.into()),
|
||||
@@ -158,7 +158,7 @@ mod tests {
|
||||
}],
|
||||
logs_bloom: 15.into(),
|
||||
state_root: Some(10.into()),
|
||||
status_code: None,
|
||||
status_code: Some(1u64.into()),
|
||||
};
|
||||
|
||||
let serialized = serde_json::to_string(&receipt).unwrap();
|
||||
|
||||
@@ -158,11 +158,10 @@ pub struct RichRawTransaction {
|
||||
pub transaction: Transaction
|
||||
}
|
||||
|
||||
|
||||
impl From<SignedTransaction> for RichRawTransaction {
|
||||
fn from(t: SignedTransaction) -> Self {
|
||||
// TODO: change transition to 0 when EIP-86 is commonly used.
|
||||
let tx: Transaction = Transaction::from_signed(t, 0, u64::max_value());
|
||||
impl RichRawTransaction {
|
||||
/// Creates new `RichRawTransaction` from `SignedTransaction`.
|
||||
pub fn from_signed(tx: SignedTransaction, block_number: u64, eip86_transition: u64) -> Self {
|
||||
let tx = Transaction::from_signed(tx, block_number, eip86_transition);
|
||||
RichRawTransaction {
|
||||
raw: tx.raw.clone(),
|
||||
transaction: tx,
|
||||
@@ -213,7 +212,7 @@ impl Transaction {
|
||||
hash: t.hash().into(),
|
||||
nonce: t.nonce.into(),
|
||||
block_hash: None,
|
||||
block_number: Some(block_number.into()),
|
||||
block_number: None,
|
||||
transaction_index: None,
|
||||
from: t.sender().into(),
|
||||
to: match t.action {
|
||||
|
||||
@@ -137,7 +137,7 @@ const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024;
|
||||
// Maximal number of transactions in sent in single packet.
|
||||
const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64;
|
||||
// Min number of blocks to be behind for a snapshot sync
|
||||
const SNAPSHOT_RESTORE_THRESHOLD: BlockNumber = 10000;
|
||||
const SNAPSHOT_RESTORE_THRESHOLD: BlockNumber = 30000;
|
||||
const SNAPSHOT_MIN_PEERS: usize = 3;
|
||||
|
||||
const STATUS_PACKET: u8 = 0x00;
|
||||
|
||||
4
test.sh
4
test.sh
@@ -24,6 +24,10 @@ esac
|
||||
|
||||
set -e
|
||||
|
||||
# Validate chainspecs
|
||||
./scripts/validate_chainspecs.sh
|
||||
|
||||
cargo test -j 8 $OPTIONS --features "$FEATURES" --all --exclude evmjit $1
|
||||
|
||||
# Validate --no-default-features build
|
||||
cargo check --no-default-features
|
||||
|
||||
@@ -3,7 +3,7 @@ description = "Ethcore utility library"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "ethcore-util"
|
||||
version = "1.8.0"
|
||||
version = "1.8.5"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ include!(concat!(env!("OUT_DIR"), "/version.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
|
||||
|
||||
#[cfg(feature = "final")]
|
||||
const THIS_TRACK: &'static str = "nightly";
|
||||
const THIS_TRACK: &'static str = "beta";
|
||||
// ^^^ should be reset to "stable" or "beta" according to the release branch.
|
||||
|
||||
#[cfg(not(feature = "final"))]
|
||||
|
||||
@@ -315,8 +315,9 @@ void OpenUI()
|
||||
STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
|
||||
|
||||
LPWSTR args = new WCHAR[lstrlen(commandLineFiltered) + MAX_PATH + 2];
|
||||
lstrcpy(args, L"parity.exe ui ");
|
||||
lstrcpy(args, L"parity.exe ");
|
||||
lstrcat(args, commandLineFiltered);
|
||||
lstrcat(args, L" ui");
|
||||
CreateProcess(path, args, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user