Compare commits

...

39 Commits

Author SHA1 Message Date
Tomasz Drwięga
c74c8c1ac1 [beta] Backports + HF block update (#7244)
* Reduce max block timestamp drift to 15 seconds (#7240)

* reduce max block timestamp drift to 15 seconds

* add test for block timestamp validation within allowed drift

* Update kovan HF block number.
2017-12-11 14:11:41 +01:00
Tomasz Drwięga
4e39c318aa [beta] Kovan HF (#7234)
* Kovan HF.

* Bump version.

* Fix aura difficulty race (#7198)

* Fix Aura difficulty race

* fix test key

* extract out score calculation

* fix build

* Update kovan HF block number.

* Add missing byzantium builtins.

* Bump installers versions.

* Increase allowed time drift to 10s. (#7238)
2017-12-08 13:08:15 +01:00
Robert Habermeier
03b1e9d8ba Merge pull request #7197 from paritytech/td-beta-backports
Beta backports
2017-12-06 15:18:45 +01:00
Tomasz Drwięga
fdaedc8c00 Maximum uncle count transition (#7196)
* Enable delayed maximum_uncle_count activation.

* Fix tests.

* Defer kovan HF.
2017-12-05 16:01:52 +01:00
Marek Kotewicz
d60fe51553 Merge pull request #7006 from paritytech/no-uncles
Disable uncles by default
2017-12-05 16:01:44 +01:00
Robert Habermeier
c7621b9bbf Merge pull request #7075 from miyao-gmo/feature/estimate_gas_limit
escape inifinite loop in estimte_gas
2017-12-04 16:18:22 +01:00
Marek Kotewicz
0ec35d9ac5 Merge pull request #7067 from sorpaas/patch-1
ECIP-1039: Monetary policy rounding specification
2017-12-04 16:15:06 +01:00
Sergey Pepyakin
ef702b77dc WASM Remove blockhash error (#7121)
* Remove blockhash error

* Update tests.
2017-12-04 16:14:46 +01:00
Marek Kotewicz
a8cf4efc91 Merge pull request #7110 from paritytech/remove-storage-error
WASM storage_read and storage_write don't return anything
2017-12-04 16:14:23 +01:00
Marek Kotewicz
aeb43b6af0 Merge pull request #7097 from paritytech/panic-payload-with-msg
WASM parse payload from panics
2017-12-04 16:13:29 +01:00
Tomasz Drwięga
dcdde49d91 Fix no-default-features. 2017-12-04 15:32:24 +01:00
Marek Kotewicz
b49c44a198 Merge pull request #7043 from paritytech/beta-backport
backports to beta
2017-11-14 15:51:13 +01:00
Sergey Pepyakin
561e843207 pwasm-std update (#7018) 2017-11-13 16:42:23 +01:00
debris
6ad5d559ca version 1.8.3 2017-11-13 15:31:35 +01:00
Kirill Pimenov
91db3535f8 Merge pull request #7004 from paritytech/cli-arguments-backwards-compatible
Make CLI arguments parsing more backwards compatible
2017-11-13 15:19:36 +01:00
Arkadiy Paronyan
baa1223736 Skip nonce check for gas estimation (#6997) 2017-11-13 14:54:23 +01:00
Alexey
a2d5edb8f5 Merge pull request #6967 from paritytech/wasm-elog
Events in WASM runtime
2017-11-13 14:53:05 +01:00
Tomasz Drwięga
454b4518f2 Return decoded seal fields. (#6932) 2017-11-13 14:52:00 +01:00
Tomasz Drwięga
303036cab0 Fix serialization of status in transaction receipts. (#6926) 2017-11-13 14:50:55 +01:00
Kirill Pimenov
b7e9152cc2 Merge pull request #6921 from paritytech/windows-fixes
Windows fixes
2017-11-13 14:49:01 +01:00
GitLab Build Bot
b1b5ffff95 [ci skip] js-precompiled 20171110-144625 2017-11-10 14:56:35 +00:00
Marek Kotewicz
067cbe78d2 Merge pull request #7014 from paritytech/jg-wallet-deploy
[beta] Disallow builtin multisig deploy (only watch)
2017-11-10 15:34:23 +01:00
jacogr
1211c1f10c Disallow builtin multisig deploy (only watch) 2017-11-10 09:31:32 +01:00
Nikolay Volf
148ec3731c [beta] Add hint in ActionParams for splitting code/data (#6968)
* Action params and embedded params handling

* fix namespaces
2017-11-03 12:20:54 +01:00
Arkadiy Paronyan
1b6588cb27 [beta] Backports (#6891)
* v1.8.2

* Refactor static context check in CREATE. (#6886)

* Refactor static context check in CREATE.

* Fix wasm.

* Fix serialization of non-localized transactions (#6868)

* Fix serialization of non-localized transactions.

* Return proper SignedTransactions representation.

* Allow force sealing and reseal=0 for non-dev chains. (#6878)
2017-10-25 13:13:11 +02:00
Afri Schoedon
0e4a06d078 Add ECIP1017 to Morden config (#6810) (#6845)
* Add ECIP1017 setting to Morden config

* Convert spaces to tabs

* Update Morden bootnodes to match Geth
2017-10-20 20:42:51 +02:00
Arkadiy Paronyan
d470773fec Ethstore optimizations (#6827) (#6844) 2017-10-20 20:22:01 +02:00
Arkadiy Paronyan
8f0eb3e192 v1.8.1 (#6843) 2017-10-20 16:40:59 +02:00
Arkadiy Paronyan
48c7e4ab8c Backport #6815 and #6829 (#6837)
* Tweaked snapshot sync threshold

* Change keypath derivation logic (#6815)

While the standard defined by Trezor as the default derivation path here
https://blog.trezor.io/trezor-integration-with-myetherwallet-3e217a652e08
says that it should be `m/44'/60'/0`, in practice they don't have an
implementation of a wallet for Ethereum themselves and refer customers
to MEW.

MEW has a custom implementation of the path derivation logic that allows them to
generate multiple addresses by essentially adding `/0`, `/1` etc to the path.

In my initial implementation of Trezor I didn't take this into
consideration unfortunately and just used the keypath that Trezor
themselves recommended. However, given that it's seemingly standard
practice to append `/0` for a "sub-address" (and this is what we've done
for Ledger as well) it seems like a mistake on my part to not take that
into consideration.

Unfortunately, anyone who has used their Trezor device with Parity
previously would now see a different address when they connect the
Trezor device the next time. The only way they would have to access the
old address is to use an old version, or by going through MEW and
selecting the Ledger keypath.

Also see #6811
2017-10-20 12:51:02 +02:00
GitLab Build Bot
8362bc7f2d [ci skip] js-precompiled 20171019-155727 2017-10-19 16:02:16 +00:00
Jaco Greeff
284fc65c70 Refresh cached tokens based on registry info & random balances (#6818) (#6824)
* Refresh cached tokens based on registry info & random balances

* Don't display errored token images
2017-10-19 17:49:25 +02:00
Arkadiy Paronyan
9882902f31 Updated ethabi to fix auto-update (#6771) 2017-10-15 13:59:43 +02:00
Arkadiy Paronyan
789c85561e Fixed kovan chain validation (#6758) (#6760)
* Fixed kovan chain validation

* Fork detection

* Fixed typo
2017-10-14 22:14:59 +02:00
Arkadiy Paronyan
18dff68278 Bumped fork block number for auto-update (#6755) 2017-10-14 15:10:38 +02:00
Arkadiy Paronyan
d9a92c2bea CLI: Reject invalid argument values rather than ignore them (#6723) (#6747)
* CLI: Reject invalid argument values rather than ignore them

* Fix grumbles
2017-10-13 16:34:21 +02:00
Arkadiy Paronyan
2145388103 Fixed modexp gas calculation overflow (#6741) (#6745) 2017-10-13 16:12:26 +02:00
GitLab Build Bot
77d00e3dab [ci skip] js-precompiled 20171012-203645 2017-10-12 20:48:36 +00:00
Nicolas Gotchac
aa6909ff99 Backport beta #6730 - Fixes Badges (#6732)
* Fix badges not showing up

* Always fetch meta data first [badges]
2017-10-12 22:26:57 +02:00
arkpar
0085d6a47b v1.8.0 in beta 2017-10-12 20:28:59 +02:00
78 changed files with 1272 additions and 446 deletions

106
Cargo.lock generated
View File

@@ -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]] [[package]]
name = "adler32" name = "adler32"
version = "1.0.2" version = "1.0.2"
@@ -374,7 +360,7 @@ dependencies = [
"bloomable 0.1.0", "bloomable 0.1.0",
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethjson 0.1.0", "ethjson 0.1.0",
"hash 0.1.0", "hash 0.1.0",
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -542,7 +528,7 @@ dependencies = [
[[package]] [[package]]
name = "ethabi" name = "ethabi"
version = "2.0.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "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-ipc-nano 1.8.0",
"ethcore-logger 1.8.0", "ethcore-logger 1.8.0",
"ethcore-stratum 1.8.0", "ethcore-stratum 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethjson 0.1.0", "ethjson 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"ethstore 0.1.0", "ethstore 0.1.0",
@@ -682,7 +668,7 @@ version = "1.8.0"
dependencies = [ dependencies = [
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-devtools 1.8.0", "ethcore-devtools 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "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)", "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 1.8.0",
"ethcore-ipc-codegen 1.8.0", "ethcore-ipc-codegen 1.8.0",
"ethcore-ipc-nano 1.8.0", "ethcore-ipc-nano 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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 1.8.0",
"ethcore-ipc-codegen 1.8.0", "ethcore-ipc-codegen 1.8.0",
"ethcore-network 1.8.0", "ethcore-network 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"evm 0.1.0", "evm 0.1.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"hash 0.1.0", "hash 0.1.0",
@@ -801,7 +787,7 @@ dependencies = [
"ethcore-devtools 1.8.0", "ethcore-devtools 1.8.0",
"ethcore-io 1.8.0", "ethcore-io 1.8.0",
"ethcore-logger 1.8.0", "ethcore-logger 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"hash 0.1.0", "hash 0.1.0",
@@ -827,7 +813,7 @@ name = "ethcore-secretstore"
version = "1.0.0" version = "1.0.0"
dependencies = [ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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 1.8.0",
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
@@ -836,7 +822,7 @@ dependencies = [
"ethcore-ipc-codegen 1.8.0", "ethcore-ipc-codegen 1.8.0",
"ethcore-ipc-nano 1.8.0", "ethcore-ipc-nano 1.8.0",
"ethcore-logger 1.8.0", "ethcore-logger 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "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-codegen 1.8.0",
"ethcore-ipc-nano 1.8.0", "ethcore-ipc-nano 1.8.0",
"ethcore-logger 1.8.0", "ethcore-logger 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"hash 0.1.0", "hash 0.1.0",
"jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.8)", "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)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.8)",
@@ -884,7 +870,7 @@ dependencies = [
[[package]] [[package]]
name = "ethcore-util" name = "ethcore-util"
version = "1.8.0" version = "1.8.4"
dependencies = [ dependencies = [
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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-ipc-nano 1.8.0",
"ethcore-light 1.8.0", "ethcore-light 1.8.0",
"ethcore-network 1.8.0", "ethcore-network 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethkey 0.2.0", "ethkey 0.2.0",
"hash 0.1.0", "hash 0.1.0",
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1044,7 +1030,7 @@ dependencies = [
"common-types 0.1.0", "common-types 0.1.0",
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-logger 1.8.0", "ethcore-logger 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethjson 0.1.0", "ethjson 0.1.0",
"evmjit 1.8.0", "evmjit 1.8.0",
"hash 0.1.0", "hash 0.1.0",
@@ -1066,7 +1052,7 @@ dependencies = [
"ethcore 1.8.0", "ethcore 1.8.0",
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethjson 0.1.0", "ethjson 0.1.0",
"evm 0.1.0", "evm 0.1.0",
"panic_hook 0.1.0", "panic_hook 0.1.0",
@@ -1364,7 +1350,7 @@ dependencies = [
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-ipc 1.8.0", "ethcore-ipc 1.8.0",
"ethcore-ipc-codegen 1.8.0", "ethcore-ipc-codegen 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -1809,7 +1795,7 @@ dependencies = [
name = "native-contract-generator" name = "native-contract-generator"
version = "0.1.0" version = "0.1.0"
dependencies = [ 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)", "heck 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -1818,7 +1804,7 @@ name = "native-contracts"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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", "ethcore-bigint 0.1.3",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"native-contract-generator 0.1.0", "native-contract-generator 0.1.0",
@@ -1857,7 +1843,7 @@ dependencies = [
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-io 1.8.0", "ethcore-io 1.8.0",
"ethcore-network 1.8.0", "ethcore-network 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"kvdb 0.1.0", "kvdb 0.1.0",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2056,7 +2042,7 @@ dependencies = [
[[package]] [[package]]
name = "parity" name = "parity"
version = "1.8.0" version = "1.8.4"
dependencies = [ dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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-network 1.8.0",
"ethcore-secretstore 1.0.0", "ethcore-secretstore 1.0.0",
"ethcore-stratum 1.8.0", "ethcore-stratum 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethkey 0.2.0", "ethkey 0.2.0",
"ethsync 1.8.0", "ethsync 1.8.0",
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2136,7 +2122,7 @@ dependencies = [
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-devtools 1.8.0", "ethcore-devtools 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"fetch 0.1.0", "fetch 0.1.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "futures-cpupool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2195,10 +2181,10 @@ dependencies = [
name = "parity-hash-fetch" name = "parity-hash-fetch"
version = "1.8.0" version = "1.8.0"
dependencies = [ 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-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"fetch 0.1.0", "fetch 0.1.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"hash 0.1.0", "hash 0.1.0",
@@ -2220,7 +2206,7 @@ dependencies = [
"ethcore 1.8.0", "ethcore 1.8.0",
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.8)", "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)", "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)", "multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2234,7 +2220,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"ethcore 1.8.0", "ethcore 1.8.0",
"ethcore-io 1.8.0", "ethcore-io 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethkey 0.2.0", "ethkey 0.2.0",
"kvdb 0.1.0", "kvdb 0.1.0",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2249,7 +2235,7 @@ name = "parity-machine"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
] ]
[[package]] [[package]]
@@ -2277,7 +2263,7 @@ dependencies = [
"ethcore-light 1.8.0", "ethcore-light 1.8.0",
"ethcore-logger 1.8.0", "ethcore-logger 1.8.0",
"ethcore-network 1.8.0", "ethcore-network 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethjson 0.1.0", "ethjson 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
@@ -2358,7 +2344,7 @@ name = "parity-ui"
version = "1.8.0" version = "1.8.0"
dependencies = [ dependencies = [
"parity-ui-dev 1.8.0", "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)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -2372,7 +2358,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-ui-precompiled" name = "parity-ui-precompiled"
version = "1.4.0" 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 = [ dependencies = [
"parity-dapps-glue 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -2381,13 +2367,13 @@ dependencies = [
name = "parity-updater" name = "parity-updater"
version = "1.8.0" version = "1.8.0"
dependencies = [ 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 1.8.0",
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-ipc 1.8.0", "ethcore-ipc 1.8.0",
"ethcore-ipc-codegen 1.8.0", "ethcore-ipc-codegen 1.8.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethsync 1.8.0", "ethsync 1.8.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-common-types 1.8.0", "ipc-common-types 1.8.0",
@@ -2401,7 +2387,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-wasm" name = "parity-wasm"
version = "0.14.5" version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2849,7 +2835,7 @@ name = "rpc-cli"
version = "1.4.0" version = "1.4.0"
dependencies = [ dependencies = [
"bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-rpc 1.8.0", "parity-rpc 1.8.0",
"parity-rpc-client 1.4.0", "parity-rpc-client 1.4.0",
@@ -3565,7 +3551,7 @@ dependencies = [
"common-types 0.1.0", "common-types 0.1.0",
"ethcore-bigint 0.1.3", "ethcore-bigint 0.1.3",
"ethcore-bytes 0.1.0", "ethcore-bytes 0.1.0",
"ethcore-util 1.8.0", "ethcore-util 1.8.4",
"ethjson 0.1.0", "ethjson 0.1.0",
"evmjit 1.8.0", "evmjit 1.8.0",
"hash 0.1.0", "hash 0.1.0",
@@ -3580,10 +3566,24 @@ name = "void"
version = "1.0.2" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" 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.4",
"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]] [[package]]
name = "wasm-utils" name = "wasm-utils"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/wasm-utils#6a39db802eb6b67a0c4e5cf50741f965e217335a" source = "git+https://github.com/paritytech/wasm-utils#3d59f7ca0661317bc66894a26b2a5a319fa5d229"
dependencies = [ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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]] [[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.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 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 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 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 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" "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 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-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-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-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git?branch=beta)" = "<none>"
"checksum parity-wasm 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4502e18417d96bd8e72fca9ea4cc18f4d80288ff565582d10aefe86f18b4fc3" "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 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 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" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595"

View File

@@ -1,7 +1,7 @@
[package] [package]
description = "Parity Ethereum client" description = "Parity Ethereum client"
name = "parity" name = "parity"
version = "1.8.0" version = "1.8.4"
license = "GPL-3.0" license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs" build = "build.rs"

View File

@@ -193,7 +193,7 @@ const UPDATE_TIMEOUT_ERR_SECS: u64 = 60;
const UPDATE_TIMEOUT_INCOMPLETE_SECS: u64 = 10; const UPDATE_TIMEOUT_INCOMPLETE_SECS: u64 = 10;
/// Maximal valid time drift. /// 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>; type BoxFuture<A, B> = Box<Future<Item = A, Error = B> + Send>;

View File

@@ -12,7 +12,7 @@ rustc_version = "0.1"
[dependencies] [dependencies]
parity-ui-dev = { path = "../../js", optional = true } 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 # 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] [features]
no-precompiled-js = ["parity-ui-dev"] no-precompiled-js = ["parity-ui-dev"]

View File

@@ -322,20 +322,24 @@ impl<Cost: CostType> Interpreter<Cost> {
let init_off = stack.pop_back(); let init_off = stack.pop_back();
let init_size = 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 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); if ext.is_static() {
let can_create = ext.balance(&params.address)? >= endowment && ext.depth() < ext.schedule().max_depth; return Err(vm::Error::MutableCallInStaticContext);
}
// clear return data buffer before creating new call frame. // clear return data buffer before creating new call frame.
self.return_data = ReturnData::empty(); self.return_data = ReturnData::empty();
let can_create = ext.balance(&params.address)? >= endowment && ext.depth() < ext.schedule().max_depth;
if !can_create { if !can_create {
stack.push(U256::zero()); stack.push(U256::zero());
return Ok(InstructionResult::UnusedGas(create_gas)); 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); let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme);
return match create_result { return match create_result {
ContractCreateResult::Created(address, gas_left) => { ContractCreateResult::Created(address, gas_left) => {
@@ -351,9 +355,6 @@ impl<Cost: CostType> Interpreter<Cost> {
stack.push(U256::zero()); stack.push(U256::zero());
Ok(InstructionResult::Ok) Ok(InstructionResult::Ok)
}, },
ContractCreateResult::FailedInStaticCall => {
Err(vm::Error::MutableCallInStaticContext)
},
}; };
}, },
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => { instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {

View File

@@ -724,7 +724,6 @@ fn test_jumps(factory: super::Factory) {
assert_eq!(gas_left, U256::from(54_117)); assert_eq!(gas_left, U256::from(54_117));
} }
evm_test!{test_calls: test_calls_jit, test_calls_int} evm_test!{test_calls: test_calls_jit, test_calls_int}
fn test_calls(factory: super::Factory) { fn test_calls(factory: super::Factory) {
let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap(); let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap();
@@ -769,6 +768,27 @@ fn test_calls(factory: super::Factory) {
assert_eq!(ext.calls.len(), 2); 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) { fn assert_set_contains<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, val: &T) {
let contains = set.contains(val); let contains = set.contains(val);
if !contains { if !contains {

View File

@@ -23,18 +23,27 @@
] ]
}, },
"validateScoreTransition": 1000000, "validateScoreTransition": 1000000,
"validateStepTransition": 1500000 "validateStepTransition": 1500000,
"maximumUncleCountTransition": 5067000,
"maximumUncleCount": 0
} }
} }
}, },
"params": { "params": {
"gasLimitBoundDivisor": "0x400", "gasLimitBoundDivisor": "0x400",
"registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3", "registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"networkID" : "0x2A", "networkID" : "0x2A",
"forkBlock": 4297256,
"forkCanonHash": "0x0a66d93c2f727dca618fabaf70c39b37018c73d78b939d8b11efbbd09034778f",
"validateReceiptsTransition" : 1000000, "validateReceiptsTransition" : 1000000,
"eip155Transition": 1000000 "eip155Transition": 1000000,
"validateChainIdTransition": 1000000,
"eip140Transition": 5067000,
"eip211Transition": 5067000,
"eip214Transition": 5067000,
"eip658Transition": 5067000
}, },
"genesis": { "genesis": {
"seal": { "seal": {
@@ -51,6 +60,10 @@
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, "0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "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" } "0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
}, },
"nodes": [ "nodes": [

View File

@@ -13,6 +13,7 @@
"eip160Transition": 1915000, "eip160Transition": 1915000,
"ecip1010PauseTransition": 1915000, "ecip1010PauseTransition": 1915000,
"ecip1010ContinueTransition": 3415000, "ecip1010ContinueTransition": 3415000,
"ecip1017EraRounds": 2000000,
"eip161abcTransition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff" "eip161dTransition": "0x7fffffffffffffff"
@@ -49,11 +50,13 @@
"gasLimit": "0x2fefd8" "gasLimit": "0x2fefd8"
}, },
"nodes": [ "nodes": [
"enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303",
"enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303",
"enode://fb28713820e718066a2f5df6250ae9d07cff22f672dbf26be6c75d088f821a9ad230138ba492c533a80407d054b1436ef18e951bb65e6901553516c8dffe8ff0@104.155.176.151:30304", "enode://fb28713820e718066a2f5df6250ae9d07cff22f672dbf26be6c75d088f821a9ad230138ba492c533a80407d054b1436ef18e951bb65e6901553516c8dffe8ff0@104.155.176.151:30304",
"enode://afdc6076b9bf3e7d3d01442d6841071e84c76c73a7016cb4f35c0437df219db38565766234448f1592a07ba5295a867f0ce87b359bf50311ed0b830a2361392d@104.154.136.117:30403", "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": { "accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },

View File

@@ -269,7 +269,7 @@ impl AccountProvider {
/// Checks whether an account with a given address is present. /// Checks whether an account with a given address is present.
pub fn has_account(&self, address: Address) -> Result<bool, Error> { 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. /// Returns addresses of all accounts.

View File

@@ -380,8 +380,13 @@ impl<'x> OpenBlock<'x> {
/// NOTE Will check chain constraints and the uncle number but will NOT check /// NOTE Will check chain constraints and the uncle number but will NOT check
/// that the header itself is actually valid. /// that the header itself is actually valid.
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> { pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
if self.block.uncles.len() + 1 > self.engine.maximum_uncle_count() { let max_uncles = self.engine.maximum_uncle_count(self.block.header().number());
return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.uncles.len() + 1})); 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 number
// TODO: check not a direct ancestor (use last_hashes for that) // TODO: check not a direct ancestor (use last_hashes for that)

View File

@@ -123,7 +123,11 @@ impl Pricer for ModexpPricer {
let adjusted_exp_len = Self::adjusted_exp_len(exp_len, exp_low); 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, 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 // test for potential exp len overflow
{ {
let input = FromHex::from_hex("\ let input = FromHex::from_hex("\

View File

@@ -1230,18 +1230,18 @@ impl BlockChainClient for Client {
} }
fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError> { fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError> {
const UPPER_CEILING: u64 = 1_000_000_000_000u64; let (mut upper, max_upper, env_info) = {
let (mut upper, env_info) = {
let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?; let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?;
let initial_upper = env_info.gas_limit; let init = env_info.gas_limit;
env_info.gas_limit = UPPER_CEILING.into(); let max = init * U256::from(10);
(initial_upper, env_info) env_info.gas_limit = max;
(init, max, env_info)
}; };
// that's just a copy of the state. // that's just a copy of the state.
let original_state = self.state_at(block).ok_or(CallError::StatePruned)?; let original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
let sender = t.sender(); let sender = t.sender();
let options = || TransactOptions::with_tracing(); let options = || TransactOptions::with_tracing().dont_check_nonce();
let cond = |gas| { let cond = |gas| {
let mut tx = t.as_unsigned().clone(); let mut tx = t.as_unsigned().clone();
@@ -1256,9 +1256,7 @@ impl BlockChainClient for Client {
}; };
if !cond(upper)? { if !cond(upper)? {
// impossible at block gas limit - try `UPPER_CEILING` instead. upper = max_upper;
// TODO: consider raising limit by powers of two.
upper = UPPER_CEILING.into();
if !cond(upper)? { if !cond(upper)? {
trace!(target: "estimate_gas", "estimate_gas failed with {}", upper); trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", 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()) .find_uncle_headers(&h, engine.maximum_uncle_age())
.unwrap_or_else(Vec::new) .unwrap_or_else(Vec::new)
.into_iter() .into_iter()
.take(engine.maximum_uncle_count()) .take(engine.maximum_uncle_count(open_block.header().number()))
.foreach(|h| { .foreach(|h| {
open_block.push_uncle(h).expect("pushing maximum_uncle_count; open_block.push_uncle(h).expect("pushing maximum_uncle_count;
open_block was just created; open_block was just created;
@@ -1886,7 +1884,7 @@ impl MiningBlockChainClient for Client {
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock { fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
let engine = &*self.engine; let engine = &*self.engine;
let mut block = block.reopen(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 { if block.uncles().len() < max_uncles {
let chain = self.chain.read(); let chain = self.chain.read();
let h = chain.best_block_hash(); let h = chain.best_block_hash();

View File

@@ -65,6 +65,10 @@ pub struct AuthorityRoundParams {
pub immediate_transitions: bool, pub immediate_transitions: bool,
/// Block reward in base units. /// Block reward in base units.
pub block_reward: U256, 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 { 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), validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
immediate_transitions: p.immediate_transitions.unwrap_or(false), immediate_transitions: p.immediate_transitions.unwrap_or(false),
block_reward: p.block_reward.map_or_else(Default::default, Into::into), 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 { struct EpochManager {
epoch_transition_hash: H256, epoch_transition_hash: H256,
epoch_transition_number: BlockNumber, epoch_transition_number: BlockNumber,
@@ -218,6 +229,8 @@ pub struct AuthorityRound {
epoch_manager: Mutex<EpochManager>, epoch_manager: Mutex<EpochManager>,
immediate_transitions: bool, immediate_transitions: bool,
block_reward: U256, block_reward: U256,
maximum_uncle_count_transition: u64,
maximum_uncle_count: usize,
machine: EthereumMachine, machine: EthereumMachine,
} }
@@ -365,6 +378,8 @@ impl AuthorityRound {
epoch_manager: Mutex::new(EpochManager::blank()), epoch_manager: Mutex::new(EpochManager::blank()),
immediate_transitions: our_params.immediate_transitions, immediate_transitions: our_params.immediate_transitions,
block_reward: our_params.block_reward, 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, 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) { fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
// Chain scoring: total weight is sqrt(U256::max_value())*height - step let parent_step = header_step(parent).expect("Header has been verified; qed");
let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load().into(); let score = calculate_score(parent_step.into(), self.step.load().into());
header.set_difficulty(new_difficulty); header.set_difficulty(score);
} }
fn seals_internally(&self) -> Option<bool> { fn seals_internally(&self) -> Option<bool> {
// TODO: accept a `&Call` here so we can query the validator set.
Some(self.signer.read().is_some()) Some(self.signer.read().is_some())
} }
@@ -450,13 +475,21 @@ impl Engine<EthereumMachine> for AuthorityRound {
/// ///
/// This operation is synchronous and may (quite reasonably) not be available, in which case /// This operation is synchronous and may (quite reasonably) not be available, in which case
/// `Seal::None` will be returned. /// `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 // first check to avoid generating signature most of the time
// (but there's still a race to the `compare_and_swap`) // (but there's still a race to the `compare_and_swap`)
if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; } if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; }
let header = block.header(); let header = block.header();
let parent_step: U256 = header_step(parent)
.expect("Header has been verified; qed").into();
let step = self.step.load(); 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 // fetch correct validator set for current epoch, taking into account
// finality of previous transitions. // finality of previous transitions.
@@ -498,6 +531,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
trace!(target: "engine", "generate_seal: {} not a proposer for step {}.", trace!(target: "engine", "generate_seal: {} not a proposer for step {}.",
header.author(), step); header.author(), step);
} }
Seal::None Seal::None
} }
@@ -539,7 +573,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
} }
/// Check the number of seal fields. /// 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()) { if header.number() >= self.validate_score_transition && *header.difficulty() >= U256::from(U128::max_value()) {
Err(From::from(BlockError::DifficultyOutOfBounds( Err(From::from(BlockError::DifficultyOutOfBounds(
OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() } OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() }
@@ -850,17 +884,51 @@ mod tests {
let b2 = b2.close_and_lock(); let b2 = b2.close_and_lock();
engine.set_signer(tap.clone(), addr1, "1".into()); 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()); assert!(b1.clone().try_seal(engine, seal).is_ok());
// Second proposal is forbidden. // 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()); 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()); assert!(b2.clone().try_seal(engine, seal).is_ok());
// Second proposal is forbidden. // 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 +1017,8 @@ mod tests {
validate_score_transition: 0, validate_score_transition: 0,
validate_step_transition: 0, validate_step_transition: 0,
immediate_transitions: true, immediate_transitions: true,
maximum_uncle_count_transition: 0,
maximum_uncle_count: 0,
block_reward: Default::default(), block_reward: Default::default(),
}; };
@@ -976,4 +1046,31 @@ mod tests {
assert!(aura.verify_block_family(&header, &parent_header).is_ok()); assert!(aura.verify_block_family(&header, &parent_header).is_ok());
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1); 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);
}
} }

View File

@@ -107,7 +107,7 @@ impl Engine<EthereumMachine> for BasicAuthority {
} }
/// Attempt to seal the block internally. /// 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 header = block.header();
let author = header.author(); let author = header.author();
if self.validators.contains(header.parent_hash(), 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 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 = 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(); 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()); assert!(b.try_seal(engine, seal).is_ok());
} }
} }

View File

@@ -43,7 +43,7 @@ impl<M: Machine> Engine<M> for InstantSeal<M>
fn seals_internally(&self) -> Option<bool> { Some(true) } 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()) } 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 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 = 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(); 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()); assert!(b.try_seal(engine, seal).is_ok());
} }
} }

View File

@@ -192,7 +192,8 @@ pub trait Engine<M: Machine>: Sync + Send {
fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() } fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() }
/// Maximum number of uncles a block is allowed to declare. /// 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. /// The number of generations back that uncles can be.
fn maximum_uncle_age(&self) -> usize { 6 } 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 /// It is fine to require access to state or a full client for this function, since
/// light clients do not generate seals. /// 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. /// 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. /// 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) self.machine().account_start_nonce(block)
} }

View File

@@ -16,6 +16,7 @@
use bigint::prelude::U256; use bigint::prelude::U256;
use engines::Engine; use engines::Engine;
use header::BlockNumber;
use parity_machine::{Header, LiveBlock, WithBalances}; use parity_machine::{Header, LiveBlock, WithBalances};
/// Params for a null engine. /// 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) 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> { fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> {
Ok(()) Ok(())
} }

View File

@@ -450,7 +450,7 @@ impl Engine<EthereumMachine> for Tendermint {
fn machine(&self) -> &EthereumMachine { &self.machine } 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 } 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 /// This operation is synchronous and may (quite reasonably) not be available, in which case
/// `Seal::None` will be returned. /// `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 header = block.header();
let author = header.author(); let author = header.author();
// Only proposer can generate seal if None was generated. // 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 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 = 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(); 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) (b, seal)
} else { } else {
panic!() panic!()

View File

@@ -26,7 +26,7 @@ use util::Address;
use unexpected::{OutOfBounds, Mismatch}; use unexpected::{OutOfBounds, Mismatch};
use block::*; use block::*;
use error::{BlockError, Error}; use error::{BlockError, Error};
use header::Header; use header::{Header, BlockNumber};
use engines::{self, Engine}; use engines::{self, Engine};
use ethjson; use ethjson;
use rlp::{self, UntrustedRlp}; 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) { fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
let difficulty = self.calculate_difficulty(header, parent); let difficulty = self.calculate_difficulty(header, parent);
header.set_difficulty(difficulty); header.set_difficulty(difficulty);
@@ -447,9 +449,12 @@ fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u6
} else { } else {
block_number / era_rounds block_number / era_rounds
}; };
let mut divi = U256::from(1);
for _ in 0..eras { 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) (eras, reward)
} }
@@ -515,6 +520,11 @@ mod tests {
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number);
assert_eq!(15, eras); assert_eq!(15, eras);
assert_eq!(U256::from_str("271000000000000").unwrap(), reward); 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] #[test]

View File

@@ -31,7 +31,7 @@ use machine::EthereumMachine;
use super::spec::*; use super::spec::*;
/// Most recent fork block that we support on Mainnet. /// 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. /// Most recent fork block that we support on Ropsten.
pub const FORK_SUPPORTED_ROPSTEN: u64 = 10; pub const FORK_SUPPORTED_ROPSTEN: u64 = 10;

View File

@@ -309,6 +309,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
code: Some(Arc::new(t.data.clone())), code: Some(Arc::new(t.data.clone())),
data: None, data: None,
call_type: CallType::None, call_type: CallType::None,
params_type: vm::ParamsType::Embedded,
}; };
let mut out = if output_from_create { Some(vec![]) } else { None }; 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)) (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)?), code_hash: Some(self.state.code_hash(address)?),
data: Some(t.data.clone()), data: Some(t.data.clone()),
call_type: CallType::Call, call_type: CallType::Call,
params_type: vm::ParamsType::Separate,
}; };
let mut out = vec![]; let mut out = vec![];
(self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer, &mut vm_tracer), out) (self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer, &mut vm_tracer), out)

View File

@@ -171,6 +171,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
code_hash: Some(code_hash), code_hash: Some(code_hash),
data: Some(H256::from(number).to_vec()), data: Some(H256::from(number).to_vec()),
call_type: CallType::Call, call_type: CallType::Call,
params_type: vm::ParamsType::Separate,
}; };
let mut output = H256::new(); 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, code_hash: code_hash,
data: None, data: None,
call_type: CallType::None, call_type: CallType::None,
params_type: vm::ParamsType::Embedded,
}; };
if !self.static_flag { 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 }) => { Ok(FinalizationResult{ gas_left, apply_state: false, return_data }) => {
ContractCreateResult::Reverted(gas_left, return_data) ContractCreateResult::Reverted(gas_left, return_data)
}, },
Err(vm::Error::MutableCallInStaticContext) => ContractCreateResult::FailedInStaticCall,
_ => ContractCreateResult::Failed, _ => 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), code_hash: Some(code_hash),
data: Some(data.to_vec()), data: Some(data.to_vec()),
call_type: call_type, call_type: call_type,
params_type: vm::ParamsType::Separate,
}; };
if let Some(value) = value { if let Some(value) = value {

View File

@@ -162,6 +162,12 @@ impl Header {
pub fn difficulty(&self) -> &U256 { &self.difficulty } pub fn difficulty(&self) -> &U256 { &self.difficulty }
/// Get the seal field of the header. /// Get the seal field of the header.
pub fn seal(&self) -> &[Bytes] { &self.seal } 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. // TODO: seal_at, set_seal_at &c.
@@ -340,13 +346,20 @@ mod tests {
// that's rlp of block header created with ethash engine. // that's rlp of block header created with ethash engine.
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap(); let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".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 = "88ab4e252a7e8c2a23".from_hex().unwrap();
let nonce_decoded = "ab4e252a7e8c2a23".from_hex().unwrap();
let header: Header = rlp::decode(&header_rlp); 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.len(), 2);
assert_eq!(seal_fields[0], mix_hash); assert_eq!(seal_fields[0], mix_hash);
assert_eq!(seal_fields[1], nonce); 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] #[test]

View File

@@ -35,7 +35,7 @@ use tx_filter::TransactionFilter;
use bigint::prelude::U256; use bigint::prelude::U256;
use bytes::BytesRef; use bytes::BytesRef;
use util::Address; use util::Address;
use vm::{CallType, ActionParams, ActionValue}; use vm::{CallType, ActionParams, ActionValue, ParamsType};
use vm::{EnvInfo, Schedule, CreateContractAddress}; use vm::{EnvInfo, Schedule, CreateContractAddress};
/// Parity tries to round block.gas_limit to multiple of this constant /// 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)?), code_hash: Some(state.code_hash(&contract_address)?),
data: data, data: data,
call_type: CallType::Call, call_type: CallType::Call,
params_type: ParamsType::Separate,
}; };
let mut ex = Executive::new(&mut state, &env_info, self); let mut ex = Executive::new(&mut state, &env_info, self);
let mut substate = Substate::new(); let mut substate = Substate::new();
@@ -351,7 +352,9 @@ impl EthereumMachine {
None => true, 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) Some(self.params().chain_id)
} else { } else {
None None

View File

@@ -525,7 +525,13 @@ impl Miner {
fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool { 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() { if !block.transactions().is_empty() || self.forced_sealing() || Instant::now() > *self.next_mandatory_reseal.read() {
trace!(target: "miner", "seal_block_internally: attempting internal seal."); 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. // Save proposal for later seal submission and broadcast it.
Seal::Proposal(seal) => { Seal::Proposal(seal) => {
trace!(target: "miner", "Received a Proposal seal."); trace!(target: "miner", "Received a Proposal seal.");
@@ -647,10 +653,6 @@ impl Miner {
condition: Option<TransactionCondition>, condition: Option<TransactionCondition>,
transaction_queue: &mut BanningTransactionQueue, transaction_queue: &mut BanningTransactionQueue,
) -> Vec<Result<TransactionImportResult, Error>> { ) -> 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 best_block_header = client.best_block_header().decode();
let insertion_time = client.chain_info().best_block_number; let insertion_time = client.chain_info().best_block_number;
@@ -669,8 +671,8 @@ impl Miner {
Err(e) Err(e)
}, },
Ok(transaction) => { Ok(transaction) => {
let origin = accounts.as_ref().and_then(|accounts| { let origin = self.accounts.as_ref().and_then(|accounts| {
match accounts.contains(&transaction.sender()) { match accounts.has_account(transaction.sender()).unwrap_or(false) {
true => Some(TransactionOrigin::Local), true => Some(TransactionOrigin::Local),
false => None, false => None,
} }

View File

@@ -30,7 +30,7 @@ use parking_lot::RwLock;
use rlp::{Rlp, RlpStream}; use rlp::{Rlp, RlpStream};
use rustc_hex::FromHex; use rustc_hex::FromHex;
use util::*; use util::*;
use vm::{EnvInfo, CallType, ActionValue, ActionParams}; use vm::{EnvInfo, CallType, ActionValue, ActionParams, ParamsType};
use super::genesis::Genesis; use super::genesis::Genesis;
use super::seal::Generic as GenericSeal; use super::seal::Generic as GenericSeal;
@@ -85,6 +85,8 @@ pub struct CommonParams {
pub eip155_transition: BlockNumber, pub eip155_transition: BlockNumber,
/// Validate block receipts root. /// Validate block receipts root.
pub validate_receipts_transition: BlockNumber, 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. /// Number of first block where EIP-86 (Metropolis) rules begin.
pub eip86_transition: BlockNumber, pub eip86_transition: BlockNumber,
/// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin. /// 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.validate_receipts_transition != 0 && self.eip86_transition != 0 &&
self.eip140_transition != 0 && self.eip210_transition != 0 && self.eip140_transition != 0 && self.eip210_transition != 0 &&
self.eip211_transition != 0 && self.eip214_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), eip98_transition: p.eip98_transition.map_or(0, Into::into),
eip155_transition: p.eip155_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_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( eip86_transition: p.eip86_transition.map_or(
BlockNumber::max_value(), BlockNumber::max_value(),
Into::into, Into::into,
@@ -501,6 +504,7 @@ impl Spec {
code: Some(Arc::new(constructor.clone())), code: Some(Arc::new(constructor.clone())),
data: None, data: None,
call_type: CallType::None, call_type: CallType::None,
params_type: ParamsType::Embedded,
}; };
let mut substate = Substate::new(); let mut substate = Substate::new();

View File

@@ -2,7 +2,7 @@
use std::sync::Arc; use std::sync::Arc;
use hash::keccak; use hash::keccak;
use vm::{EnvInfo, ActionParams, ActionValue, CallType}; use vm::{EnvInfo, ActionParams, ActionValue, CallType, ParamsType};
use evm::{Factory, VMType}; use evm::{Factory, VMType};
use executive::Executive; use executive::Executive;
use state::Substate; use state::Substate;
@@ -45,6 +45,7 @@ fn test_blockhash_eip210(factory: Factory) {
code_hash: Some(blockhash_contract_code_hash), code_hash: Some(blockhash_contract_code_hash),
data: Some(H256::from(i - 1).to_vec()), data: Some(H256::from(i - 1).to_vec()),
call_type: CallType::Call, call_type: CallType::Call,
params_type: ParamsType::Separate,
}; };
let mut ex = Executive::new(&mut state, &env_info, &machine); let mut ex = Executive::new(&mut state, &env_info, &machine);
let mut substate = Substate::new(); let mut substate = Substate::new();
@@ -67,6 +68,7 @@ fn test_blockhash_eip210(factory: Factory) {
code_hash: Some(get_prev_hash_code_hash), code_hash: Some(get_prev_hash_code_hash),
data: None, data: None,
call_type: CallType::Call, call_type: CallType::Call,
params_type: ParamsType::Separate,
}; };
let mut ex = Executive::new(&mut state, &env_info, &machine); let mut ex = Executive::new(&mut state, &env_info, &machine);
let mut substate = Substate::new(); let mut substate = Substate::new();

View File

@@ -469,6 +469,11 @@ impl SignedTransaction {
pub fn is_unsigned(&self) -> bool { pub fn is_unsigned(&self) -> bool {
self.transaction.is_unsigned() 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. /// Signed Transaction that is a part of canon blockchain.

View File

@@ -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> { fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> {
let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?; 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 != 0 {
if num_uncles > engine.maximum_uncle_count() { if num_uncles > max_uncles {
return Err(From::from(BlockError::TooManyUncles(OutOfBounds { min: None, max: Some(engine.maximum_uncle_count()), found: num_uncles }))); return Err(From::from(BlockError::TooManyUncles(OutOfBounds {
min: None,
max: Some(max_uncles),
found: num_uncles,
})));
} }
let mut excluded = HashSet::new(); let mut excluded = HashSet::new();
@@ -268,7 +273,7 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool)
} }
if is_full { 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 { if header.timestamp() > max_time {
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() }))) 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)); check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
header = good.clone(); 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)); 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 = good.clone();
header.set_number(9); header.set_number(9);
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), 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(); let mut bad_uncles = good_uncles.clone();
bad_uncles.push(good_uncle1.clone()); bad_uncles.push(good_uncle1.clone());
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc), check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() })); TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count(header.number())), min: None, found: bad_uncles.len() }));
header = good.clone(); header = good.clone();
bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ]; bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ];

View File

@@ -21,7 +21,7 @@ use bigint::prelude::U256;
use bigint::hash::{H256, H2048}; use bigint::hash::{H256, H2048};
use util::Address; use util::Address;
use bytes::Bytes; use bytes::Bytes;
use rlp::Rlp; use rlp::{self, Rlp};
use header::BlockNumber; use header::BlockNumber;
/// View onto block header rlp. /// View onto block header rlp.
@@ -99,6 +99,14 @@ impl<'a> HeaderView<'a> {
} }
seal 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)] #[cfg(test)]

View File

@@ -35,6 +35,15 @@ pub enum ActionValue {
Apparent(U256) 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 { impl ActionValue {
/// Returns action value as U256. /// Returns action value as U256.
pub fn value(&self) -> U256 { pub fn value(&self) -> U256 {
@@ -81,7 +90,8 @@ pub struct ActionParams {
pub data: Option<Bytes>, pub data: Option<Bytes>,
/// Type of call /// Type of call
pub call_type: CallType, pub call_type: CallType,
/// Param types encoding
pub params_type: ParamsType,
} }
impl Default for ActionParams { impl Default for ActionParams {
@@ -99,6 +109,7 @@ impl Default for ActionParams {
code: None, code: None,
data: None, data: None,
call_type: CallType::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(), gas_price: t.gas_price.into(),
value: ActionValue::Transfer(t.value.into()), value: ActionValue::Transfer(t.value.into()),
call_type: match address.is_zero() { true => CallType::None, false => CallType::Call }, // TODO @debris is this correct? call_type: match address.is_zero() { true => CallType::None, false => CallType::Call }, // TODO @debris is this correct?
params_type: ParamsType::Separate,
} }
} }
} }

View File

@@ -35,9 +35,6 @@ pub enum ContractCreateResult {
/// Returned when contract creation failed. /// Returned when contract creation failed.
/// VM doesn't have to know the reason. /// VM doesn't have to know the reason.
Failed, Failed,
/// Returned when contract creation failed.
/// VM doesn't have to know the reason.
FailedInStaticCall,
/// Reverted with REVERT. /// Reverted with REVERT.
Reverted(U256, ReturnData), Reverted(U256, ReturnData),
} }

View File

@@ -35,7 +35,7 @@ mod error;
pub mod tests; pub mod tests;
pub use action_params::{ActionParams, ActionValue}; pub use action_params::{ActionParams, ActionValue, ParamsType};
pub use call_type::CallType; pub use call_type::CallType;
pub use env_info::{EnvInfo, LastHashes}; pub use env_info::{EnvInfo, LastHashes};
pub use schedule::{Schedule, CleanDustMode}; pub use schedule::{Schedule, CleanDustMode};

View File

@@ -127,12 +127,14 @@ pub struct WasmCosts {
pub mul: u32, pub mul: u32,
/// Memory (load/store) operations multiplier. /// Memory (load/store) operations multiplier.
pub mem: u32, pub mem: u32,
/// Memory copy operation. /// Memory copy operation, per byte.
pub mem_copy: u32, 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. /// Static region charge, per byte.
pub static_region: u32, 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 /// General static query of U256 value from env-info
pub static_u256: u32, pub static_u256: u32,
/// General static query of Address value from env-info /// General static query of Address value from env-info
@@ -147,11 +149,9 @@ impl Default for WasmCosts {
mul: 4, mul: 4,
mem: 2, mem: 2,
mem_copy: 1, mem_copy: 1,
mem_move: 1,
mem_set: 1,
static_region: 1, static_region: 1,
// due to runtime issues, this can be slow
static_u64: 32,
static_u256: 64, static_u256: 64,
static_address: 40, static_address: 40,
} }

View File

@@ -65,6 +65,7 @@ pub struct FakeExt {
pub schedule: Schedule, pub schedule: Schedule,
pub balances: HashMap<Address, U256>, pub balances: HashMap<Address, U256>,
pub tracing: bool, pub tracing: bool,
pub is_static: bool,
} }
// similar to the normal `finalize` function, but ignoring NeedsReturn. // similar to the normal `finalize` function, but ignoring NeedsReturn.
@@ -192,7 +193,7 @@ impl Ext for FakeExt {
} }
fn is_static(&self) -> bool { fn is_static(&self) -> bool {
false self.is_static
} }
fn inc_sstore_clears(&mut self) { fn inc_sstore_clears(&mut self) {

View File

@@ -8,7 +8,7 @@ byteorder = "1.0"
ethcore-util = { path = "../../util" } ethcore-util = { path = "../../util" }
ethcore-bigint = { path = "../../util/bigint" } ethcore-bigint = { path = "../../util/bigint" }
log = "0.3" log = "0.3"
parity-wasm = "0.14" parity-wasm = "0.15"
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" } wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
vm = { path = "../vm" } vm = { path = "../vm" }
ethcore-logger = { path = "../../logger" } ethcore-logger = { path = "../../logger" }

View File

@@ -25,12 +25,12 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
Static( Static(
"_storage_read", "_storage_read",
&[I32; 2], &[I32; 2],
Some(I32), None,
), ),
Static( Static(
"_storage_write", "_storage_write",
&[I32; 2], &[I32; 2],
Some(I32), None,
), ),
Static( Static(
"_balance", "_balance",
@@ -38,12 +38,12 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
None, None,
), ),
Static( Static(
"_malloc", "_ext_malloc",
&[I32], &[I32],
Some(I32), Some(I32),
), ),
Static( Static(
"_free", "_ext_free",
&[I32], &[I32],
None, None,
), ),
@@ -92,6 +92,21 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
&[I32; 3], &[I32; 3],
Some(I32), Some(I32),
), ),
Static(
"_ext_memcpy",
&[I32; 3],
Some(I32),
),
Static(
"_ext_memset",
&[I32; 3],
Some(I32),
),
Static(
"_ext_memmove",
&[I32; 3],
Some(I32),
),
Static( Static(
"_panic", "_panic",
&[I32; 2], &[I32; 2],
@@ -99,8 +114,8 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
), ),
Static( Static(
"_blockhash", "_blockhash",
&[I32; 3], &[I64, I32],
Some(I32), None,
), ),
Static( Static(
"_coinbase", "_coinbase",
@@ -130,12 +145,12 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
Static( Static(
"_timestamp", "_timestamp",
&[], &[],
Some(I32), Some(I64),
), ),
Static( Static(
"_blocknumber", "_blocknumber",
&[], &[],
Some(I32), Some(I64),
), ),
Static( Static(
"_difficulty", "_difficulty",
@@ -147,6 +162,11 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
&[I32], &[I32],
None, None,
), ),
Static(
"_elog",
&[I32; 4],
None,
),
// TODO: Get rid of it also somehow? // TODO: Get rid of it also somehow?
Static( Static(
@@ -157,8 +177,8 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
Static( Static(
"_llvm_bswap_i64", "_llvm_bswap_i64",
&[I32; 2], &[I64],
Some(I32) Some(I64)
), ),
]; ];

View File

@@ -31,6 +31,7 @@ mod result;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
mod env; mod env;
mod panic_payload;
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024; const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
@@ -115,7 +116,18 @@ impl vm::Vm for WasmInterpreter {
&self.program, &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( let contract_module = wasm_utils::inject_gas_counter(
elements::Module::deserialize( 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; let static_segment_cost = data_section_length * runtime.ext().schedule().wasm.static_region as u64;
runtime.charge(|_| static_segment_cost).map_err(Error)?; runtime.charge(|_| static_segment_cost).map_err(Error)?;
let d_ptr = runtime.write_descriptor(&params.data.unwrap_or_default()) let d_ptr = {
.map_err(Error)?; 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(&params.data.unwrap_or_default())
.map_err(Error)?
}
}
};
{ {
let execution_params = runtime.execution_params() let execution_params = runtime.execution_params()

View 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,
}
);
}
}

View File

@@ -21,6 +21,7 @@ use std::sync::Arc;
use byteorder::{LittleEndian, ByteOrder}; use byteorder::{LittleEndian, ByteOrder};
use vm; use vm;
use panic_payload;
use parity_wasm::interpreter; use parity_wasm::interpreter;
use wasm_utils::rules; use wasm_utils::rules;
use bigint::prelude::U256; use bigint::prelude::U256;
@@ -55,6 +56,8 @@ pub enum UserTrap {
Unknown, Unknown,
/// Passed string had invalid utf-8 encoding /// Passed string had invalid utf-8 encoding
BadUtf8, BadUtf8,
/// Log event error
Log,
/// Other error in native code /// Other error in native code
Other, Other,
/// Panic with message /// Panic with message
@@ -75,6 +78,7 @@ impl ::std::fmt::Display for UserTrap {
UserTrap::AllocationFailed => write!(f, "Memory allocation failed (OOM)"), UserTrap::AllocationFailed => write!(f, "Memory allocation failed (OOM)"),
UserTrap::BadUtf8 => write!(f, "String encoding is bad utf-8 sequence"), UserTrap::BadUtf8 => write!(f, "String encoding is bad utf-8 sequence"),
UserTrap::GasLimit => write!(f, "Invocation resulted in gas limit violated"), 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::Other => write!(f, "Other unspecified error"),
UserTrap::Panic(ref msg) => write!(f, "Panic: {}", msg), 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)?; self.ext.set_storage(key, val).map_err(|_| UserTrap::StorageUpdateError)?;
Ok(Some(0i32.into())) Ok(None)
} }
/// Read from the storage to wasm memory /// 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)?; self.memory.set(val_ptr as u32, &*val)?;
Ok(Some(0.into())) Ok(None)
} }
/// Fetches balance for address /// Fetches balance for address
@@ -221,8 +225,8 @@ impl<'a, 'b> Runtime<'a, 'b> {
} }
/// Charge gas according to closure /// Charge gas according to closure
pub fn charge<F>(&mut self, f: F) -> Result<(), InterpreterError> pub fn charge<F>(&mut self, f: F) -> Result<(), InterpreterError>
where F: FnOnce(&vm::Schedule) -> u64 where F: FnOnce(&vm::Schedule) -> u64
{ {
let amount = f(self.ext.schedule()); let amount = f(self.ext.schedule());
if !self.charge_gas(amount as u64) { 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 /// Invoke create in the state runtime
pub fn create(&mut self, context: InterpreterCallerContext) pub fn create(&mut self, context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> 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(); self.gas_counter = self.gas_limit - gas_left.low_u64();
Ok(Some((-1i32).into())) 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) fn mem_copy(&mut self, context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> 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 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 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)?; self.charge(|schedule| schedule.wasm.mem_copy as u64 * len as u64)?;
let mem = self.memory().get(src, len as usize)?; self.memory().copy_nonoverlapping(src as usize, dst as usize, len as usize)?;
self.memory().set(dst, &mem)?;
Ok(Some(0i32.into())) Ok(Some(Into::into(dst as i32)))
} }
fn bswap_32(x: u32) -> u32 { fn mem_move(&mut self, context: InterpreterCallerContext)
x >> 24 | x >> 8 & 0xff00 | x << 8 & 0xff0000 | x << 24 -> 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) fn bitswap_i64(&mut self, context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
{ {
let x1 = context.value_stack.pop_as::<i32>()?; let x = context.value_stack.pop_as::<i64>()?;
let x2 = context.value_stack.pop_as::<i32>()?; let result = x.swap_bytes();
let result = ((Runtime::bswap_32(x2 as u32) as u64) << 32 Ok(Some(result.into()))
| Runtime::bswap_32(x1 as u32) as u64) as i64;
self.return_i64(result)
} }
fn user_panic(&mut self, context: InterpreterCallerContext) fn user_panic(&mut self, context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
{ {
let msg_len = context.value_stack.pop_as::<i32>()? as u32; let payload_len = context.value_stack.pop_as::<i32>()? as u32;
let msg_ptr = context.value_stack.pop_as::<i32>()? as u32; let payload_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 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); trace!(target: "wasm", "Contract custom panic message: {}", msg);
Err(UserTrap::Panic(msg).into()) Err(UserTrap::Panic(msg).into())
@@ -592,19 +656,16 @@ impl<'a, 'b> Runtime<'a, 'b> {
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
{ {
let return_ptr = context.value_stack.pop_as::<i32>()? as u32; let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
let block_hi = context.value_stack.pop_as::<i32>()? as u32; let block_num = context.value_stack.pop_as::<i64>()? as u64;
let block_lo = context.value_stack.pop_as::<i32>()? as u32;
self.charge(|schedule| schedule.blockhash_gas 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); trace!("Requesting block hash for block #{}", block_num);
let hash = self.ext.blockhash(&U256::from(block_num)); let hash = self.ext.blockhash(&U256::from(block_num));
self.memory.set(return_ptr, &*hash)?; self.memory.set(return_ptr, &*hash)?;
Ok(Some(0i32.into())) Ok(None)
} }
fn return_address_ptr(&mut self, ptr: u32, val: Address) -> Result<(), InterpreterError> 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> { 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.charge(|schedule| schedule.wasm.static_u256 as u64)?;
self.memory.set(ptr, &*value)?; self.memory.set(ptr, &*value)?;
Ok(()) Ok(())
} }
fn coinbase(&mut self, context: InterpreterCallerContext) fn coinbase(&mut self, context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
@@ -640,7 +701,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
sender, sender,
)?; )?;
Ok(None) Ok(None)
} }
fn address(&mut self, context: InterpreterCallerContext) fn address(&mut self, context: InterpreterCallerContext)
@@ -651,7 +712,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
addr, addr,
)?; )?;
Ok(None) Ok(None)
} }
fn origin(&mut self, context: InterpreterCallerContext) fn origin(&mut self, context: InterpreterCallerContext)
@@ -662,7 +723,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
origin, origin,
)?; )?;
Ok(None) Ok(None)
} }
fn value(&mut self, context: InterpreterCallerContext) fn value(&mut self, context: InterpreterCallerContext)
@@ -680,14 +741,14 @@ impl<'a, 'b> Runtime<'a, 'b> {
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
{ {
let timestamp = self.ext.env_info().timestamp as i64; let timestamp = self.ext.env_info().timestamp as i64;
self.return_i64(timestamp) Ok(Some(timestamp.into()))
} }
fn block_number(&mut self, _context: InterpreterCallerContext) fn block_number(&mut self, _context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
{ {
let block_number: u64 = self.ext.env_info().number.into(); let block_number = self.ext.env_info().number as i64;
self.return_i64(block_number as i64) Ok(Some(block_number.into()))
} }
fn difficulty(&mut self, context: InterpreterCallerContext) fn difficulty(&mut self, context: InterpreterCallerContext)
@@ -709,26 +770,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
gas_limit, gas_limit,
)?; )?;
Ok(None) 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()
))
} }
pub fn execution_params(&mut self) -> interpreter::ExecutionParams<UserTrap> { 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 { pub fn ext(&mut self) -> &mut vm::Ext {
self.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> { 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> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
{ {
match name { match name {
"_malloc" => { "_ext_malloc" => {
self.malloc(context) self.malloc(context)
}, },
"_free" => { "_ext_free" => {
// Since it is arena allocator, free does nothing // Since it is arena allocator, free does nothing
// todo: update if changed // todo: update if changed
self.user_noop(context) self.user_noop(context)
@@ -801,6 +881,15 @@ impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
"_emscripten_memcpy_big" => { "_emscripten_memcpy_big" => {
self.mem_copy(context) 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" => { "_llvm_bswap_i64" => {
self.bitswap_i64(context) self.bitswap_i64(context)
}, },
@@ -837,6 +926,9 @@ impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
"_value" => { "_value" => {
self.value(context) self.value(context)
}, },
"_elog" => {
self.log(context)
},
_ => { _ => {
trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name); trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name);
Ok(self.unknown_trap(context)?) Ok(self.unknown_trap(context)?)

View File

@@ -60,7 +60,7 @@ fn empty() {
test_finalize(interpreter.exec(params, &mut ext)).unwrap() 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. // This test checks if the contract deserializes payload header properly.
@@ -89,7 +89,6 @@ fn logger() {
test_finalize(interpreter.exec(params, &mut ext)).unwrap() test_finalize(interpreter.exec(params, &mut ext)).unwrap()
}; };
assert_eq!(gas_left, U256::from(15_177));
let address_val: H256 = address.into(); let address_val: H256 = address.into();
assert_eq!( assert_eq!(
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"), ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
@@ -113,6 +112,7 @@ fn logger() {
U256::from(1_000_000_000), U256::from(1_000_000_000),
"Logger sets 0x04 key to the trasferred value" "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. // 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!( assert_eq!(
Address::from_slice(&result), Address::from_slice(&result),
sender, sender,
"Idenity test contract does not return the sender passed" "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 // 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!( assert_eq!(
result, result,
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0] vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
); );
assert_eq!(gas_left, U256::from(96_393));
} }
#[test] #[test]
@@ -205,12 +204,11 @@ fn suicide_not() {
} }
}; };
assert_eq!(gas_left, U256::from(96_822));
assert_eq!( assert_eq!(
result, result,
vec![0u8] vec![0u8]
); );
assert_eq!(gas_left, U256::from(96_725));
} }
#[test] #[test]
@@ -241,8 +239,8 @@ fn suicide() {
} }
}; };
assert_eq!(gas_left, U256::from(96_580));
assert!(ext.suicides.contains(&refund)); assert!(ext.suicides.contains(&refund));
assert_eq!(gas_left, U256::from(96_687));
} }
#[test] #[test]
@@ -272,7 +270,7 @@ fn create() {
assert!(ext.calls.contains( assert!(ext.calls.contains(
&FakeCall { &FakeCall {
call_type: FakeCallType::Create, call_type: FakeCallType::Create,
gas: U256::from(62_324), gas: U256::from(65_899),
sender_address: None, sender_address: None,
receive_address: None, receive_address: None,
value: Some(1_000_000_000.into()), value: Some(1_000_000_000.into()),
@@ -280,7 +278,7 @@ fn create() {
code_address: None, 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( assert!(ext.calls.contains(
&FakeCall { &FakeCall {
call_type: FakeCallType::Call, call_type: FakeCallType::Call,
gas: U256::from(95_585), gas: U256::from(98_713),
sender_address: Some(sender), sender_address: Some(sender),
receive_address: Some(receiver), receive_address: Some(receiver),
value: None, value: None,
@@ -322,11 +320,11 @@ fn call_code() {
code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()), code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()),
} }
)); ));
assert_eq!(gas_left, U256::from(90_665));
// siphash result // siphash result
let res = LittleEndian::read_u32(&result[..]); let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 4198595614); assert_eq!(res, 4198595614);
assert_eq!(gas_left, U256::from(93_855));
} }
#[test] #[test]
@@ -359,7 +357,7 @@ fn call_static() {
assert!(ext.calls.contains( assert!(ext.calls.contains(
&FakeCall { &FakeCall {
call_type: FakeCallType::Call, call_type: FakeCallType::Call,
gas: U256::from(95_585), gas: U256::from(98_713),
sender_address: Some(sender), sender_address: Some(sender),
receive_address: Some(receiver), receive_address: Some(receiver),
value: None, value: None,
@@ -367,11 +365,12 @@ fn call_static() {
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()), code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
} }
)); ));
assert_eq!(gas_left, U256::from(90_665));
// siphash result // siphash result
let res = LittleEndian::read_u32(&result[..]); let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 317632590); assert_eq!(res, 317632590);
assert_eq!(gas_left, U256::from(93_855));
} }
// Realloc test // Realloc test
@@ -393,8 +392,8 @@ fn realloc() {
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), 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!(result, vec![0u8; 2]);
assert_eq!(gas_left, U256::from(96_723));
} }
// Tests that contract's ability to read from a storage // 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!(Address::from(&result[12..32]), address);
assert_eq!(gas_left, U256::from(99_767));
} }
// Tests keccak calculation // Tests keccak calculation
@@ -446,9 +445,97 @@ fn keccak() {
}; };
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87")); 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 { macro_rules! reqrep_test {
($name: expr, $input: expr) => { ($name: expr, $input: expr) => {
@@ -500,11 +587,11 @@ fn math_add() {
} }
).expect("Interpreter to execute without any errors"); ).expect("Interpreter to execute without any errors");
assert_eq!(gas_left, U256::from(94_666));
assert_eq!( assert_eq!(
U256::from_dec_str("1888888888888888888888888888887").unwrap(), U256::from_dec_str("1888888888888888888888888888887").unwrap(),
(&result[..]).into() (&result[..]).into()
); );
assert_eq!(gas_left, U256::from(95_524));
} }
// multiplication // multiplication
@@ -522,11 +609,11 @@ fn math_mul() {
} }
).expect("Interpreter to execute without any errors"); ).expect("Interpreter to execute without any errors");
assert_eq!(gas_left, U256::from(93_719));
assert_eq!( assert_eq!(
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(), U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
(&result[..]).into() (&result[..]).into()
); );
assert_eq!(gas_left, U256::from(94_674));
} }
// subtraction // subtraction
@@ -544,11 +631,11 @@ fn math_sub() {
} }
).expect("Interpreter to execute without any errors"); ).expect("Interpreter to execute without any errors");
assert_eq!(gas_left, U256::from(94_718));
assert_eq!( assert_eq!(
U256::from_dec_str("111111111111111111111111111111").unwrap(), U256::from_dec_str("111111111111111111111111111111").unwrap(),
(&result[..]).into() (&result[..]).into()
); );
assert_eq!(gas_left, U256::from(95_516));
} }
// subtraction with overflow // 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] #[test]
@@ -583,11 +673,11 @@ fn math_div() {
} }
).expect("Interpreter to execute without any errors"); ).expect("Interpreter to execute without any errors");
assert_eq!(gas_left, U256::from(86_996));
assert_eq!( assert_eq!(
U256::from_dec_str("1125000").unwrap(), U256::from_dec_str("1125000").unwrap(),
(&result[..]).into() (&result[..]).into()
); );
assert_eq!(gas_left, U256::from(88_514));
} }
// This test checks the ability of wasm contract to invoke // This test checks the ability of wasm contract to invoke
@@ -675,5 +765,66 @@ fn externs() {
"Gas limit requested and returned does not match" "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));
} }

View File

@@ -122,6 +122,13 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
Ok(hasher.finish()) 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 /// all accounts found in keys directory
fn files_content(&self) -> Result<HashMap<PathBuf, SafeAccount>, Error> { fn files_content(&self) -> Result<HashMap<PathBuf, SafeAccount>, Error> {
// it's not done using one iterator cause // 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> { fn unique_repr(&self) -> Result<u64, Error> {
self.files_hash() self.last_modification_date()
} }
} }

View File

@@ -18,6 +18,7 @@ use std::collections::{BTreeMap, HashMap};
use std::mem; use std::mem;
use std::path::PathBuf; use std::path::PathBuf;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use std::time::{Instant, Duration};
use crypto::KEY_ITERATIONS; use crypto::KEY_ITERATIONS;
use random::Random; use random::Random;
@@ -28,6 +29,8 @@ use presale::PresaleWallet;
use json::{self, Uuid, OpaqueKeyFile}; use json::{self, Uuid, OpaqueKeyFile};
use {import, Error, SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation, OpaqueSecret}; use {import, Error, SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation, OpaqueSecret};
const REFRESH_TIME_SEC: u64 = 5;
/// Accounts store. /// Accounts store.
pub struct EthStore { pub struct EthStore {
store: EthMultiStore, store: EthMultiStore,
@@ -245,7 +248,12 @@ pub struct EthMultiStore {
// order lock: cache, then vaults // order lock: cache, then vaults
cache: RwLock<BTreeMap<StoreAccountRef, Vec<SafeAccount>>>, cache: RwLock<BTreeMap<StoreAccountRef, Vec<SafeAccount>>>,
vaults: Mutex<HashMap<String, Box<VaultKeyDirectory>>>, 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 { impl EthMultiStore {
@@ -261,20 +269,27 @@ impl EthMultiStore {
vaults: Mutex::new(HashMap::new()), vaults: Mutex::new(HashMap::new()),
iterations: iterations, iterations: iterations,
cache: Default::default(), cache: Default::default(),
dir_hash: Default::default(), timestamp: Mutex::new(Timestamp {
dir_hash: None,
last_checked: Instant::now(),
}),
}; };
store.reload_accounts()?; store.reload_accounts()?;
Ok(store) Ok(store)
} }
fn reload_if_changed(&self) -> Result<(), Error> { fn reload_if_changed(&self) -> Result<(), Error> {
let mut last_dir_hash = self.dir_hash.lock(); let mut last_timestamp = self.timestamp.lock();
let dir_hash = Some(self.dir.unique_repr()?); let now = Instant::now();
if *last_dir_hash == dir_hash { if (now - last_timestamp.last_checked) > Duration::from_secs(REFRESH_TIME_SEC) {
return Ok(()) 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(()) Ok(())
} }
@@ -455,11 +470,11 @@ impl SimpleSecretStore for EthMultiStore {
} }
fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error> { fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error> {
use std::collections::Bound;
self.reload_if_changed()?; self.reload_if_changed()?;
self.cache.read().keys() let cache = self.cache.read();
.find(|r| &r.address == address) let mut r = cache.range((Bound::Included(*address), Bound::Included(*address)));
.cloned() r.next().ok_or(Error::InvalidAccount).map(|(k, _)| k.clone())
.ok_or(Error::InvalidAccount)
} }
fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error> { fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error> {

View File

@@ -16,6 +16,7 @@
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::path::PathBuf; use std::path::PathBuf;
use std::cmp::Ordering;
use ethkey::{Address, Message, Signature, Secret, Public}; use ethkey::{Address, Message, Signature, Secret, Public};
use Error; use Error;
use json::{Uuid, OpaqueKeyFile}; use json::{Uuid, OpaqueKeyFile};
@@ -32,12 +33,24 @@ pub enum SecretVaultRef {
} }
/// Stored account reference /// Stored account reference
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Ord)]
pub struct StoreAccountRef { pub struct StoreAccountRef {
/// Vault reference
pub vault: SecretVaultRef,
/// Account address /// Account address
pub address: 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 /// Simple Secret Store API

View File

@@ -37,8 +37,8 @@ use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumT
const TREZOR_VID: u16 = 0x534c; 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 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 ETH_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003C, 0x80000000, 0, 0]; // m/44'/60'/0'/0/0
const ETC_DERIVATION_PATH: [u32; 4] = [0x8000002C, 0x8000003D, 0x80000000, 0]; // m/44'/61'/0'/0 const ETC_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003D, 0x80000000, 0, 0]; // m/44'/61'/0'/0/0
/// Hardware wallet error. /// Hardware wallet error.

View File

@@ -17,35 +17,35 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { walletSourceURL } from '~/contracts/code/wallet'; // import { walletSourceURL } from '~/contracts/code/wallet';
import { RadioButtons } from '~/ui'; import { RadioButtons } from '~/ui';
const TYPES = [ const TYPES = [
{ // {
label: ( // label: (
<FormattedMessage // <FormattedMessage
id='createWallet.type.multisig.label' // id='createWallet.type.multisig.label'
defaultMessage='Multi-Sig wallet' // defaultMessage='Multi-Sig wallet'
/> // />
), // ),
key: 'MULTISIG', // key: 'MULTISIG',
description: ( // description: (
<FormattedMessage // <FormattedMessage
id='createWallet.type.multisig.description' // id='createWallet.type.multisig.description'
defaultMessage='Create/Deploy a {link} Wallet' // defaultMessage='Create/Deploy a {link} Wallet'
values={ { // values={ {
link: ( // link: (
<a href={ walletSourceURL } target='_blank'> // <a href={ walletSourceURL } target='_blank'>
<FormattedMessage // <FormattedMessage
id='createWallet.type.multisig.link' // id='createWallet.type.multisig.link'
defaultMessage='standard multi-signature' // defaultMessage='standard multi-signature'
/> // />
</a> // </a>
) // )
} } // } }
/> // />
) // )
}, // },
{ {
label: ( label: (
<FormattedMessage <FormattedMessage

View File

@@ -59,7 +59,7 @@ const STEPS = {
export default class CreateWalletStore { export default class CreateWalletStore {
@observable step = null; @observable step = null;
@observable txhash = null; @observable txhash = null;
@observable walletType = 'MULTISIG'; @observable walletType = 'WATCH'; // 'MULTISIG';
@observable wallet = { @observable wallet = {
account: '', account: '',

View File

@@ -206,7 +206,7 @@ export default class CertifiersMonitor {
// Fetch the address, name and owner in one batch // Fetch the address, name and owner in one batch
return querier(this.api, { address: instance.address, from, limit }, instance.badge) return querier(this.api, { address: instance.address, from, limit }, instance.badge)
.then((results) => { .then((results) => {
this.certifiers = results const certifiers = results
.map(([ address, name, owner ], index) => ({ .map(([ address, name, owner ], index) => ({
address, owner, address, owner,
id: index + from, id: index + from,
@@ -225,7 +225,7 @@ export default class CertifiersMonitor {
}, {}); }, {});
// Fetch the meta-data in serie // 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)) return promise.then(() => badgeReg.fetchMeta(certifier.id))
.then((meta) => { .then((meta) => {
this.certifiers[certifier.id] = { ...certifier, ...meta }; this.certifiers[certifier.id] = { ...certifier, ...meta };
@@ -274,8 +274,6 @@ export default class CertifiersMonitor {
.then((certified) => { .then((certified) => {
const { id, title, icon, name } = certifier; const { id, title, icon, name } = certifier;
this.fetchedAccounts[address] = true;
if (!certified) { if (!certified) {
return this.store.dispatch(removeCertification(address, id)); return this.store.dispatch(removeCertification(address, id));
} }
@@ -283,7 +281,10 @@ export default class CertifiersMonitor {
log.debug('seen as certified', { address, id, name, icon }); log.debug('seen as certified', { address, id, name, icon });
this.store.dispatch(addCertification(address, id, name, title, icon)); this.store.dispatch(addCertification(address, id, name, title, icon));
}); });
}, Promise.resolve()); }, Promise.resolve())
.then(() => {
this.fetchedAccounts[address] = true;
});
} }
setCertifiersFilter () { setCertifiersFilter () {

View File

@@ -71,7 +71,6 @@ function loadCachedTokens (tokenRegContract) {
// Check if we have data from the right contract // Check if we have data from the right contract
if (cached.tokenreg === tokenRegContract.address && cached.tokens) { if (cached.tokenreg === tokenRegContract.address && cached.tokens) {
log.debug('found cached tokens', cached.tokens); log.debug('found cached tokens', cached.tokens);
dispatch(_setTokens(cached.tokens));
// Fetch all the tokens images on load // Fetch all the tokens images on load
// (it's the only thing that might have changed) // (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; const limit = 64;
return (dispatch, getState) => { return (dispatch, getState) => {
const { api, tokens } = getState(); const { api } = getState();
const { tokenReg } = Contracts.get(); const { tokenReg } = Contracts.get();
const nextTokens = {}; 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; const count = tokenIndexes.length;
log.debug('loading basic tokens', tokenIndexes); log.debug('loading basic tokens', tokenIndexes);
@@ -240,6 +230,7 @@ function fetchTokensData (tokenRegContract, tokenIndexes) {
log.debug('fetched', { fullResults, partialResults }); log.debug('fetched', { fullResults, partialResults });
return [].concat(fullResults, partialResults) return [].concat(fullResults, partialResults)
.filter(({ address }) => !/0x0*$/.test(address))
.reduce((tokens, token) => { .reduce((tokens, token) => {
const { id, image, address } = token; const { id, image, address } = token;

View File

@@ -32,14 +32,19 @@ class TokenImage extends Component {
}).isRequired }).isRequired
}; };
state = {
error: false
};
render () { render () {
const { error } = this.state;
const { api } = this.context; const { api } = this.context;
const { image, token } = this.props; const { image, token } = this.props;
const imageurl = token.image || image; const imageurl = token.image || image;
let imagesrc = unknownImage; let imagesrc = unknownImage;
if (imageurl) { if (imageurl && !error) {
const host = /^(\/)?api/.test(imageurl) const host = /^(\/)?api/.test(imageurl)
? api.dappsUrl ? api.dappsUrl
: ''; : '';
@@ -49,11 +54,16 @@ class TokenImage extends Component {
return ( return (
<img <img
src={ imagesrc }
alt={ token.name } alt={ token.name }
onError={ this.handleError }
src={ imagesrc }
/> />
); );
} }
handleError = () => {
this.setState({ error: true });
};
} }
function mapStateToProps (iniState) { function mapStateToProps (iniState) {

View File

@@ -55,9 +55,14 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
return api.eth return api.eth
.call({ data: tokenAddressesBytcode + tokenAddressesCallData }) .call({ data: tokenAddressesBytcode + tokenAddressesCallData })
.then((result) => { .then((result) => {
const tokenAddresses = decodeArray(api, 'address[]', result); return decodeArray(api, 'address[]', result);
})
.then((tokenAddresses) => {
return tokenAddresses.map((tokenAddress, index) => { return tokenAddresses.map((tokenAddress, index) => {
if (/^0x0*$/.test(tokenAddress)) {
return null;
}
const tokenIndex = start + index; const tokenIndex = start + index;
return { return {
@@ -68,6 +73,17 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
fetched: false 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));
});
}); });
} }

View File

@@ -43,6 +43,12 @@ pub struct AuthorityRoundParams {
/// Reward per block in wei. /// Reward per block in wei.
#[serde(rename="blockReward")] #[serde(rename="blockReward")]
pub block_reward: Option<Uint>, 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. /// Authority engine deserialization.
@@ -71,7 +77,9 @@ mod tests {
}, },
"startStep" : 24, "startStep" : 24,
"validateStepTransition": 150, "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.validators, ValidatorSet::List(vec![Address(H160::from("0xc6d9d2cd449a754c494264e1809c50e34d64562b"))]));
assert_eq!(deserialized.params.start_step, Some(Uint(U256::from(24)))); assert_eq!(deserialized.params.start_step, Some(Uint(U256::from(24))));
assert_eq!(deserialized.params.immediate_transitions, None); 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())));
} }
} }

View File

@@ -58,6 +58,9 @@ pub struct Params {
#[serde(rename="eip155Transition")] #[serde(rename="eip155Transition")]
pub eip155_transition: Option<Uint>, pub eip155_transition: Option<Uint>,
/// See `CommonParams` docs. /// See `CommonParams` docs.
#[serde(rename="validateChainIdTransition")]
pub validate_chain_id_transition: Option<Uint>,
/// See `CommonParams` docs.
#[serde(rename="validateReceiptsTransition")] #[serde(rename="validateReceiptsTransition")]
pub validate_receipts_transition: Option<Uint>, pub validate_receipts_transition: Option<Uint>,
/// See `CommonParams` docs. /// See `CommonParams` docs.

View File

@@ -462,7 +462,7 @@
<key>OVERWRITE_PERMISSIONS</key> <key>OVERWRITE_PERMISSIONS</key>
<false/> <false/>
<key>VERSION</key> <key>VERSION</key>
<string>1.8.0</string> <string>1.8.4</string>
</dict> </dict>
<key>UUID</key> <key>UUID</key>
<string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string> <string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string>

View File

@@ -10,9 +10,9 @@
!define DESCRIPTION "Fast, light, robust Ethereum implementation" !define DESCRIPTION "Fast, light, robust Ethereum implementation"
!define VERSIONMAJOR 1 !define VERSIONMAJOR 1
!define VERSIONMINOR 8 !define VERSIONMINOR 8
!define VERSIONBUILD 0 !define VERSIONBUILD 4
!define ARGS "--warp" !define ARGS ""
!define FIRST_START_ARGS "ui --warp --mode=passive" !define FIRST_START_ARGS "--mode=passive ui"
!addplugindir .\ !addplugindir .\

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -24,6 +24,7 @@ usage! {
// Subcommands must start with cmd_ and have '_' in place of '-' // Subcommands must start with cmd_ and have '_' in place of '-'
// Sub-subcommands must start with the name of the subcommand // Sub-subcommands must start with the name of the subcommand
// Arguments must start with arg_ // Arguments must start with arg_
// Flags must start with flag_
CMD cmd_ui { CMD cmd_ui {
"Manage ui", "Manage ui",
@@ -53,10 +54,6 @@ usage! {
CMD cmd_account_new { CMD cmd_account_new {
"Create a new acount", "Create a new acount",
ARG arg_account_new_password: (Option<String>) = None,
"--password=[FILE]",
"Path to the password file",
} }
CMD cmd_account_list { CMD cmd_account_list {
@@ -81,10 +78,6 @@ usage! {
{ {
"Import wallet", "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, ARG arg_wallet_import_path: (Option<String>) = None,
"<PATH>", "<PATH>",
"Path to the wallet", "Path to the wallet",
@@ -179,10 +172,6 @@ usage! {
{ {
"Sign", "Sign",
ARG arg_signer_sign_password: (Option<String>) = None,
"--password=[FILE]",
"Path to the password file",
ARG arg_signer_sign_id: (Option<usize>) = None, ARG arg_signer_sign_id: (Option<usize>) = None,
"[ID]", "[ID]",
"ID", "ID",
@@ -244,7 +233,7 @@ usage! {
} }
} }
{ {
// Flags and arguments // Global flags and arguments
["Operating Options"] ["Operating Options"]
FLAG flag_public_node: (bool) = false, or |c: &Config| otry!(c.parity).public_node.clone(), FLAG flag_public_node: (bool) = false, or |c: &Config| otry!(c.parity).public_node.clone(),
"--public-node", "--public-node",
@@ -353,7 +342,6 @@ usage! {
ARG arg_password: (Vec<String>) = Vec::new(), or |c: &Config| otry!(c.account).password.clone(), ARG arg_password: (Vec<String>) = Vec::new(), or |c: &Config| otry!(c.account).password.clone(),
"--password=[FILE]...", "--password=[FILE]...",
"Provide a file containing a password for unlocking an account. Leading and trailing whitespace is trimmed.", "Provide a file containing a password for unlocking an account. Leading and trailing whitespace is trimmed.",
["UI options"] ["UI options"]
FLAG flag_force_ui: (bool) = false, or |c: &Config| otry!(c.ui).force.clone(), FLAG flag_force_ui: (bool) = false, or |c: &Config| otry!(c.ui).force.clone(),
"--force-ui", "--force-ui",
@@ -836,6 +824,10 @@ usage! {
"Target size of the whisper message pool in megabytes.", "Target size of the whisper message pool in megabytes.",
["Legacy options"] ["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, FLAG flag_dapps_apis_all: (bool) = false, or |_| None,
"--dapps-apis-all", "--dapps-apis-all",
"Dapps server is merged with RPC server. Use --jsonrpc-apis.", "Dapps server is merged with RPC server. Use --jsonrpc-apis.",
@@ -1203,6 +1195,39 @@ mod tests {
use toml; use toml;
use clap::{ErrorKind as ClapErrorKind}; 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] #[test]
fn should_parse_args_and_flags() { fn should_parse_args_and_flags() {
let args = Args::parse(&["parity", "--no-warp"]).unwrap(); let args = Args::parse(&["parity", "--no-warp"]).unwrap();
@@ -1365,9 +1390,6 @@ mod tests {
arg_restore_file: None, arg_restore_file: None,
arg_tools_hash_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_sign_id: None,
arg_signer_reject_id: None, arg_signer_reject_id: None,
arg_dapp_path: None, arg_dapp_path: None,
@@ -1549,6 +1571,7 @@ mod tests {
arg_whisper_pool_size: 20, arg_whisper_pool_size: 20,
// -- Legacy Options // -- Legacy Options
flag_warp: false,
flag_geth: false, flag_geth: false,
flag_testnet: false, flag_testnet: false,
flag_import_geth_keys: false, flag_import_geth_keys: false,

View File

@@ -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 { macro_rules! if_option {
(Option<$type:ty>, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => ( (Option<$type:ty>, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
$($then)* $($then)*
@@ -139,7 +153,7 @@ macro_rules! usage {
use std::{fs, io, process}; use std::{fs, io, process};
use std::io::{Read, Write}; use std::io::{Read, Write};
use util::version; 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 helpers::replace_home;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::collections::HashMap; use std::collections::HashMap;
@@ -489,6 +503,36 @@ macro_rules! usage {
args 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 #[allow(unused_variables)] // the submatches of arg-less subcommands aren't used
pub fn parse<S: AsRef<str>>(command: &[S]) -> Result<Self, ClapError> { 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..])) SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc)[4..]))
.about($subc_help) .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(&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` .setting(AppSettings::SubcommandRequired) // prevent from running `parity account`
.subcommand( .subcommand(
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])) SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]))
.about($subc_subc_help) .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(&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())))?; .get_matches_from_safe(command.iter().map(|x| OsStr::new(x.as_ref())))?;
let mut raw_args : RawArgs = Default::default(); let mut raw_args : RawArgs = Default::default();
$(
$( raw_args.hydrate_with_globals(&matches)?;
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() }
)
}
);
)*
)*
// Subcommands // Subcommands
$( $(
if let Some(submatches) = matches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc)[4..])) { if let Some(submatches) = matches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc)[4..])) {
raw_args.$subc = true; raw_args.$subc = true;
// Globals
raw_args.hydrate_with_globals(&submatches)?;
// Subcommand flags // Subcommand flags
$( $(
raw_args.$subc_flag = submatches.is_present(&stringify!($subc_flag)); raw_args.$subc_flag = submatches.is_present(&stringify!($subc_flag));
)* )*
// Subcommand arguments // Subcommand arguments
$( $(
raw_args.$subc_arg = if_option!( raw_args.$subc_arg = return_if_parse_error!(if_option!(
$($subc_arg_type_tt)+, $($subc_arg_type_tt)+,
THEN { THEN {
if_option_vec!( if_option_vec!(
$($subc_arg_type_tt)+, $($subc_arg_type_tt)+,
THEN { values_t!(submatches, stringify!($subc_arg), inner_option_vec_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)+)).ok() } ELSE { value_t!(submatches, stringify!($subc_arg), inner_option_type!($($subc_arg_type_tt)+)) }
) )
} }
ELSE { ELSE {
if_vec!( if_vec!(
$($subc_arg_type_tt)+, $($subc_arg_type_tt)+,
THEN { values_t!(submatches, stringify!($subc_arg), inner_vec_type!($($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)+).ok() } ELSE { value_t!(submatches, stringify!($subc_arg), $($subc_arg_type_tt)+) }
) )
} }
); ));
)* )*
// Sub-subcommands // Sub-subcommands
$( $(
if let Some(subsubmatches) = submatches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])) { if let Some(subsubmatches) = submatches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])) {
raw_args.$subc_subc = true; raw_args.$subc_subc = true;
// Globals
raw_args.hydrate_with_globals(&subsubmatches)?;
// Sub-subcommand flags // Sub-subcommand flags
$( $(
raw_args.$subc_subc_flag = subsubmatches.is_present(&stringify!($subc_subc_flag)); raw_args.$subc_subc_flag = subsubmatches.is_present(&stringify!($subc_subc_flag));
)* )*
// Sub-subcommand arguments // 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)+, $($subc_subc_arg_type_tt)+,
THEN { THEN {
if_option_vec!( if_option_vec!(
$($subc_subc_arg_type_tt)+, $($subc_subc_arg_type_tt)+,
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_vec_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)+)).ok() } ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_type!($($subc_subc_arg_type_tt)+)) }
) )
} }
ELSE { ELSE {
if_vec!( if_vec!(
$($subc_subc_arg_type_tt)+, $($subc_subc_arg_type_tt)+,
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_vec_type!($($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)+).ok() } ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), $($subc_subc_arg_type_tt)+) }
) )
} }
); ));
)* )*
} }
else { else {

View File

@@ -40,7 +40,7 @@ use parity_rpc::NetworkSettings;
use cache::CacheConfig; 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, 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}; 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 ethcore_logger::Config as LogConfig;
use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path};
use dapps::Configuration as DappsConfiguration; use dapps::Configuration as DappsConfiguration;
@@ -109,7 +109,7 @@ impl Configuration {
let pruning = self.args.arg_pruning.parse()?; let pruning = self.args.arg_pruning.parse()?;
let pruning_history = self.args.arg_pruning_history; let pruning_history = self.args.arg_pruning_history;
let vm_type = self.vm_type()?; let vm_type = self.vm_type()?;
let spec = self.chain().parse()?; let spec = self.chain()?;
let mode = match self.args.arg_mode.as_ref() { let mode = match self.args.arg_mode.as_ref() {
"last" => None, "last" => None,
mode => Some(to_mode(&mode, self.args.arg_mode_timeout, self.args.arg_mode_alarm)?), 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 { if self.args.cmd_signer_new_token {
Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone()) Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone())
} else if self.args.cmd_signer_sign { } 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) PathBuf::from(pwfile)
}); });
Cmd::SignerSign { Cmd::SignerSign {
@@ -180,7 +180,7 @@ impl Configuration {
iterations: self.args.arg_keys_iterations, iterations: self.args.arg_keys_iterations,
path: dirs.keys, path: dirs.keys,
spec: spec, 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) AccountCmd::New(new_acc)
} else if self.args.cmd_account_list { } else if self.args.cmd_account_list {
@@ -215,7 +215,7 @@ impl Configuration {
path: dirs.keys, path: dirs.keys,
spec: spec, spec: spec,
wallet_path: self.args.arg_wallet_import_path.unwrap().clone(), 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) Cmd::ImportPresaleWallet(presale_cmd)
} else if self.args.cmd_import { } else if self.args.cmd_import {
@@ -336,7 +336,7 @@ impl Configuration {
pruning_memory: self.args.arg_pruning_memory, pruning_memory: self.args.arg_pruning_memory,
daemon: daemon, daemon: daemon,
logger_config: logger_config.clone(), 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(), ntp_servers: self.ntp_servers(),
ws_conf: ws_conf, ws_conf: ws_conf,
http_conf: http_conf, http_conf: http_conf,
@@ -441,15 +441,16 @@ impl Configuration {
} }
} }
fn chain(&self) -> String { fn chain(&self) -> Result<SpecType, String> {
if let Some(ref s) = self.spec_name_override { let name = if let Some(ref s) = self.spec_name_override {
s.clone() s.clone()
} } else if self.args.flag_testnet {
else if self.args.flag_testnet {
"testnet".to_owned() "testnet".to_owned()
} else { } else {
self.args.arg_chain.clone() self.args.arg_chain.clone()
} };
Ok(name.parse()?)
} }
fn max_peers(&self) -> u32 { fn max_peers(&self) -> u32 {
@@ -504,8 +505,9 @@ impl Configuration {
} else { Ok(None) } } else { Ok(None) }
} }
fn miner_options(&self, reseal_min_period: u64) -> Result<MinerOptions, String> { fn miner_options(&self) -> Result<MinerOptions, String> {
if self.args.flag_force_sealing && reseal_min_period == 0 { 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()); 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_gas_limit: to_gas_limit(&self.args.arg_tx_queue_gas)?,
tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?, tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?,
pending_set: to_pending_set(&self.args.arg_relay_set)?, 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), reseal_max_period: Duration::from_millis(self.args.arg_reseal_max_period),
work_queue_size: self.args.arg_work_queue_size, work_queue_size: self.args.arg_work_queue_size,
enable_resubmission: !self.args.flag_remove_solved, enable_resubmission: !self.args.flag_remove_solved,
@@ -883,7 +885,7 @@ impl Configuration {
let net_addresses = self.net_addresses()?; let net_addresses = self.net_addresses()?;
Ok(NetworkSettings { Ok(NetworkSettings {
name: self.args.arg_identity.clone(), name: self.args.arg_identity.clone(),
chain: self.chain(), chain: format!("{}", self.chain()?),
network_port: net_addresses.0.port(), network_port: net_addresses.0.port(),
rpc_enabled: http_conf.enabled, rpc_enabled: http_conf.enabled,
rpc_interface: http_conf.interface, rpc_interface: http_conf.interface,
@@ -914,8 +916,6 @@ impl Configuration {
} }
fn directories(&self) -> Directories { fn directories(&self) -> Directories {
use path;
let local_path = default_local_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 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); let data_path = replace_home("", &base_path);
@@ -935,21 +935,6 @@ impl Configuration {
let secretstore_path = replace_home(&data_path, &self.args.arg_secretstore_path); let secretstore_path = replace_home(&data_path, &self.args.arg_secretstore_path);
let ui_path = replace_home(&data_path, &self.args.arg_ui_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 { Directories {
keys: keys_path, keys: keys_path,
base: data_path, base: data_path,
@@ -1401,21 +1386,20 @@ mod tests {
let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]); let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]);
// then // then
let min_period = conf0.args.arg_reseal_min_period; assert_eq!(conf0.miner_options().unwrap(), mining_options);
assert_eq!(conf0.miner_options(min_period).unwrap(), mining_options);
mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice; 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; 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; 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] #[test]
fn should_fail_on_force_reseal_and_reseal_min_period() { 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] #[test]
@@ -1443,7 +1427,7 @@ mod tests {
// then // then
assert_eq!(conf.network_settings(), Ok(NetworkSettings { assert_eq!(conf.network_settings(), Ok(NetworkSettings {
name: "testname".to_owned(), name: "testname".to_owned(),
chain: "testnet".to_owned(), chain: "kovan".to_owned(),
network_port: 30303, network_port: 30303,
rpc_enabled: true, rpc_enabled: true,
rpc_interface: "127.0.0.1".to_owned(), rpc_interface: "127.0.0.1".to_owned(),

View File

@@ -195,9 +195,7 @@ mod server {
pub struct Middleware; pub struct Middleware;
impl RequestMiddleware for Middleware { impl RequestMiddleware for Middleware {
fn on_request( fn on_request(&self, _req: hyper::Request) -> RequestMiddlewareAction {
&self, _req: &hyper::server::Request<hyper::net::HttpStream>, _control: &hyper::Control
) -> RequestMiddlewareAction {
unreachable!() unreachable!()
} }
} }

View File

@@ -37,6 +37,10 @@ impl fmt::Display for Deprecated {
pub fn find_deprecated(args: &Args) -> Vec<Deprecated> { pub fn find_deprecated(args: &Args) -> Vec<Deprecated> {
let mut result = vec![]; let mut result = vec![];
if args.flag_warp {
result.push(Deprecated::DoesNothing("--warp"));
}
if args.flag_jsonrpc { if args.flag_jsonrpc {
result.push(Deprecated::DoesNothing("--jsonrpc")); result.push(Deprecated::DoesNothing("--jsonrpc"));
} }
@@ -117,6 +121,7 @@ mod tests {
assert_eq!(find_deprecated(&Args::default()), vec![]); assert_eq!(find_deprecated(&Args::default()), vec![]);
assert_eq!(find_deprecated(&{ assert_eq!(find_deprecated(&{
let mut args = Args::default(); let mut args = Args::default();
args.flag_warp = true;
args.flag_jsonrpc = true; args.flag_jsonrpc = true;
args.flag_rpc = true; args.flag_rpc = true;
args.flag_jsonrpc_off = true; args.flag_jsonrpc_off = true;
@@ -135,6 +140,7 @@ mod tests {
args.flag_dapps_apis_all = true; args.flag_dapps_apis_all = true;
args args
}), vec![ }), vec![
Deprecated::DoesNothing("--warp"),
Deprecated::DoesNothing("--jsonrpc"), Deprecated::DoesNothing("--jsonrpc"),
Deprecated::DoesNothing("--rpc"), Deprecated::DoesNothing("--rpc"),
Deprecated::Replaced("--jsonrpc-off", "--no-jsonrpc"), Deprecated::Replaced("--jsonrpc-off", "--no-jsonrpc"),

View File

@@ -301,6 +301,16 @@ pub fn new_ipc<D: rpc_apis::Dependencies>(
let handler = setup_apis(conf.apis, dependencies); let handler = setup_apis(conf.apis, dependencies);
let remote = dependencies.remote.clone(); 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) { match rpc::start_ipc(&conf.socket_addr, handler, remote, rpc::RpcExtractor) {
Ok(server) => Ok(Some(server)), Ok(server) => Ok(Some(server)),
Err(io_error) => Err(format!("IPC error: {}", io_error)), Err(io_error) => Err(format!("IPC error: {}", io_error)),

View File

@@ -71,6 +71,9 @@ pub trait Dispatcher: Send + Sync + Clone {
fn sign(&self, accounts: Arc<AccountProvider>, filled: FilledTransactionRequest, password: SignWith) fn sign(&self, accounts: Arc<AccountProvider>, filled: FilledTransactionRequest, password: SignWith)
-> BoxFuture<WithToken<SignedTransaction>, Error>; -> BoxFuture<WithToken<SignedTransaction>, Error>;
/// Converts a `SignedTransaction` into `RichRawTransaction`
fn enrich(&self, SignedTransaction) -> RpcRichRawTransaction;
/// "Dispatch" a local transaction. /// "Dispatch" a local transaction.
fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error>; 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> { fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error> {
let hash = signed_transaction.transaction.hash(); let hash = signed_transaction.transaction.hash();
@@ -261,11 +269,11 @@ impl LightDispatcher {
transaction_queue: Arc<RwLock<LightTransactionQueue>>, transaction_queue: Arc<RwLock<LightTransactionQueue>>,
) -> Self { ) -> Self {
LightDispatcher { LightDispatcher {
sync: sync, sync,
client: client, client,
on_demand: on_demand, on_demand,
cache: cache, cache,
transaction_queue: transaction_queue, transaction_queue,
} }
} }
@@ -399,6 +407,11 @@ impl Dispatcher for LightDispatcher {
.and_then(move |nonce| with_nonce(filled, nonce))) .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> { fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error> {
let hash = signed_transaction.transaction.hash(); let hash = signed_transaction.transaction.hash();
@@ -510,8 +523,8 @@ pub fn execute<D: Dispatcher + 'static>(
}, },
ConfirmationPayload::SignTransaction(request) => { ConfirmationPayload::SignTransaction(request) => {
Box::new(dispatcher.sign(accounts, request, pass) Box::new(dispatcher.sign(accounts, request, pass)
.map(|result| result .map(move |result| result
.map(RpcRichRawTransaction::from) .map(move |tx| dispatcher.enrich(tx))
.map(ConfirmationResponse::SignTransaction) .map(ConfirmationResponse::SignTransaction)
)) ))
}, },

View File

@@ -23,7 +23,7 @@ use ethcore::encoded;
use ethcore::executed::{Executed, ExecutionError}; use ethcore::executed::{Executed, ExecutionError};
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use ethcore::filter::Filter as EthcoreFilter; 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 ethcore::receipt::Receipt;
use jsonrpc_core::{BoxFuture, Error}; use jsonrpc_core::{BoxFuture, Error};
@@ -65,13 +65,24 @@ pub struct LightFetch {
/// Extract a transaction at given index. /// Extract a transaction at given index.
pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_transition: u64) -> Option<Transaction> { pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_transition: u64) -> Option<Transaction> {
block.transactions().into_iter().nth(index) block.transactions().into_iter().nth(index)
// Verify if transaction signature is correct.
.and_then(|tx| SignedTransaction::new(tx).ok()) .and_then(|tx| SignedTransaction::new(tx).ok())
.map(|tx| Transaction::from_signed(tx, block.number(), eip86_transition)) .map(|signed_tx| {
.map(|mut tx| { let (signed, sender, _) = signed_tx.deconstruct();
tx.block_hash = Some(block.hash().into()); let block_hash = block.hash();
tx.transaction_index = Some(index.into()); let block_number = block.number();
tx 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))
} }

View File

@@ -73,8 +73,8 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
SignerClient { SignerClient {
signer: signer.clone(), signer: signer.clone(),
accounts: store.clone(), accounts: store.clone(),
dispatcher: dispatcher, dispatcher,
subscribers: subscribers, subscribers,
} }
} }
@@ -205,7 +205,8 @@ impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
}, },
ConfirmationPayload::SignTransaction(request) => { ConfirmationPayload::SignTransaction(request) => {
Self::verify_transaction(bytes, request, |pending_transaction| { 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) => { ConfirmationPayload::EthSignMessage(address, data) => {

View File

@@ -547,7 +547,7 @@ fn rpc_eth_pending_transaction_by_hash() {
tester.miner.pending_transactions.lock().insert(H256::zero(), tx); 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#"{ let request = r#"{
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "eth_getTransactionByHash", "method": "eth_getTransactionByHash",
@@ -863,7 +863,7 @@ fn rpc_eth_sign_transaction() {
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() + let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
r#""raw":"0x"# + &rlp.to_hex() + r#"","# + r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
r#""tx":{"# + 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))) + &format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
r#""condition":null,"creates":null,"# + r#""condition":null,"creates":null,"# +
&format!("\"from\":\"0x{:?}\",", &address) + &format!("\"from\":\"0x{:?}\",", &address) +

View File

@@ -234,7 +234,7 @@ fn rpc_parity_remove_transaction() {
let hash = signed.hash(); let hash = signed.hash();
let request = r#"{"jsonrpc": "2.0", "method": "parity_removeTransaction", "params":[""#.to_owned() + &format!("0x{:?}", hash) + r#""], "id": 1}"#; 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); miner.pending_transactions.lock().insert(hash, signed);
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned())); assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));

View File

@@ -456,7 +456,7 @@ fn should_confirm_sign_transaction_with_rlp() {
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() + let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
r#""raw":"0x"# + &rlp.to_hex() + r#"","# + r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
r#""tx":{"# + 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))) + &format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
r#""condition":null,"creates":null,"# + r#""condition":null,"creates":null,"# +
&format!("\"from\":\"0x{:?}\",", &address) + &format!("\"from\":\"0x{:?}\",", &address) +

View File

@@ -25,7 +25,7 @@ use v1::impls::SigningQueueClient;
use v1::metadata::Metadata; use v1::metadata::Metadata;
use v1::traits::{EthSigning, ParitySigning, Parity}; use v1::traits::{EthSigning, ParitySigning, Parity};
use v1::helpers::{SignerService, SigningQueue, FullDispatcher}; use v1::helpers::{SignerService, SigningQueue, FullDispatcher};
use v1::types::ConfirmationResponse; use v1::types::{ConfirmationResponse, RichRawTransaction};
use v1::tests::helpers::TestMinerService; use v1::tests::helpers::TestMinerService;
use v1::tests::mocked::parity; 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() + let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
r#""raw":"0x"# + &rlp.to_hex() + r#"","# + r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
r#""tx":{"# + 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))) + &format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
r#""condition":null,"creates":null,"# + r#""condition":null,"creates":null,"# +
&format!("\"from\":\"0x{:?}\",", &address) + &format!("\"from\":\"0x{:?}\",", &address) +
@@ -326,7 +326,9 @@ fn should_add_sign_transaction_to_the_queue() {
::std::thread::spawn(move || loop { ::std::thread::spawn(move || loop {
if signer.requests().len() == 1 { if signer.requests().len() == 1 {
// respond // 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 break
} }
::std::thread::sleep(Duration::from_millis(100)) ::std::thread::sleep(Duration::from_millis(100))

View File

@@ -173,8 +173,10 @@ impl<'a> From<&'a EthHeader> for Header {
logs_bloom: h.log_bloom().into(), logs_bloom: h.log_bloom().into(),
timestamp: h.timestamp().into(), timestamp: h.timestamp().into(),
difficulty: h.difficulty().into(), difficulty: h.difficulty().into(),
seal_fields: h.seal().into_iter().map(Into::into).collect(),
extra_data: h.extra_data().into(), 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(),
} }
} }
} }

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use 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}; use ethcore::receipt::{Receipt as EthReceipt, RichReceipt, LocalizedReceipt, TransactionOutcome};
/// Receipt /// Receipt
@@ -51,7 +51,7 @@ pub struct Receipt {
pub logs_bloom: H2048, pub logs_bloom: H2048,
/// Status code /// Status code
#[serde(rename="status")] #[serde(rename="status")]
pub status_code: Option<u8>, pub status_code: Option<U64>,
} }
impl Receipt { 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 { match *outcome {
TransactionOutcome::Unknown | TransactionOutcome::StateRoot(_) => None, 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] #[test]
fn receipt_serialization() { 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 { let receipt = Receipt {
transaction_hash: Some(0.into()), transaction_hash: Some(0.into()),
@@ -158,7 +158,7 @@ mod tests {
}], }],
logs_bloom: 15.into(), logs_bloom: 15.into(),
state_root: Some(10.into()), state_root: Some(10.into()),
status_code: None, status_code: Some(1u64.into()),
}; };
let serialized = serde_json::to_string(&receipt).unwrap(); let serialized = serde_json::to_string(&receipt).unwrap();

View File

@@ -158,11 +158,10 @@ pub struct RichRawTransaction {
pub transaction: Transaction pub transaction: Transaction
} }
impl RichRawTransaction {
impl From<SignedTransaction> for RichRawTransaction { /// Creates new `RichRawTransaction` from `SignedTransaction`.
fn from(t: SignedTransaction) -> Self { pub fn from_signed(tx: SignedTransaction, block_number: u64, eip86_transition: u64) -> Self {
// TODO: change transition to 0 when EIP-86 is commonly used. let tx = Transaction::from_signed(tx, block_number, eip86_transition);
let tx: Transaction = Transaction::from_signed(t, 0, u64::max_value());
RichRawTransaction { RichRawTransaction {
raw: tx.raw.clone(), raw: tx.raw.clone(),
transaction: tx, transaction: tx,
@@ -213,7 +212,7 @@ impl Transaction {
hash: t.hash().into(), hash: t.hash().into(),
nonce: t.nonce.into(), nonce: t.nonce.into(),
block_hash: None, block_hash: None,
block_number: Some(block_number.into()), block_number: None,
transaction_index: None, transaction_index: None,
from: t.sender().into(), from: t.sender().into(),
to: match t.action { to: match t.action {

View File

@@ -137,7 +137,7 @@ const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024;
// Maximal number of transactions in sent in single packet. // Maximal number of transactions in sent in single packet.
const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64;
// Min number of blocks to be behind for a snapshot sync // 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 SNAPSHOT_MIN_PEERS: usize = 3;
const STATUS_PACKET: u8 = 0x00; const STATUS_PACKET: u8 = 0x00;

View File

@@ -24,6 +24,10 @@ esac
set -e set -e
# Validate chainspecs
./scripts/validate_chainspecs.sh ./scripts/validate_chainspecs.sh
cargo test -j 8 $OPTIONS --features "$FEATURES" --all --exclude evmjit $1 cargo test -j 8 $OPTIONS --features "$FEATURES" --all --exclude evmjit $1
# Validate --no-default-features build
cargo check --no-default-features

View File

@@ -3,7 +3,7 @@ description = "Ethcore utility library"
homepage = "http://parity.io" homepage = "http://parity.io"
license = "GPL-3.0" license = "GPL-3.0"
name = "ethcore-util" name = "ethcore-util"
version = "1.8.0" version = "1.8.4"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs" build = "build.rs"

View File

@@ -24,7 +24,7 @@ include!(concat!(env!("OUT_DIR"), "/version.rs"));
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
#[cfg(feature = "final")] #[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. // ^^^ should be reset to "stable" or "beta" according to the release branch.
#[cfg(not(feature = "final"))] #[cfg(not(feature = "final"))]

View File

@@ -315,8 +315,9 @@ void OpenUI()
STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
LPWSTR args = new WCHAR[lstrlen(commandLineFiltered) + MAX_PATH + 2]; 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, commandLineFiltered);
lstrcat(args, L" ui");
CreateProcess(path, args, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo); CreateProcess(path, args, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo);
} }